示例#1
0
        internal PipelineStack(
            Construct scope,
            string id,
            string ecrRepositoryName,
            string framework,
            string channel,
            string dockerBuildImage,
            Configuration configuration,
            IStackProps props = null) : base(scope, $"{id}-{framework}", props)
        {
            var repository = Repository.FromRepositoryArn(this, "Repository", configuration.Source.RepositoryArn);

            var sourceArtifact = new Artifact_();
            var outputArtifact = new Artifact_();
            var ecrPolicy      = new PolicyStatement(new PolicyStatementProps
            {
                Effect    = Effect.ALLOW,
                Actions   = new[] { "ecr:*" },
                Resources = new[] { "*" }
            });


            // Setup CodeCommit cross account role access policies if required
            IRole codeCommitRole = null;

            if (!string.IsNullOrWhiteSpace(configuration.Source.CrossAccountRoleArn))
            {
                codeCommitRole = Role.FromRoleArn(this, "CodeCommitRole", configuration.Source.CrossAccountRoleArn, new FromRoleArnOptions
                {
                    Mutable = false // Flag to indicate CDK to not modify the role
                });
            }

            // Strict ordering is required to make sure CloudFormation template doesn't result in false difference
            var environmentVariablesToCopy = System.Environment.GetEnvironmentVariables()
                                             .Keys.Cast <string>()
                                             .Where(variable => variable.StartsWith("AWS_LAMBDA_"))
                                             .OrderBy(variable => variable);

            // Self mutation
            // TODO: DOTNET-6085 - Migration from CDKPipeline to CodePipeline
            const string cdkCliVersion = "1.159.0";
            var          pipeline      = new CdkPipeline(this, "Pipeline", new CdkPipelineProps
            {
                PipelineName          = $"{id}-{framework}",
                CloudAssemblyArtifact = outputArtifact,
                CdkCliVersion         = cdkCliVersion,

                SourceAction = new CodeCommitSourceAction(new CodeCommitSourceActionProps
                {
                    ActionName = "CodeCommit",
                    Output     = sourceArtifact,
                    Repository = repository,
                    Branch     = configuration.Source.BranchName,
                    Role       = codeCommitRole,
                    Trigger    = CodeCommitTrigger.POLL
                }),

                // It synthesizes CDK code to cdk.out directory which is picked by SelfMutate stage to mutate the pipeline
                SynthAction = new SimpleSynthAction(new SimpleSynthActionProps
                {
                    SourceArtifact        = sourceArtifact,
                    CloudAssemblyArtifact = outputArtifact,
                    Subdirectory          = "LambdaRuntimeDockerfiles/Infrastructure",
                    InstallCommands       = new[]
                    {
                        $"npm install -g aws-cdk@{cdkCliVersion}",
                    },
                    BuildCommands            = new[] { "dotnet build" },
                    SynthCommand             = "cdk synth",
                    CopyEnvironmentVariables = environmentVariablesToCopy.ToArray()
                })
            });

            var stageEcr = GetStageEcr(this, ecrRepositoryName, configuration);

            var dockerBuildStage = pipeline.AddStage("Stage-DockerBuild");

            // Stage
            // Build AMD64 image
            var dockerBuildAmd64 = new Project(this, "DockerBuild-amd64", new ProjectProps
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerBuild/buildspec.yml"),
                Description = $"Builds and pushes image to {stageEcr}",
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "AWS_LAMBDA_STAGE_ECR", new BuildEnvironmentVariable {
                          Value = stageEcr
                      } },
                    { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = ecrRepositoryName
                      } },
                    { "AWS_LAMBDA_ARCHITECTURE", new BuildEnvironmentVariable {
                          Value = "amd64"
                      } },
                    { "AWS_LAMBDA_POWERSHELL_VERSION", new BuildEnvironmentVariable {
                          Value = PowershellAmd64
                      } },
                    { "AWS_LAMBDA_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = configuration.BaseImageAMD64Tags[framework]
                      } },
                    { "AWS_LAMBDA_DOTNET_FRAMEWORK_VERSION", new BuildEnvironmentVariable {
                          Value = framework
                      } },
                    { "AWS_LAMBDA_DOTNET_FRAMEWORK_CHANNEL", new BuildEnvironmentVariable {
                          Value = channel
                      } }
                }
            });

            dockerBuildAmd64.AddToRolePolicy(ecrPolicy);
            dockerBuildStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
            {
                Input      = sourceArtifact,
                Project    = dockerBuildAmd64,
                ActionName = "amd64"
            }));

            if (configuration.DockerARM64Images.Contains(framework))
            {
                // Build ARM64 image
                var dockerBuildArm64 = new Project(this, "DockerBuild-arm64", new ProjectProps
                {
                    BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerBuild/buildspec.yml"),
                    Description = $"Builds and pushes image to {stageEcr}",
                    Environment = new BuildEnvironment
                    {
                        BuildImage = LinuxBuildImage.AMAZON_LINUX_2_ARM,
                        Privileged = true
                    },
                    Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                    {
                        Repository  = repository,
                        BranchOrRef = configuration.Source.BranchName
                    }),
                    EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                    {
                        { "AWS_LAMBDA_STAGE_ECR", new BuildEnvironmentVariable {
                              Value = stageEcr
                          } },
                        { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                              Value = ecrRepositoryName
                          } },
                        { "AWS_LAMBDA_ARCHITECTURE", new BuildEnvironmentVariable {
                              Value = "arm64"
                          } },
                        { "AWS_LAMBDA_POWERSHELL_VERSION", new BuildEnvironmentVariable {
                              Value = PowershellArm64
                          } },
                        { "AWS_LAMBDA_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = configuration.BaseImageARM64Tags[framework]
                          } },
                        { "AWS_LAMBDA_DOTNET_FRAMEWORK_VERSION", new BuildEnvironmentVariable {
                              Value = framework
                          } },
                        { "AWS_LAMBDA_DOTNET_FRAMEWORK_CHANNEL", new BuildEnvironmentVariable {
                              Value = channel
                          } }
                    }
                });

                dockerBuildArm64.AddToRolePolicy(ecrPolicy);
                dockerBuildStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
                {
                    Input      = sourceArtifact,
                    Project    = dockerBuildArm64,
                    ActionName = "arm64"
                }));
            }

            // Create multi arch image manifest
            var dockerImageManifest = new Project(this, "DockerImageManifest", new ProjectProps
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerImageManifest/buildspec.yml"),
                Description = $"Creates image manifest and pushes to {stageEcr}",
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "AWS_LAMBDA_STAGE_ECR", new BuildEnvironmentVariable {
                          Value = stageEcr
                      } },
                    { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = ecrRepositoryName
                      } },
                    { "AWS_LAMBDA_MULTI_ARCH_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = BaseImageMultiArch
                      } },
                    { "AWS_LAMBDA_AMD64_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = configuration.BaseImageAMD64Tags[framework]
                      } },
                    { "AWS_LAMBDA_ARM64_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = configuration.BaseImageARM64Tags[framework]
                      } },
                    { "AWS_LAMBDA_INCLUDE_ARM64", new BuildEnvironmentVariable {
                          Value = configuration.DockerARM64Images.Contains(framework).ToString()
                      } },
                }
            });

            dockerImageManifest.AddToRolePolicy(ecrPolicy);

            var dockerImageManifestStage = pipeline.AddStage("DockerImageManifest");

            dockerImageManifestStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
            {
                Input      = sourceArtifact,
                Project    = dockerImageManifest,
                ActionName = "DockerImageManifest"
            }));

            // Smoke test AMD64 image
            var amd64SmokeTests = new Project(this, "SmokeTests-amd64", new ProjectProps
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/SmokeTests/buildspec.yml"),
                Description = "Runs smoke tests on the built image.",
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                          Value = stageEcr
                      } },
                    { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = ecrRepositoryName
                      } },
                    { "AWS_LAMBDA_SOURCE_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = BaseImageMultiArch
                      } },
                    { "AWS_LAMBDA_POWERSHELL_VERSION", new BuildEnvironmentVariable {
                          Value = PowershellAmd64
                      } },
                    { "AWS_LAMBDA_DOTNET_FRAMEWORK_VERSION", new BuildEnvironmentVariable {
                          Value = framework
                      } },
                    { "AWS_LAMBDA_DOTNET_FRAMEWORK_CHANNEL", new BuildEnvironmentVariable {
                          Value = channel
                      } },
                    { "AWS_LAMBDA_DOTNET_BUILD_IMAGE", new BuildEnvironmentVariable {
                          Value = dockerBuildImage
                      } },
                }
            });

            var smokeTestsPolicy = new PolicyStatement(new PolicyStatementProps
            {
                Effect  = Effect.ALLOW,
                Actions = new[]
                {
                    "sts:*",
                    "iam:*",
                    "ecr:*",
                    "lambda:*"
                },
                Resources = new[] { "*" }
            });

            amd64SmokeTests.AddToRolePolicy(smokeTestsPolicy);

            var smokeTestsStage = pipeline.AddStage("SmokeTests");

            smokeTestsStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
            {
                Input      = sourceArtifact,
                Project    = amd64SmokeTests,
                ActionName = "amd64"
            }));

            if (configuration.DockerARM64Images.Contains(framework))
            {
                // Smoke test ARM64 image
                var arm64SmokeTests = new Project(this, "SmokeTests-arm64", new ProjectProps
                {
                    BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/SmokeTests/buildspec.yml"),
                    Description = "Runs smoke tests on the built image.",
                    Environment = new BuildEnvironment
                    {
                        BuildImage = LinuxBuildImage.AMAZON_LINUX_2_ARM,
                        Privileged = true
                    },
                    Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                    {
                        Repository  = repository,
                        BranchOrRef = configuration.Source.BranchName
                    }),
                    EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                    {
                        { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                              Value = stageEcr
                          } },
                        { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                              Value = ecrRepositoryName
                          } },
                        { "AWS_LAMBDA_SOURCE_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = BaseImageMultiArch
                          } },
                        { "AWS_LAMBDA_POWERSHELL_VERSION", new BuildEnvironmentVariable {
                              Value = PowershellArm64
                          } },
                        { "AWS_LAMBDA_DOTNET_FRAMEWORK_VERSION", new BuildEnvironmentVariable {
                              Value = framework
                          } },
                        { "AWS_LAMBDA_DOTNET_FRAMEWORK_CHANNEL", new BuildEnvironmentVariable {
                              Value = channel
                          } },
                        { "AWS_LAMBDA_DOTNET_BUILD_IMAGE", new BuildEnvironmentVariable {
                              Value = dockerBuildImage
                          } },
                    }
                });

                arm64SmokeTests.AddToRolePolicy(smokeTestsPolicy);

                smokeTestsStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
                {
                    Input      = sourceArtifact,
                    Project    = arm64SmokeTests,
                    ActionName = "arm64"
                }));
            }

            // Beta
            if (!string.IsNullOrWhiteSpace(configuration.Ecrs.Beta))
            {
                var betaDockerPush = new Project(this, "Beta-DockerPush", new ProjectProps
                {
                    BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerPush/buildspec.yml"),
                    Description = $"Pushes staged image to {configuration.Ecrs.Beta}",
                    Environment = new BuildEnvironment
                    {
                        BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                        Privileged = true
                    },
                    Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                    {
                        Repository  = repository,
                        BranchOrRef = configuration.Source.BranchName
                    }),
                    EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                    {
                        { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                              Value = stageEcr
                          } },
                        { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                              Value = ecrRepositoryName
                          } },
                        { "AWS_LAMBDA_DESTINATION_ECRS", new BuildEnvironmentVariable {
                              Value = configuration.Ecrs.Beta
                          } },
                        { "AWS_LAMBDA_MULTI_ARCH_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = BaseImageMultiArch
                          } },
                        { "AWS_LAMBDA_AMD64_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = configuration.BaseImageAMD64Tags[framework]
                          } },
                        { "AWS_LAMBDA_ARM64_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = configuration.BaseImageARM64Tags[framework]
                          } },
                        { "AWS_LAMBDA_INCLUDE_ARM64", new BuildEnvironmentVariable {
                              Value = configuration.DockerARM64Images.Contains(framework).ToString()
                          } },
                    }
                });

                betaDockerPush.AddToRolePolicy(ecrPolicy);

                var betaDockerPushStage = pipeline.AddStage("Beta-DockerPush");
                betaDockerPushStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
                {
                    Input      = sourceArtifact,
                    Project    = betaDockerPush,
                    ActionName = "DockerPush"
                }));
            }


            // Prod
            if (!string.IsNullOrWhiteSpace(configuration.Ecrs.Prod))
            {
                // Manual Approval
                var manualApprovalStage = pipeline.AddStage("Prod-ManualApproval");
                manualApprovalStage.AddActions(new ManualApprovalAction(new ManualApprovalActionProps
                {
                    ActionName = "ManualApproval"
                }));


                var prodDockerPush = new Project(this, "Prod-DockerPush", new ProjectProps
                {
                    BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerPush/buildspec.yml"),
                    Description = $"Pushes staged image to {configuration.Ecrs.Prod}",
                    Environment = new BuildEnvironment
                    {
                        BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                        Privileged = true
                    },
                    Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                    {
                        Repository  = repository,
                        BranchOrRef = configuration.Source.BranchName
                    }),
                    EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                    {
                        { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                              Value = stageEcr
                          } },
                        { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                              Value = ecrRepositoryName
                          } },
                        { "AWS_LAMBDA_DESTINATION_ECRS", new BuildEnvironmentVariable {
                              Value = configuration.Ecrs.Prod
                          } },
                        { "AWS_LAMBDA_MULTI_ARCH_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = BaseImageMultiArch
                          } },
                        { "AWS_LAMBDA_AMD64_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = configuration.BaseImageAMD64Tags[framework]
                          } },
                        { "AWS_LAMBDA_ARM64_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = configuration.BaseImageARM64Tags[framework]
                          } },
                        { "AWS_LAMBDA_INCLUDE_ARM64", new BuildEnvironmentVariable {
                              Value = configuration.DockerARM64Images.Contains(framework).ToString()
                          } },
                    }
                });

                prodDockerPush.AddToRolePolicy(ecrPolicy);

                var prodDockerPushStage = pipeline.AddStage("Prod-DockerPush");
                prodDockerPushStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
                {
                    Input      = sourceArtifact,
                    Project    = prodDockerPush,
                    ActionName = "DockerPush"
                }));
            }
        }
        internal PipelineStack(Construct scope, string id, Configuration configuration, IStackProps props = null) : base(scope, id, props)
        {
            var repository = Repository.FromRepositoryArn(this, "Repository", configuration.Source.RepositoryArn);

            var sourceArtifact = new Artifact_();
            var outputArtifact = new Artifact_();
            var ecrPolicy      = new PolicyStatement(new PolicyStatementProps
            {
                Effect    = Effect.ALLOW,
                Actions   = new[] { "ecr:*" },
                Resources = new[] { "*" }
            });


            // Setup CodeCommit cross account role access policies if required
            IRole codeCommitRole = null;

            if (!string.IsNullOrWhiteSpace(configuration.Source.CrossAccountRoleArn))
            {
                codeCommitRole = Role.FromRoleArn(this, "CodeCommitRole", configuration.Source.CrossAccountRoleArn, new FromRoleArnOptions()
                {
                    Mutable = false // Flag to indicate CDK to not modify the role
                });
            }


            // Self mutation
            var pipeline = new CdkPipeline(this, "Pipeline", new CdkPipelineProps
            {
                PipelineName          = Configuration.ProjectName,
                CloudAssemblyArtifact = outputArtifact,

                SourceAction = new CodeCommitSourceAction(new CodeCommitSourceActionProps
                {
                    ActionName = "CodeCommit",
                    Output     = sourceArtifact,
                    Repository = repository,
                    Branch     = configuration.Source.BranchName,
                    Role       = codeCommitRole,
                    Trigger    = CodeCommitTrigger.POLL
                }),

                // It synthesizes CDK code to cdk.out directory which is picked by SelfMutate stage to mutate the pipeline
                SynthAction = new SimpleSynthAction(new SimpleSynthActionProps
                {
                    SourceArtifact        = sourceArtifact,
                    CloudAssemblyArtifact = outputArtifact,
                    Subdirectory          = "LambdaRuntimeDockerfiles/dotnet5/Infrastructure",
                    InstallCommands       = new[]
                    {
                        "npm install -g aws-cdk",
                    },
                    BuildCommands            = new[] { "dotnet build" },
                    SynthCommand             = "cdk synth",
                    CopyEnvironmentVariables = new[]
                    {
                        "SOURCE_REPOSITORY_ARN",
                        "SOURCE_BRANCH_NAME",
                        "SOURCE_CROSS_ACCOUNT_ROLE_ARN",
                        "BASE_ECRS",
                        "STAGE_ECR",
                        "BETA_ECRS",
                        "PROD_ECRS",
                        "ECR_REPOSITORY_NAME",
                    }
                })
            });


            // Stage
            var dockerBuild = new Project(this, "DockerBuild", new ProjectProps()
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerBuild/buildspec.yml"),
                Description = $"Builds and pushes image to {configuration.Ecrs.Stage}",
                Environment = new BuildEnvironment()
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps()
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "BASE_ECRS", new BuildEnvironmentVariable()
                      {
                          Value = configuration.Ecrs.Base
                      } },
                    { "STAGE_ECR", new BuildEnvironmentVariable {
                          Value = configuration.Ecrs.Stage
                      } },
                    { "ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = configuration.EcrRepositoryName
                      } }
                }
            });

            dockerBuild.AddToRolePolicy(ecrPolicy);

            var dockerBuildStage = pipeline.AddStage("Stage-DockerBuild");

            dockerBuildStage.AddActions(new CodeBuildAction(new CodeBuildActionProps()
            {
                Input      = sourceArtifact,
                Project    = dockerBuild,
                ActionName = "DockerBuild"
            }));


            // Beta
            var betaDockerPush = new Project(this, "Beta-DockerPush", new ProjectProps()
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerPush/buildspec.yml"),
                Description = $"Pushes staged image to {configuration.Ecrs.Beta}",
                Environment = new BuildEnvironment()
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps()
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "SOURCE_ECR", new BuildEnvironmentVariable {
                          Value = configuration.Ecrs.Stage
                      } },
                    { "ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = configuration.EcrRepositoryName
                      } },
                    { "DESTINATION_ECRS", new BuildEnvironmentVariable {
                          Value = configuration.Ecrs.Beta
                      } },
                    { "DESTINATION_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = "beta"
                      } },
                }
            });

            betaDockerPush.AddToRolePolicy(ecrPolicy);

            var betaDockerPushStage = pipeline.AddStage("Beta-DockerPush");

            betaDockerPushStage.AddActions(new CodeBuildAction(new CodeBuildActionProps()
            {
                Input      = sourceArtifact,
                Project    = betaDockerPush,
                ActionName = "DockerPush"
            }));


            // Manual Approval
            var manualApprovalStage = pipeline.AddStage("Prod-ManualApproval");

            manualApprovalStage.AddActions(new ManualApprovalAction(new ManualApprovalActionProps()
            {
                ActionName = "ManualApproval"
            }));


            // Prod
            var prodDockerPush = new Project(this, "Prod-DockerPush", new ProjectProps()
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerPush/buildspec.yml"),
                Description = $"Pushes staged image to {configuration.Ecrs.Prod}",
                Environment = new BuildEnvironment()
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps()
                {
                    Repository  = repository,
                    BranchOrRef = "dotnet5/cdk"
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "SOURCE_ECR", new BuildEnvironmentVariable {
                          Value = configuration.Ecrs.Stage
                      } },
                    { "ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = configuration.EcrRepositoryName
                      } },
                    { "DESTINATION_ECRS", new BuildEnvironmentVariable {
                          Value = configuration.Ecrs.Prod
                      } },
                    { "DESTINATION_IMAGE_TAG", new BuildEnvironmentVariable {
                          Value = "beta"
                      } },                                                                    // Prod images are also tagged as beta
                }
            });

            prodDockerPush.AddToRolePolicy(ecrPolicy);

            var prodDockerPushStage = pipeline.AddStage("Prod-DockerPush");

            prodDockerPushStage.AddActions(new CodeBuildAction(new CodeBuildActionProps()
            {
                Input      = sourceArtifact,
                Project    = prodDockerPush,
                ActionName = "DockerPush"
            }));
        }
