| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | import * as SDK from 'aws-sdk'; | 
					
						
							|  |  |  | import { customAlphabet } from 'nanoid'; | 
					
						
							| 
									
										
										
										
											2021-09-29 22:34:39 +00:00
										 |  |  | import CloudRunnerSecret from '../cloud-runner-services/cloud-runner-secret'; | 
					
						
							|  |  |  | import CloudRunnerEnvironmentVariable from '../cloud-runner-services/cloud-runner-environment-variable'; | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | import * as fs from 'fs'; | 
					
						
							|  |  |  | import * as core from '@actions/core'; | 
					
						
							| 
									
										
										
										
											2021-09-29 22:34:39 +00:00
										 |  |  | import CloudRunnerTaskDef from '../cloud-runner-services/cloud-runner-task-def'; | 
					
						
							|  |  |  | import CloudRunnerConstants from '../cloud-runner-services/cloud-runner-constants'; | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | import AWSBuildRunner from './aws-build-runner'; | 
					
						
							| 
									
										
										
										
											2021-09-29 22:34:39 +00:00
										 |  |  | import { CloudRunnerProviderInterface } from '../cloud-runner-services/cloud-runner-provider-interface'; | 
					
						
							| 
									
										
										
										
											2021-09-22 20:05:21 +00:00
										 |  |  | import BuildParameters from '../../build-parameters'; | 
					
						
							| 
									
										
										
										
											2021-09-29 22:34:39 +00:00
										 |  |  | import CloudRunnerLogger from '../cloud-runner-services/cloud-runner-logger'; | 
					
						
							| 
									
										
										
										
											2021-08-08 09:20:52 +00:00
										 |  |  | const crypto = require('crypto'); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 20:09:42 +00:00
										 |  |  | class AWSBuildEnvironment implements CloudRunnerProviderInterface { | 
					
						
							| 
									
										
										
										
											2021-08-13 19:59:01 +00:00
										 |  |  |   private baseStackName: string; | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   constructor(buildParameters: BuildParameters) { | 
					
						
							| 
									
										
										
										
											2021-08-13 19:59:01 +00:00
										 |  |  |     this.baseStackName = buildParameters.awsBaseStackName; | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-06-19 23:06:44 +00:00
										 |  |  |   cleanupSharedBuildResources( | 
					
						
							| 
									
										
										
										
											2021-06-19 22:15:44 +00:00
										 |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |     buildGuid: string, | 
					
						
							| 
									
										
										
										
											2021-06-19 22:15:44 +00:00
										 |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							|  |  |  |     buildParameters: BuildParameters, | 
					
						
							|  |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							|  |  |  |     branchName: string, | 
					
						
							|  |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							|  |  |  |     defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[], | 
					
						
							| 
									
										
										
										
											2021-06-19 23:25:46 +00:00
										 |  |  |   ) {} | 
					
						
							| 
									
										
										
										
											2021-06-19 23:06:44 +00:00
										 |  |  |   setupSharedBuildResources( | 
					
						
							| 
									
										
										
										
											2021-06-19 22:15:44 +00:00
										 |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |     buildGuid: string, | 
					
						
							| 
									
										
										
										
											2021-06-19 22:15:44 +00:00
										 |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							|  |  |  |     buildParameters: BuildParameters, | 
					
						
							|  |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							|  |  |  |     branchName: string, | 
					
						
							|  |  |  |     // eslint-disable-next-line no-unused-vars
 | 
					
						
							|  |  |  |     defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[], | 
					
						
							| 
									
										
										
										
											2021-06-19 23:25:46 +00:00
										 |  |  |   ) {} | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 04:49:32 +00:00
										 |  |  |   async runBuildTask( | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     buildId: string, | 
					
						
							|  |  |  |     image: string, | 
					
						
							|  |  |  |     commands: string[], | 
					
						
							|  |  |  |     mountdir: string, | 
					
						
							|  |  |  |     workingdir: string, | 
					
						
							| 
									
										
										
										
											2021-08-17 22:13:46 +00:00
										 |  |  |     environment: CloudRunnerEnvironmentVariable[], | 
					
						
							|  |  |  |     secrets: CloudRunnerSecret[], | 
					
						
							| 
									
										
										
										
											2021-06-18 20:36:45 +00:00
										 |  |  |   ): Promise<void> { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     const ECS = new SDK.ECS(); | 
					
						
							|  |  |  |     const CF = new SDK.CloudFormation(); | 
					
						
							|  |  |  |     const entrypoint = ['/bin/sh']; | 
					
						
							| 
									
										
										
										
											2021-08-15 22:59:07 +00:00
										 |  |  |     const t0 = Date.now(); | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |     const taskDef = await this.setupCloudFormations( | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |       CF, | 
					
						
							|  |  |  |       buildId, | 
					
						
							|  |  |  |       image, | 
					
						
							|  |  |  |       entrypoint, | 
					
						
							|  |  |  |       commands, | 
					
						
							|  |  |  |       mountdir, | 
					
						
							|  |  |  |       workingdir, | 
					
						
							|  |  |  |       secrets, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2021-08-15 22:59:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     let t2; | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2021-08-15 22:59:07 +00:00
										 |  |  |       const t1 = Date.now(); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |       CloudRunnerLogger.log(`Setup job time: ${Math.floor((t1 - t0) / 1000)}s`); | 
					
						
							| 
									
										
										
										
											2021-06-19 21:07:24 +00:00
										 |  |  |       await AWSBuildRunner.runTask(taskDef, ECS, CF, environment, buildId, commands); | 
					
						
							| 
									
										
										
										
											2021-08-15 22:59:07 +00:00
										 |  |  |       t2 = Date.now(); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |       CloudRunnerLogger.log(`Run job time: ${Math.floor((t2 - t1) / 1000)}s`); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     } finally { | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |       await this.cleanupResources(CF, taskDef); | 
					
						
							| 
									
										
										
										
											2021-08-15 22:59:07 +00:00
										 |  |  |       const t3 = Date.now(); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |       if (t2 !== undefined) CloudRunnerLogger.log(`Cleanup job time: ${Math.floor((t3 - t2) / 1000)}s`); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   getParameterTemplate(p1) { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     return `
 | 
					
						
							|  |  |  |   ${p1}: | 
					
						
							|  |  |  |     Type: String | 
					
						
							|  |  |  |     Default: '' | 
					
						
							|  |  |  | `;
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   getSecretTemplate(p1) { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     return `
 | 
					
						
							|  |  |  |   ${p1}Secret: | 
					
						
							|  |  |  |     Type: AWS::SecretsManager::Secret | 
					
						
							|  |  |  |     Properties: | 
					
						
							|  |  |  |       Name: !Join [ "", [ '${p1}', !Ref BUILDID ] ] | 
					
						
							|  |  |  |       SecretString: !Ref ${p1} | 
					
						
							|  |  |  | `;
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   getSecretDefinitionTemplate(p1, p2) { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     return `
 | 
					
						
							|  |  |  |             - Name: '${p1}' | 
					
						
							|  |  |  |               ValueFrom: !Ref ${p2}Secret | 
					
						
							|  |  |  | `;
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   insertAtTemplate(template, insertionKey, insertion) { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     const index = template.search(insertionKey) + insertionKey.length + '\n'.length; | 
					
						
							|  |  |  |     template = [template.slice(0, index), insertion, template.slice(index)].join(''); | 
					
						
							|  |  |  |     return template; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   async setupCloudFormations( | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     CF: SDK.CloudFormation, | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |     buildGuid: string, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     image: string, | 
					
						
							|  |  |  |     entrypoint: string[], | 
					
						
							|  |  |  |     commands: string[], | 
					
						
							|  |  |  |     mountdir: string, | 
					
						
							|  |  |  |     workingdir: string, | 
					
						
							| 
									
										
										
										
											2021-08-17 22:13:46 +00:00
										 |  |  |     secrets: CloudRunnerSecret[], | 
					
						
							| 
									
										
										
										
											2021-08-17 20:09:42 +00:00
										 |  |  |   ): Promise<CloudRunnerTaskDef> { | 
					
						
							| 
									
										
										
										
											2021-08-17 22:13:46 +00:00
										 |  |  |     const logGuid = customAlphabet(CloudRunnerConstants.alphabet, 9)(); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     commands[1] += `
 | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |       echo "${logGuid}" | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     `;
 | 
					
						
							| 
									
										
										
										
											2021-08-08 08:48:18 +00:00
										 |  |  |     await this.setupBaseStack(CF); | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |     const taskDefStackName = `${this.baseStackName}-${buildGuid}`; | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     let taskDefCloudFormation = this.readTaskCloudFormationTemplate(); | 
					
						
							|  |  |  |     const cleanupTaskDefStackName = `${taskDefStackName}-cleanup`; | 
					
						
							|  |  |  |     const cleanupCloudFormation = fs.readFileSync(`${__dirname}/cloud-formations/cloudformation-stack-ttl.yml`, 'utf8'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       for (const secret of secrets) { | 
					
						
							| 
									
										
										
										
											2021-08-15 18:40:55 +00:00
										 |  |  |         if (typeof secret.ParameterValue == 'number') { | 
					
						
							|  |  |  |           secret.ParameterValue = `${secret.ParameterValue}`; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-08-15 18:13:15 +00:00
										 |  |  |         if (!secret.ParameterValue || secret.ParameterValue === '') { | 
					
						
							| 
									
										
										
										
											2021-08-15 18:19:18 +00:00
										 |  |  |           secrets = secrets.filter((x) => x !== secret); | 
					
						
							| 
									
										
										
										
											2021-08-15 18:13:15 +00:00
										 |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |         taskDefCloudFormation = this.insertAtTemplate( | 
					
						
							|  |  |  |           taskDefCloudFormation, | 
					
						
							|  |  |  |           'p1 - input', | 
					
						
							|  |  |  |           this.getParameterTemplate(secret.ParameterKey.replace(/[^\dA-Za-z]/g, '')), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         taskDefCloudFormation = this.insertAtTemplate( | 
					
						
							|  |  |  |           taskDefCloudFormation, | 
					
						
							|  |  |  |           'p2 - secret', | 
					
						
							|  |  |  |           this.getSecretTemplate(secret.ParameterKey.replace(/[^\dA-Za-z]/g, '')), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         taskDefCloudFormation = this.insertAtTemplate( | 
					
						
							|  |  |  |           taskDefCloudFormation, | 
					
						
							|  |  |  |           'p3 - container def', | 
					
						
							|  |  |  |           this.getSecretDefinitionTemplate(secret.EnvironmentVariable, secret.ParameterKey.replace(/[^\dA-Za-z]/g, '')), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-08-21 22:41:08 +00:00
										 |  |  |       const secretsMappedToCloudFormationParameters = secrets.map((x) => { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |         return { ParameterKey: x.ParameterKey.replace(/[^\dA-Za-z]/g, ''), ParameterValue: x.ParameterValue }; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       await CF.createStack({ | 
					
						
							|  |  |  |         StackName: taskDefStackName, | 
					
						
							|  |  |  |         TemplateBody: taskDefCloudFormation, | 
					
						
							| 
									
										
										
										
											2021-08-13 18:33:34 +00:00
										 |  |  |         Capabilities: ['CAPABILITY_IAM'], | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |         Parameters: [ | 
					
						
							| 
									
										
										
										
											2021-08-21 22:41:08 +00:00
										 |  |  |           { | 
					
						
							| 
									
										
										
										
											2021-08-21 22:47:58 +00:00
										 |  |  |             ParameterKey: 'EnvironmentName', | 
					
						
							| 
									
										
										
										
											2021-08-21 22:41:08 +00:00
										 |  |  |             ParameterValue: this.baseStackName, | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'ImageUrl', | 
					
						
							|  |  |  |             ParameterValue: image, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'ServiceName', | 
					
						
							|  |  |  |             ParameterValue: taskDefStackName, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'Command', | 
					
						
							| 
									
										
										
										
											2021-06-19 21:07:24 +00:00
										 |  |  |             ParameterValue: 'echo "this template should be overwritten when running a task"', | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'EntryPoint', | 
					
						
							|  |  |  |             ParameterValue: entrypoint.join(','), | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'WorkingDirectory', | 
					
						
							|  |  |  |             ParameterValue: workingdir, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'EFSMountDirectory', | 
					
						
							|  |  |  |             ParameterValue: mountdir, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'BUILDID', | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |             ParameterValue: buildGuid, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |           }, | 
					
						
							| 
									
										
										
										
											2021-08-21 22:41:08 +00:00
										 |  |  |           ...secretsMappedToCloudFormationParameters, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |         ], | 
					
						
							|  |  |  |       }).promise(); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |       CloudRunnerLogger.log('Creating cloud runner job'); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |       await CF.createStack({ | 
					
						
							|  |  |  |         StackName: cleanupTaskDefStackName, | 
					
						
							|  |  |  |         TemplateBody: cleanupCloudFormation, | 
					
						
							|  |  |  |         Capabilities: ['CAPABILITY_IAM'], | 
					
						
							|  |  |  |         Parameters: [ | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'StackName', | 
					
						
							|  |  |  |             ParameterValue: taskDefStackName, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'DeleteStackName', | 
					
						
							|  |  |  |             ParameterValue: cleanupTaskDefStackName, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'TTL', | 
					
						
							|  |  |  |             ParameterValue: '100', | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'BUILDID', | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |             ParameterValue: buildGuid, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |           }, | 
					
						
							| 
									
										
										
										
											2021-09-15 03:10:41 +00:00
										 |  |  |           { | 
					
						
							|  |  |  |             ParameterKey: 'EnvironmentName', | 
					
						
							|  |  |  |             ParameterValue: this.baseStackName, | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |         ], | 
					
						
							|  |  |  |       }).promise(); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |       // Side effect: CloudRunnerLogger.log('Creating cleanup double checker cron job...');
 | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise(); | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |       await this.handleStackCreationFailure(error, CF, taskDefStackName, taskDefCloudFormation, secrets); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       throw error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const taskDefResources = ( | 
					
						
							|  |  |  |       await CF.describeStackResources({ | 
					
						
							|  |  |  |         StackName: taskDefStackName, | 
					
						
							|  |  |  |       }).promise() | 
					
						
							|  |  |  |     ).StackResources; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-13 19:59:01 +00:00
										 |  |  |     const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources; | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-12 23:23:19 +00:00
										 |  |  |     // TODO: offer a parameter to decide if you want the guarenteed shutdown or fastest startup time possible
 | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       taskDefStackName, | 
					
						
							|  |  |  |       taskDefCloudFormation, | 
					
						
							|  |  |  |       taskDefStackNameTTL: cleanupTaskDefStackName, | 
					
						
							|  |  |  |       ttlCloudFormation: cleanupCloudFormation, | 
					
						
							|  |  |  |       taskDefResources, | 
					
						
							|  |  |  |       baseResources, | 
					
						
							| 
									
										
										
										
											2021-08-15 21:59:58 +00:00
										 |  |  |       logid: logGuid, | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 08:48:18 +00:00
										 |  |  |   async setupBaseStack(CF: SDK.CloudFormation) { | 
					
						
							| 
									
										
										
										
											2021-08-13 19:59:01 +00:00
										 |  |  |     const baseStackName = this.baseStackName; | 
					
						
							| 
									
										
										
										
											2021-08-08 08:48:18 +00:00
										 |  |  |     const baseStack = fs.readFileSync(`${__dirname}/cloud-formations/base-setup.yml`, 'utf8'); | 
					
						
							| 
									
										
										
										
											2021-08-13 18:52:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Cloud Formation Input
 | 
					
						
							| 
									
										
										
										
											2021-08-08 09:05:16 +00:00
										 |  |  |     const describeStackInput: SDK.CloudFormation.DescribeStacksInput = { | 
					
						
							|  |  |  |       StackName: baseStackName, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-08-21 23:41:25 +00:00
										 |  |  |     const parametersWithoutHash: SDK.CloudFormation.Parameter[] = [ | 
					
						
							| 
									
										
										
										
											2021-08-21 22:41:08 +00:00
										 |  |  |       { ParameterKey: 'EnvironmentName', ParameterValue: baseStackName }, | 
					
						
							| 
									
										
										
										
											2021-08-13 18:52:37 +00:00
										 |  |  |       { ParameterKey: 'Storage', ParameterValue: `${baseStackName}-storage` }, | 
					
						
							| 
									
										
										
										
											2021-08-21 23:41:25 +00:00
										 |  |  |     ]; | 
					
						
							|  |  |  |     const hash = crypto | 
					
						
							|  |  |  |       .createHash('md5') | 
					
						
							|  |  |  |       .update(baseStack + JSON.stringify(parametersWithoutHash)) | 
					
						
							|  |  |  |       .digest('hex'); | 
					
						
							|  |  |  |     const parameters: SDK.CloudFormation.Parameter[] = [ | 
					
						
							|  |  |  |       ...parametersWithoutHash, | 
					
						
							|  |  |  |       ...[{ ParameterKey: 'Version', ParameterValue: hash }], | 
					
						
							| 
									
										
										
										
											2021-08-13 18:52:37 +00:00
										 |  |  |     ]; | 
					
						
							|  |  |  |     const updateInput: SDK.CloudFormation.UpdateStackInput = { | 
					
						
							|  |  |  |       StackName: baseStackName, | 
					
						
							|  |  |  |       TemplateBody: baseStack, | 
					
						
							|  |  |  |       Parameters: parameters, | 
					
						
							| 
									
										
										
										
											2021-08-13 18:55:38 +00:00
										 |  |  |       Capabilities: ['CAPABILITY_IAM'], | 
					
						
							| 
									
										
										
										
											2021-08-13 18:52:37 +00:00
										 |  |  |     }; | 
					
						
							|  |  |  |     const createStackInput: SDK.CloudFormation.CreateStackInput = { | 
					
						
							|  |  |  |       StackName: baseStackName, | 
					
						
							|  |  |  |       TemplateBody: baseStack, | 
					
						
							|  |  |  |       Parameters: parameters, | 
					
						
							| 
									
										
										
										
											2021-08-13 18:55:38 +00:00
										 |  |  |       Capabilities: ['CAPABILITY_IAM'], | 
					
						
							| 
									
										
										
										
											2021-08-13 18:52:37 +00:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-15 16:38:40 +00:00
										 |  |  |     const stacks = ( | 
					
						
							|  |  |  |       await CF.listStacks({ StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE'] }).promise() | 
					
						
							|  |  |  |     ).StackSummaries?.map((x) => x.StackName); | 
					
						
							| 
									
										
										
										
											2021-08-13 18:16:17 +00:00
										 |  |  |     const stackExists: Boolean = stacks?.includes(baseStackName) || false; | 
					
						
							| 
									
										
										
										
											2021-08-13 18:52:37 +00:00
										 |  |  |     const describeStack = async () => { | 
					
						
							|  |  |  |       return await CF.describeStacks(describeStackInput).promise(); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |     try { | 
					
						
							|  |  |  |       if (!stackExists) { | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |         CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stacks)})`); | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |         await CF.createStack(createStackInput).promise(); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |         CloudRunnerLogger.log(`created stack (version: ${hash})`); | 
					
						
							| 
									
										
										
										
											2021-08-08 09:05:16 +00:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |       const CFState = await describeStack(); | 
					
						
							|  |  |  |       let stack = CFState.Stacks?.[0]; | 
					
						
							| 
									
										
										
										
											2021-08-13 18:16:17 +00:00
										 |  |  |       if (!stack) { | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |         throw new Error(`Base stack doesn't exist, even after creation, stackExists check: ${stackExists}`); | 
					
						
							| 
									
										
										
										
											2021-08-13 18:16:17 +00:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |       const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (stack.StackStatus === 'CREATE_IN_PROGRESS') { | 
					
						
							|  |  |  |         await CF.waitFor('stackCreateComplete', describeStackInput).promise(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (stackExists) { | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |         CloudRunnerLogger.log(`Base stack exists (version: ${stackVersion}, local version: ${hash})`); | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |         if (hash !== stackVersion) { | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |           CloudRunnerLogger.log(`Updating`); | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |           await CF.updateStack(updateInput).promise(); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |           CloudRunnerLogger.log(`No update required`); | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         stack = (await describeStack()).Stacks?.[0]; | 
					
						
							|  |  |  |         if (!stack) { | 
					
						
							|  |  |  |           throw new Error( | 
					
						
							|  |  |  |             `Base stack doesn't exist, even after updating and creation, stackExists check: ${stackExists}`, | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (stack.StackStatus === 'UPDATE_IN_PROGRESS') { | 
					
						
							|  |  |  |           await CF.waitFor('stackUpdateComplete', describeStackInput).promise(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-08-13 18:16:17 +00:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |       CloudRunnerLogger.log('base stack is ready'); | 
					
						
							| 
									
										
										
										
											2021-08-22 00:15:02 +00:00
										 |  |  |     } catch (error) { | 
					
						
							|  |  |  |       core.error(JSON.stringify(await describeStack(), undefined, 4)); | 
					
						
							|  |  |  |       throw error; | 
					
						
							| 
									
										
										
										
											2021-08-08 09:05:16 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-08 08:48:18 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   async handleStackCreationFailure( | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     error: any, | 
					
						
							|  |  |  |     CF: SDK.CloudFormation, | 
					
						
							|  |  |  |     taskDefStackName: string, | 
					
						
							|  |  |  |     taskDefCloudFormation: string, | 
					
						
							| 
									
										
										
										
											2021-08-17 22:13:46 +00:00
										 |  |  |     secrets: CloudRunnerSecret[], | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |   ) { | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |     CloudRunnerLogger.log(JSON.stringify(secrets, undefined, 4)); | 
					
						
							|  |  |  |     CloudRunnerLogger.log(taskDefCloudFormation); | 
					
						
							| 
									
										
										
										
											2021-08-15 18:35:27 +00:00
										 |  |  |     core.error(error); | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |     CloudRunnerLogger.log('Getting events and resources for task stack'); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents; | 
					
						
							|  |  |  |     const resources = (await CF.describeStackResources({ StackName: taskDefStackName }).promise()).StackResources; | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |     CloudRunnerLogger.log(JSON.stringify(events, undefined, 4)); | 
					
						
							|  |  |  |     CloudRunnerLogger.log(JSON.stringify(resources, undefined, 4)); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-19 20:35:22 +00:00
										 |  |  |   readTaskCloudFormationTemplate(): string { | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     return fs.readFileSync(`${__dirname}/cloud-formations/task-def-formation.yml`, 'utf8'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 20:09:42 +00:00
										 |  |  |   async cleanupResources(CF: SDK.CloudFormation, taskDef: CloudRunnerTaskDef) { | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |     CloudRunnerLogger.log('Cleanup starting'); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |     await CF.deleteStack({ | 
					
						
							|  |  |  |       StackName: taskDef.taskDefStackName, | 
					
						
							|  |  |  |     }).promise(); | 
					
						
							|  |  |  |     await CF.deleteStack({ | 
					
						
							|  |  |  |       StackName: taskDef.taskDefStackNameTTL, | 
					
						
							|  |  |  |     }).promise(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await CF.waitFor('stackDeleteComplete', { | 
					
						
							|  |  |  |       StackName: taskDef.taskDefStackName, | 
					
						
							|  |  |  |     }).promise(); | 
					
						
							|  |  |  |     await CF.waitFor('stackDeleteComplete', { | 
					
						
							|  |  |  |       StackName: taskDef.taskDefStackNameTTL, | 
					
						
							|  |  |  |     }).promise(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-15 03:20:04 +00:00
										 |  |  |     const stacks = (await CF.listStacks().promise()).StackSummaries?.filter((x) => x.StackStatus !== 'DELETE_COMPLETE'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |     CloudRunnerLogger.log(`Deleted Stacks: ${taskDef.taskDefStackName}, ${taskDef.taskDefStackNameTTL}`); | 
					
						
							|  |  |  |     CloudRunnerLogger.log(`Stacks: ${JSON.stringify(stacks, undefined, 4)}`); | 
					
						
							| 
									
										
										
										
											2021-09-15 03:20:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 18:27:04 +00:00
										 |  |  |     CloudRunnerLogger.log('Cleanup complete'); | 
					
						
							| 
									
										
										
										
											2021-05-23 04:08:40 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | export default AWSBuildEnvironment; |