github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/ops/aws/canary/lib/pipeline-stack.ts (about)

     1  import * as cdk from 'aws-cdk-lib';
     2  import * as codebuild from 'aws-cdk-lib/aws-codebuild';
     3  import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
     4  import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions';
     5  import * as lambda from 'aws-cdk-lib/aws-lambda';
     6  import {CanaryConfig, getCanaryConfig, PipelineConfig} from "./config";
     7  
     8  export interface PipelineStackProps extends cdk.StackProps {
     9      readonly lambdaCode: lambda.CfnParametersCode;
    10  }
    11  
    12  
    13  export class PipelineStack extends cdk.Stack {
    14      constructor(app: cdk.App, id: string, props: PipelineStackProps, config: PipelineConfig) {
    15          super(app, id, props)
    16  
    17          // Source artifacts
    18          const sourceOutput = new codepipeline.Artifact("SourceOutput")
    19  
    20          // Configs
    21          const prodConfig = getCanaryConfig(app, 'prod');
    22          const stagingConfig = getCanaryConfig(app, 'staging');
    23          const allConfigs = [prodConfig, stagingConfig]
    24  
    25          // Build artifacts
    26          const cloudformationBuild = this.getCloudformationBuild(allConfigs);
    27          const canaryBuild = this.getCanaryBuild();
    28  
    29          const cdkBuildOutput = new codepipeline.Artifact('CFBuildOutput');
    30          const canaryBuildOutput = new codepipeline.Artifact('CanaryBuildOutput');
    31  
    32          new codepipeline.Pipeline(this, 'Pipeline' + config.suffix, {
    33              stages: [
    34                  {
    35                      stageName: 'Source',
    36                      actions: [
    37                          new codepipeline_actions.CodeStarConnectionsSourceAction({
    38                              actionName: "BacalhauCommit",
    39                              output: sourceOutput,
    40                              owner: config.bacalhauSourceConnection.owner,
    41                              repo: config.bacalhauSourceConnection.repo,
    42                              branch: config.bacalhauSourceConnection.branch,
    43                              connectionArn: config.bacalhauSourceConnection.connectionArn,
    44                          })
    45                      ],
    46                  },
    47                  {
    48                      stageName: 'Build',
    49                      actions: [
    50                          new codepipeline_actions.CodeBuildAction({
    51                              actionName: 'BuildCF',
    52                              project: cloudformationBuild,
    53                              input: sourceOutput,
    54                              outputs: [cdkBuildOutput],
    55                          }),
    56                          new codepipeline_actions.CodeBuildAction({
    57                              actionName: 'BuildCanary',
    58                              project: canaryBuild,
    59                              input: sourceOutput,
    60                              outputs: [canaryBuildOutput],
    61                          })
    62                      ],
    63                  },
    64                  {
    65                      stageName: 'PreStagingVerification',
    66                      actions: [
    67                          new codepipeline_actions.CodeBuildAction({
    68                              actionName: 'IntegrationTest',
    69                              project: this.getIntegrationTest(stagingConfig),
    70                              input: sourceOutput,
    71                          }),
    72                      ],
    73                  },
    74  
    75                  {
    76                      stageName: 'DeployStaging',
    77                      actions: [
    78                          new codepipeline_actions.CloudFormationCreateUpdateStackAction({
    79                              actionName: 'DeployCanary',
    80                              templatePath: cdkBuildOutput.atPath('BacalhauCanaryStaging.template.json'),
    81                              stackName: 'BacalhauCanaryStaging',
    82                              adminPermissions: true,
    83                              parameterOverrides: {
    84                                  ...props.lambdaCode.assign(canaryBuildOutput.s3Location),
    85                              },
    86                              extraInputs: [canaryBuildOutput],
    87                          }),
    88                      ],
    89                  },
    90                  {
    91                      stageName: 'PreProdVerification',
    92                      actions: [
    93                          new codepipeline_actions.CodeBuildAction({
    94                              actionName: 'IntegrationTest',
    95                              project: this.getIntegrationTest(prodConfig),
    96                              input: sourceOutput,
    97                          }),
    98                          new codepipeline_actions.ManualApprovalAction({
    99                              actionName: 'ManualApproval',
   100                              additionalInformation: 'Approve the Canary deployment to production',
   101                          }),
   102                      ],
   103                  },
   104                  {
   105                      stageName: 'DeployProd',
   106                      actions: [
   107                          new codepipeline_actions.CloudFormationCreateUpdateStackAction({
   108                              actionName: 'DeployCanary',
   109                              templatePath: cdkBuildOutput.atPath('BacalhauCanaryProd.template.json'),
   110                              stackName: 'BacalhauCanaryProd',
   111                              adminPermissions: true,
   112                              parameterOverrides: {
   113                                  ...props.lambdaCode.assign(canaryBuildOutput.s3Location),
   114                              },
   115                              extraInputs: [canaryBuildOutput],
   116                          }),
   117                      ],
   118                  }
   119              ],
   120          });
   121      }
   122  
   123  
   124      private getCanaryBuild() {
   125          return new codebuild.PipelineProject(this, 'CanaryBuild', {
   126              buildSpec: codebuild.BuildSpec.fromObject({
   127                  version: '0.2',
   128                  phases: {
   129                      install: {
   130                          commands: [
   131                              'rm -rf `goenv root`',
   132                              'curl --silent --show-error --location --fail https://go.dev/dl/go1.19.6.linux-amd64.tar.gz | tar --extract --gzip --file=- --directory=/usr/local',
   133                              'ln -s /usr/local/go/bin/go /usr/local/bin/go',
   134                          ],
   135                      },
   136                      build: {
   137                          commands: [
   138                              'cd ops/aws/canary/lambda',
   139                              'go build -ldflags="-s -w" -o scenario_handler ./cmd/scenario_lambda_runner/',
   140                              'go build -ldflags="-s -w" -o alarm_handler ./cmd/alarm_slack_handler/',
   141                          ],
   142                      },
   143                  },
   144                  artifacts: {
   145                      'base-directory': 'ops/aws/canary/lambda',
   146                      files: [
   147                          'scenario_handler',
   148                          'alarm_handler',
   149                      ],
   150                  },
   151              }),
   152              environment: {
   153                  buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_4,
   154              },
   155          });
   156      }
   157  
   158      private getCloudformationBuild(configs: CanaryConfig[]) {
   159          const synthCommands: string[] = new Array(configs.length)
   160          for (const config of configs) {
   161              synthCommands.push(`npm run cdk synth -- -c config=${config.env} -o dist`);
   162          }
   163  
   164          return new codebuild.PipelineProject(this, 'CFBuild', {
   165              buildSpec: codebuild.BuildSpec.fromObject({
   166                  version: '0.2',
   167                  phases: {
   168                      install: {
   169                          commands: [
   170                              'cd ops/aws/canary',
   171                              'npm install',
   172                          ]
   173                      },
   174                      pre_build: {
   175                          commands: [
   176                              'npm run build',
   177                          ],
   178                      },
   179                      build: {
   180                          commands: synthCommands,
   181                      },
   182                  },
   183                  artifacts: {
   184                      'base-directory': 'ops/aws/canary/dist',
   185                      files: [
   186                          '**/*'
   187                      ],
   188                  },
   189              }),
   190              environment: {
   191                  buildImage: codebuild.LinuxBuildImage.STANDARD_6_0,
   192              },
   193          });
   194      }
   195  
   196      private getIntegrationTest(config: CanaryConfig) {
   197          return new codebuild.PipelineProject(this, 'IntegrationTest' + config.envTitle, {
   198              buildSpec: codebuild.BuildSpec.fromObject({
   199                  version: '0.2',
   200                  env: {
   201                      variables: {
   202                          'BACALHAU_ENVIRONMENT': config.bacalhauEnvironment,
   203                      },
   204                  },
   205                  phases: {
   206                      install: {
   207                          commands: [
   208                              'rm -rf `goenv root`',
   209                              'curl --silent --show-error --location --fail https://go.dev/dl/go1.19.6.linux-amd64.tar.gz | tar --extract --gzip --file=- --directory=/usr/local',
   210                              'ln -s /usr/local/go/bin/go /usr/local/bin/go',
   211                              'go install gotest.tools/gotestsum@v1.8.2',
   212                          ],
   213                      },
   214                      build: {
   215                          commands: [
   216                              'cd ops/aws/canary/lambda',
   217                              'make integration-test',
   218                          ],
   219                      },
   220                  },
   221                  reports: {
   222                      IntegrationTest: {
   223                          files: [
   224                              'ops/aws/canary/lambda/tests.xml',
   225                          ],
   226                          'discard-paths': 'yes',
   227                      }
   228                  },
   229              }),
   230              environment: {
   231                  buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_4,
   232              },
   233          });
   234      }
   235  }