示例#3
0
        internal PipelineStack(Construct scope, string id, Configuration configuration, IStackProps props = null) : base(scope, id, props)
        {
            var repository = Repository.FromRepositoryArn(this, "Repository", configuration.Source.RepositoryArn);

            var sourceArtifact = new Artifact_();
            var outputArtifact = new Artifact_();
            var ecrPolicy      = new PolicyStatement(new PolicyStatementProps
            {
                Effect    = Effect.ALLOW,
                Actions   = new[] { "ecr:*" },
                Resources = new[] { "*" }
            });


            // Setup CodeCommit cross account role access policies if required
            IRole codeCommitRole = null;

            if (!string.IsNullOrWhiteSpace(configuration.Source.CrossAccountRoleArn))
            {
                codeCommitRole = Role.FromRoleArn(this, "CodeCommitRole", configuration.Source.CrossAccountRoleArn, new FromRoleArnOptions
                {
                    Mutable = false // Flag to indicate CDK to not modify the role
                });
            }

            // Strict ordering is required to make sure CloudFormation template doesn't result in false difference
            var environmentVariablesToCopy = System.Environment.GetEnvironmentVariables()
                                             .Keys.Cast <string>()
                                             .Where(variable => variable.StartsWith("AWS_LAMBDA_"))
                                             .OrderBy(variable => variable);

            // Self mutation
            var pipeline = new CdkPipeline(this, "Pipeline", new CdkPipelineProps
            {
                PipelineName          = Configuration.ProjectName,
                CloudAssemblyArtifact = outputArtifact,

                SourceAction = new CodeCommitSourceAction(new CodeCommitSourceActionProps
                {
                    ActionName = "CodeCommit",
                    Output     = sourceArtifact,
                    Repository = repository,
                    Branch     = configuration.Source.BranchName,
                    Role       = codeCommitRole,
                    Trigger    = CodeCommitTrigger.POLL
                }),

                // It synthesizes CDK code to cdk.out directory which is picked by SelfMutate stage to mutate the pipeline
                SynthAction = new SimpleSynthAction(new SimpleSynthActionProps
                {
                    SourceArtifact        = sourceArtifact,
                    CloudAssemblyArtifact = outputArtifact,
                    Subdirectory          = "LambdaRuntimeDockerfiles/dotnet5/Infrastructure",
                    InstallCommands       = new[]
                    {
                        "npm install -g aws-cdk",
                    },
                    BuildCommands            = new[] { "dotnet build" },
                    SynthCommand             = "cdk synth",
                    CopyEnvironmentVariables = environmentVariablesToCopy.ToArray()
                })
            });

            var stageEcr = GetStageEcr(this, configuration);

            // Stage
            var dockerBuild = new Project(this, "DockerBuild", new ProjectProps
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerBuild/buildspec.yml"),
                Description = $"Builds and pushes image to {stageEcr}",
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "AWS_LAMBDA_STAGE_ECR", new BuildEnvironmentVariable {
                          Value = stageEcr
                      } },
                    { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = configuration.EcrRepositoryName
                      } }
                }
            });

            dockerBuild.AddToRolePolicy(ecrPolicy);

            var dockerBuildStage = pipeline.AddStage("Stage-DockerBuild");

            dockerBuildStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
            {
                Input      = sourceArtifact,
                Project    = dockerBuild,
                ActionName = "DockerBuild"
            }));


            var smokeTests = new Project(this, "SmokeTests", new ProjectProps
            {
                BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/SmokeTests/buildspec.yml"),
                Description = "Runs smoke tests on the built image.",
                Environment = new BuildEnvironment
                {
                    BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                    Privileged = true
                },
                Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                {
                    Repository  = repository,
                    BranchOrRef = configuration.Source.BranchName
                }),
                EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                {
                    { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                          Value = stageEcr
                      } },
                    { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                          Value = configuration.EcrRepositoryName
                      } },
                }
            });

            var smokeTestsPolicy = new PolicyStatement(new PolicyStatementProps
            {
                Effect  = Effect.ALLOW,
                Actions = new[]
                {
                    "sts:*",
                    "iam:*",
                    "ecr:*",
                    "lambda:*"
                },
                Resources = new[] { "*" }
            });

            smokeTests.AddToRolePolicy(smokeTestsPolicy);

            var smokeTestsStage = pipeline.AddStage("SmokeTests");

            smokeTestsStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
            {
                Input      = sourceArtifact,
                Project    = smokeTests,
                ActionName = "SmokeTests"
            }));


            // Beta
            if (!string.IsNullOrWhiteSpace(configuration.Ecrs.Beta))
            {
                var betaDockerPush = new Project(this, "Beta-DockerPush", new ProjectProps
                {
                    BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerPush/buildspec.yml"),
                    Description = $"Pushes staged image to {configuration.Ecrs.Beta}",
                    Environment = new BuildEnvironment
                    {
                        BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                        Privileged = true
                    },
                    Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                    {
                        Repository  = repository,
                        BranchOrRef = configuration.Source.BranchName
                    }),
                    EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                    {
                        { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                              Value = stageEcr
                          } },
                        { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                              Value = configuration.EcrRepositoryName
                          } },
                        { "AWS_LAMBDA_DESTINATION_ECRS", new BuildEnvironmentVariable {
                              Value = configuration.Ecrs.Beta
                          } },
                        { "AWS_LAMBDA_DESTINATION_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = "beta"
                          } },
                    }
                });

                betaDockerPush.AddToRolePolicy(ecrPolicy);

                var betaDockerPushStage = pipeline.AddStage("Beta-DockerPush");
                betaDockerPushStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
                {
                    Input      = sourceArtifact,
                    Project    = betaDockerPush,
                    ActionName = "DockerPush"
                }));
            }


            // Prod
            if (!string.IsNullOrWhiteSpace(configuration.Ecrs.Prod))
            {
                // Manual Approval
                var manualApprovalStage = pipeline.AddStage("Prod-ManualApproval");
                manualApprovalStage.AddActions(new ManualApprovalAction(new ManualApprovalActionProps
                {
                    ActionName = "ManualApproval"
                }));


                var prodDockerPush = new Project(this, "Prod-DockerPush", new ProjectProps
                {
                    BuildSpec   = BuildSpec.FromSourceFilename($"{Configuration.ProjectRoot}/DockerPush/buildspec.yml"),
                    Description = $"Pushes staged image to {configuration.Ecrs.Prod}",
                    Environment = new BuildEnvironment
                    {
                        BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3,
                        Privileged = true
                    },
                    Source = Amazon.CDK.AWS.CodeBuild.Source.CodeCommit(new CodeCommitSourceProps
                    {
                        Repository  = repository,
                        BranchOrRef = "dotnet5/cdk"
                    }),
                    EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable>
                    {
                        { "AWS_LAMBDA_SOURCE_ECR", new BuildEnvironmentVariable {
                              Value = stageEcr
                          } },
                        { "AWS_LAMBDA_ECR_REPOSITORY_NAME", new BuildEnvironmentVariable {
                              Value = configuration.EcrRepositoryName
                          } },
                        { "AWS_LAMBDA_DESTINATION_ECRS", new BuildEnvironmentVariable {
                              Value = configuration.Ecrs.Prod
                          } },
                        { "AWS_LAMBDA_DESTINATION_IMAGE_TAG", new BuildEnvironmentVariable {
                              Value = "beta"
                          } },                                                                               // Prod images are also tagged as beta
                    }
                });

                prodDockerPush.AddToRolePolicy(ecrPolicy);

                var prodDockerPushStage = pipeline.AddStage("Prod-DockerPush");
                prodDockerPushStage.AddActions(new CodeBuildAction(new CodeBuildActionProps
                {
                    Input      = sourceArtifact,
                    Project    = prodDockerPush,
                    ActionName = "DockerPush"
                }));
            }
        }