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 }