carlin 1.19.11 → 1.19.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/cli.js +232 -0
  2. package/dist/config.js +10 -0
  3. package/dist/deploy/addDefaults.cloudFormation.js +138 -0
  4. package/dist/deploy/baseStack/command.js +9 -0
  5. package/dist/deploy/baseStack/config.js +30 -0
  6. package/dist/deploy/baseStack/deployBaseStack.js +59 -0
  7. package/dist/deploy/baseStack/getBaseStackResource.js +26 -0
  8. package/dist/deploy/baseStack/getBucket.template.js +44 -0
  9. package/dist/deploy/baseStack/getLambdaImageBuilder.template.js +186 -0
  10. package/dist/deploy/baseStack/getLambdaLayerBuilder.template.js +140 -0
  11. package/dist/deploy/baseStack/getVpc.template.js +169 -0
  12. package/dist/deploy/cicd/cicd.template.js +922 -0
  13. package/dist/deploy/cicd/command.js +27 -0
  14. package/dist/deploy/cicd/command.options.js +71 -0
  15. package/dist/deploy/cicd/config.js +8 -0
  16. package/dist/deploy/cicd/deployCicd.js +93 -0
  17. package/dist/deploy/cicd/ecsTaskReportCommand.js +51 -0
  18. package/dist/deploy/cicd/getCicdStackName.js +11 -0
  19. package/dist/deploy/cicd/getTriggerPipelineObjectKey.js +11 -0
  20. package/dist/deploy/cicd/lambdas/cicdApiV1.handler.js +124 -0
  21. package/dist/deploy/cicd/lambdas/ecsTaskReport.handler.js +126 -0
  22. package/dist/deploy/cicd/lambdas/executeTasks.js +67 -0
  23. package/dist/deploy/cicd/lambdas/getProcessEnvVariable.js +10 -0
  24. package/dist/deploy/cicd/lambdas/githubWebhooksApiV1.handler.js +146 -0
  25. package/dist/deploy/cicd/lambdas/imageUpdaterSchedule.handler.js +44 -0
  26. package/dist/deploy/cicd/lambdas/index.js +13 -0
  27. package/dist/deploy/cicd/lambdas/pipelines.handler.js +134 -0
  28. package/dist/deploy/cicd/lambdas/putApprovalResultManualTask.js +52 -0
  29. package/dist/deploy/cicd/lambdas/shConditionalCommands.js +30 -0
  30. package/dist/deploy/cicd/pipelines.js +76 -0
  31. package/dist/deploy/cicd/readSSHKey.js +10 -0
  32. package/dist/deploy/cloudFormation.core.js +300 -0
  33. package/dist/deploy/cloudFormation.js +182 -0
  34. package/dist/deploy/command.js +185 -0
  35. package/dist/deploy/lambda/buildLambdaSingleFile.js +30 -0
  36. package/dist/deploy/lambda/deployLambdaCode.js +41 -0
  37. package/dist/deploy/lambda/deployLambdaLayers.js +34 -0
  38. package/dist/deploy/lambda/uploadCodeToECR.js +53 -0
  39. package/dist/deploy/lambda/uploadCodeToS3.js +31 -0
  40. package/dist/deploy/lambdaLayer/command.js +48 -0
  41. package/dist/deploy/lambdaLayer/deployLambdaLayer.js +140 -0
  42. package/dist/deploy/readDockerfile.js +18 -0
  43. package/dist/deploy/s3.js +165 -0
  44. package/dist/deploy/stackName.js +78 -0
  45. package/dist/deploy/staticApp/command.js +79 -0
  46. package/dist/deploy/staticApp/deployStaticApp.js +64 -0
  47. package/dist/deploy/staticApp/findDefaultBuildFolder.js +27 -0
  48. package/dist/deploy/staticApp/getOriginShieldRegion.js +30 -0
  49. package/dist/deploy/staticApp/getStaticAppBucket.js +19 -0
  50. package/dist/deploy/staticApp/invalidateCloudFront.js +42 -0
  51. package/dist/deploy/staticApp/removeOldVersions.js +43 -0
  52. package/dist/deploy/staticApp/staticApp.template.js +303 -0
  53. package/dist/deploy/staticApp/uploadBuiltAppToS3.js +27 -0
  54. package/dist/deploy/utils.js +29 -0
  55. package/dist/generateEnv/generateEnv.js +46 -0
  56. package/dist/generateEnv/generateEnvCommand.js +9 -0
  57. package/dist/index.js +5 -0
  58. package/dist/utils/addGroupToOptions.js +11 -0
  59. package/dist/utils/cloudFormationTemplate.js +132 -0
  60. package/dist/utils/codeBuild.js +50 -0
  61. package/dist/utils/environmentVariables.js +11 -0
  62. package/dist/utils/exec.js +22 -0
  63. package/dist/utils/formatCode.js +12 -0
  64. package/dist/utils/getAwsAccountId.js +10 -0
  65. package/dist/utils/getCurrentBranch.js +33 -0
  66. package/dist/utils/getEnvironment.js +6 -0
  67. package/dist/utils/getIamPath.js +6 -0
  68. package/dist/utils/getProjectName.js +35 -0
  69. package/dist/utils/index.js +17 -0
  70. package/dist/utils/packageJson.js +25 -0
  71. package/dist/utils/readCloudFormationTemplate.js +33 -0
  72. package/dist/utils/readObjectFile.js +46 -0
  73. package/package.json +3 -3
@@ -0,0 +1,922 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCicdTemplate = exports.getRepositoryImageBuilder = exports.IMAGE_UPDATER_SCHEDULE_SERVERLESS_FUNCTION_LOGICAL_ID = exports.PIPELINES_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID = exports.PIPELINES_TAG_LOGICAL_ID = exports.PIPELINES_MAIN_LOGICAL_ID = exports.PIPELINES_ROLE_LOGICAL_ID = exports.PIPELINES_ARTIFACT_STORE_S3_BUCKET_LOGICAL_ID = exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_TASK_ROLE_LOGICAL_ID = exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_EXECUTION_ROLE_LOGICAL_ID = exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGS_LOG_GROUP_LOGICAL_ID = exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGICAL_ID = exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID = exports.REPOSITORY_ECS_TASK_DEFINITION_LOGICAL_ID = exports.REPOSITORY_ECS_TASK_CONTAINER_NAME = exports.PROCESS_ENV_REPOSITORY_IMAGE_CODE_BUILD_PROJECT_NAME = exports.ECS_TASK_REPORT_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID = exports.FUNCTION_IAM_ROLE_LOGICAL_ID = exports.ECR_REPOSITORY_LOGICAL_ID = exports.CODE_BUILD_PROJECT_SERVICE_ROLE_LOGICAL_ID = exports.CODE_BUILD_PROJECT_LOGS_LOGICAL_ID = exports.API_LOGICAL_ID = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const config_1 = require("../baseStack/config");
6
+ const command_options_1 = require("./command.options");
7
+ const utils_1 = require("../../utils");
8
+ const config_2 = require("./config");
9
+ const change_case_1 = require("change-case");
10
+ const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
11
+ const getTriggerPipelineObjectKey_1 = require("./getTriggerPipelineObjectKey");
12
+ exports.API_LOGICAL_ID = 'ApiV1ServerlessApi';
13
+ exports.CODE_BUILD_PROJECT_LOGS_LOGICAL_ID = 'RepositoryImageCodeBuildProjectLogsLogGroup';
14
+ exports.CODE_BUILD_PROJECT_SERVICE_ROLE_LOGICAL_ID = 'RepositoryImageCodeBuildProjectIAMRole';
15
+ exports.ECR_REPOSITORY_LOGICAL_ID = 'RepositoryECRRepository';
16
+ exports.FUNCTION_IAM_ROLE_LOGICAL_ID = 'ApiV1ServerlessFunctionIAMRole';
17
+ exports.ECS_TASK_REPORT_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID = 'EcsTaskReportHandler';
18
+ exports.PROCESS_ENV_REPOSITORY_IMAGE_CODE_BUILD_PROJECT_NAME = 'REPOSITORY_IMAGE_CODE_BUILD_PROJECT_NAME';
19
+ exports.REPOSITORY_ECS_TASK_CONTAINER_NAME = 'RepositoryECSTaskContainerName';
20
+ exports.REPOSITORY_ECS_TASK_DEFINITION_LOGICAL_ID = 'RepositoryECSTaskDefinition';
21
+ exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID = 'RepositoryImageCodeBuildProject';
22
+ exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGICAL_ID = 'RepositoryTasksECSCluster';
23
+ exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGS_LOG_GROUP_LOGICAL_ID = 'RepositoryTasksECSClusterLogsLogGroup';
24
+ exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_EXECUTION_ROLE_LOGICAL_ID = 'RepositoryTasksECSTaskDefinitionExecutionRoleIAMRole';
25
+ exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_TASK_ROLE_LOGICAL_ID = 'RepositoryTasksECSTaskDefinitionTaskRoleIAMRole';
26
+ exports.PIPELINES_ARTIFACT_STORE_S3_BUCKET_LOGICAL_ID = 'PipelinesArtifactStoreS3Bucket';
27
+ exports.PIPELINES_ROLE_LOGICAL_ID = 'PipelinesMainIAMRole';
28
+ exports.PIPELINES_MAIN_LOGICAL_ID = 'PipelinesMainCodePipeline';
29
+ exports.PIPELINES_TAG_LOGICAL_ID = 'PipelinesTagCodePipeline';
30
+ exports.PIPELINES_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID = 'PipelinesHandlerLambdaFunction';
31
+ exports.IMAGE_UPDATER_SCHEDULE_SERVERLESS_FUNCTION_LOGICAL_ID = 'ImageUpdaterScheduleServerlessFunction';
32
+ /**
33
+ * An [AWS CodeBuild](https://aws.amazon.com/codebuild/) project is created
34
+ * to build (create and update) repository images. It uses a
35
+ * [BUILD\_GENERAL1\_SMALL environment compute type](https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-compute-types.html)
36
+ * with Linux as operational system to build the image.
37
+ */
38
+ const getRepositoryImageBuilder = () => ({
39
+ Type: 'AWS::CodeBuild::Project',
40
+ Properties: {
41
+ Artifacts: {
42
+ Type: 'NO_ARTIFACTS',
43
+ },
44
+ Cache: {
45
+ Location: 'LOCAL',
46
+ Modes: ['LOCAL_DOCKER_LAYER_CACHE'],
47
+ Type: 'LOCAL',
48
+ },
49
+ Description: 'Create repository image.',
50
+ Environment: {
51
+ ComputeType: 'BUILD_GENERAL1_SMALL',
52
+ EnvironmentVariables: [
53
+ {
54
+ Name: 'AWS_ACCOUNT_ID',
55
+ Value: { Ref: 'AWS::AccountId' },
56
+ },
57
+ {
58
+ Name: 'AWS_REGION',
59
+ Value: { Ref: 'AWS::Region' },
60
+ },
61
+ {
62
+ Name: 'DOCKERFILE',
63
+ Value: {
64
+ 'Fn::Sub': [
65
+ 'FROM public.ecr.aws/ubuntu/ubuntu:20.04_stable',
66
+ // https://stackoverflow.com/a/59693182/8786986
67
+ 'ENV DEBIAN_FRONTEND noninteractive',
68
+ // Make sure apt is up to date
69
+ 'RUN apt-get update --fix-missing',
70
+ 'RUN apt-get install -y curl',
71
+ 'RUN apt-get install -y git',
72
+ 'RUN apt-get install -y jq',
73
+ // Install Node.js
74
+ 'RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -',
75
+ 'RUN apt-get install -y nodejs',
76
+ // Clean cache
77
+ 'RUN apt-get clean',
78
+ // Install Yarn
79
+ 'RUN npm install -g yarn',
80
+ // Install carlin CLI
81
+ 'RUN yarn global add carlin',
82
+ // Configure git
83
+ 'RUN git config --global user.name carlin',
84
+ 'RUN git config --global user.email carlin@ttoss.dev',
85
+ 'RUN mkdir /root/.ssh/',
86
+ 'COPY ./id_rsa /root/.ssh/id_rsa',
87
+ 'RUN chmod 600 /root/.ssh/id_rsa',
88
+ // Make sure your domain is accepted
89
+ 'RUN touch /root/.ssh/known_hosts',
90
+ 'RUN ssh-keyscan github.com >> /root/.ssh/known_hosts',
91
+ // Copy repository
92
+ 'COPY . /home',
93
+ // Go to repository directory
94
+ 'WORKDIR /home/repository',
95
+ // Set Yarn cache
96
+ 'RUN mkdir -p /home/yarn-cache',
97
+ 'RUN yarn config set cache-folder /home/yarn-cache',
98
+ 'RUN yarn install',
99
+ // Used in case of yarn.lock is modified.
100
+ 'RUN git checkout -- yarn.lock',
101
+ ].join('\n'),
102
+ },
103
+ },
104
+ {
105
+ Name: 'IMAGE_TAG',
106
+ Value: 'latest',
107
+ },
108
+ {
109
+ Name: 'REPOSITORY_ECR_REPOSITORY',
110
+ Value: { Ref: exports.ECR_REPOSITORY_LOGICAL_ID },
111
+ },
112
+ {
113
+ Name: 'SSH_KEY',
114
+ Value: { Ref: 'SSHKey' },
115
+ },
116
+ {
117
+ Name: 'SSH_URL',
118
+ Value: { Ref: 'SSHUrl' },
119
+ },
120
+ ],
121
+ Image: 'aws/codebuild/standard:3.0',
122
+ ImagePullCredentialsType: 'CODEBUILD',
123
+ /**
124
+ * Enables running the Docker daemon inside a Docker container. Set to
125
+ * true only if the build project is used to build Docker images.
126
+ * Otherwise, a build that attempts to interact with the Docker daemon
127
+ * fails. The default setting is false."
128
+ * https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-environment.html#cfn-codebuild-project-environment-privilegedmode
129
+ */
130
+ PrivilegedMode: true,
131
+ Type: 'LINUX_CONTAINER',
132
+ },
133
+ LogsConfig: {
134
+ CloudWatchLogs: {
135
+ Status: 'ENABLED',
136
+ GroupName: { Ref: exports.CODE_BUILD_PROJECT_LOGS_LOGICAL_ID },
137
+ },
138
+ },
139
+ ServiceRole: {
140
+ 'Fn::GetAtt': [exports.CODE_BUILD_PROJECT_SERVICE_ROLE_LOGICAL_ID, 'Arn'],
141
+ },
142
+ Source: {
143
+ BuildSpec: js_yaml_1.default.dump({
144
+ version: '0.2',
145
+ phases: {
146
+ install: {
147
+ commands: [
148
+ 'echo install started on `date`',
149
+ `echo "$SSH_KEY" > ~/.ssh/id_rsa`,
150
+ 'chmod 600 ~/.ssh/id_rsa',
151
+ 'rm -rf repository',
152
+ 'git clone $SSH_URL repository',
153
+ 'cd repository',
154
+ 'ls',
155
+ ],
156
+ },
157
+ pre_build: {
158
+ commands: ['echo pre_build started on `date`'],
159
+ },
160
+ build: {
161
+ commands: [
162
+ 'echo build started on `date`',
163
+ '$(aws ecr get-login --no-include-email --region $AWS_REGION)',
164
+ 'echo Building the repository image...',
165
+ 'cd ../',
166
+ 'cp ~/.ssh/id_rsa .',
167
+ 'echo "$DOCKERFILE" > Dockerfile',
168
+ 'cat Dockerfile',
169
+ 'docker build -t $REPOSITORY_ECR_REPOSITORY:$IMAGE_TAG -f Dockerfile .',
170
+ 'docker tag $REPOSITORY_ECR_REPOSITORY:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPOSITORY_ECR_REPOSITORY:$IMAGE_TAG',
171
+ 'echo Pushing the repository image...',
172
+ 'docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPOSITORY_ECR_REPOSITORY:$IMAGE_TAG',
173
+ ],
174
+ },
175
+ post_build: {
176
+ commands: ['echo post_build completed on `date`'],
177
+ },
178
+ },
179
+ }),
180
+ Type: 'NO_SOURCE',
181
+ },
182
+ TimeoutInMinutes: 15,
183
+ },
184
+ });
185
+ exports.getRepositoryImageBuilder = getRepositoryImageBuilder;
186
+ /**
187
+ * This variable is used inside GitHub webhooks to identify the object key
188
+ * prefix of the file that triggers the pipelines.
189
+ */
190
+ const triggerPipelinesObjectKeyPrefix = [
191
+ 'cicd',
192
+ 'pipelines',
193
+ 'triggers',
194
+ (0, utils_1.getProjectName)(),
195
+ ].join('/');
196
+ const getCicdTemplate = ({ pipelines = [], cpu = config_2.ECS_TASK_DEFAULT_CPU, memory = config_2.ECS_TASK_DEFAULT_MEMORY, s3, slackWebhookUrl, taskEnvironment = [], }) => {
197
+ const resources = {};
198
+ const executeEcsTaskVariables = {
199
+ ECS_CLUSTER_ARN: {
200
+ 'Fn::GetAtt': [exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGICAL_ID, 'Arn'],
201
+ },
202
+ ECS_CONTAINER_NAME: exports.REPOSITORY_ECS_TASK_CONTAINER_NAME,
203
+ ECS_TASK_DEFINITION: {
204
+ Ref: exports.REPOSITORY_ECS_TASK_DEFINITION_LOGICAL_ID,
205
+ },
206
+ VPC_SECURITY_GROUP: {
207
+ 'Fn::ImportValue': config_1.BASE_STACK_VPC_DEFAULT_SECURITY_GROUP_EXPORTED_NAME,
208
+ },
209
+ VPC_PUBLIC_SUBNET_0: {
210
+ 'Fn::ImportValue': config_1.BASE_STACK_VPC_PUBLIC_SUBNET_0_EXPORTED_NAME,
211
+ },
212
+ VPC_PUBLIC_SUBNET_1: {
213
+ 'Fn::ImportValue': config_1.BASE_STACK_VPC_PUBLIC_SUBNET_1_EXPORTED_NAME,
214
+ },
215
+ VPC_PUBLIC_SUBNET_2: {
216
+ 'Fn::ImportValue': config_1.BASE_STACK_VPC_PUBLIC_SUBNET_2_EXPORTED_NAME,
217
+ },
218
+ ECS_TASK_REPORT_HANDLER_NAME: {
219
+ Ref: exports.ECS_TASK_REPORT_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID,
220
+ },
221
+ };
222
+ /**
223
+ * The algorithm will clone the repository and will create a Docker image
224
+ * to be used to perform your commands. [Yarn cache](https://classic.yarnpkg.com/en/docs/cli/cache/)
225
+ * will also be saved together with the code to reduce packages installation
226
+ * time. The created image will be pushed to [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/).
227
+ * with a defined expiration rule is also defined. The registry only keeps
228
+ * the latest image.
229
+ */
230
+ const getEcrRepositoryResource = () => ({
231
+ Type: 'AWS::ECR::Repository',
232
+ Properties: {
233
+ LifecyclePolicy: {
234
+ LifecyclePolicyText: JSON.stringify({
235
+ rules: [
236
+ {
237
+ rulePriority: 1,
238
+ description: 'Only keep the latest image',
239
+ selection: {
240
+ tagStatus: 'any',
241
+ countType: 'imageCountMoreThan',
242
+ countNumber: 1,
243
+ },
244
+ action: {
245
+ type: 'expire',
246
+ },
247
+ },
248
+ ],
249
+ }, null, 2),
250
+ },
251
+ },
252
+ });
253
+ resources[exports.ECR_REPOSITORY_LOGICAL_ID] = getEcrRepositoryResource();
254
+ const commonFunctionProperties = {
255
+ CodeUri: {
256
+ Bucket: s3.bucket,
257
+ Key: s3.key,
258
+ Version: s3.versionId,
259
+ },
260
+ Role: {
261
+ 'Fn::GetAtt': [exports.FUNCTION_IAM_ROLE_LOGICAL_ID, 'Arn'],
262
+ },
263
+ Runtime: 'nodejs14.x',
264
+ Timeout: 60,
265
+ };
266
+ /**
267
+ * CodeBuild
268
+ */
269
+ (() => {
270
+ resources[exports.CODE_BUILD_PROJECT_LOGS_LOGICAL_ID] = {
271
+ Type: 'AWS::Logs::LogGroup',
272
+ DeletionPolicy: 'Delete',
273
+ Properties: {},
274
+ };
275
+ resources[exports.CODE_BUILD_PROJECT_SERVICE_ROLE_LOGICAL_ID] = {
276
+ Type: 'AWS::IAM::Role',
277
+ Properties: {
278
+ AssumeRolePolicyDocument: {
279
+ Version: '2012-10-17',
280
+ Statement: [
281
+ {
282
+ Effect: 'Allow',
283
+ Principal: {
284
+ Service: 'codebuild.amazonaws.com',
285
+ },
286
+ Action: 'sts:AssumeRole',
287
+ },
288
+ ],
289
+ },
290
+ Path: (0, utils_1.getIamPath)(),
291
+ Policies: [
292
+ {
293
+ PolicyName: `${exports.CODE_BUILD_PROJECT_SERVICE_ROLE_LOGICAL_ID}Policy`,
294
+ PolicyDocument: {
295
+ Version: '2012-10-17',
296
+ Statement: [
297
+ {
298
+ Effect: 'Allow',
299
+ Action: ['logs:CreateLogStream', 'logs:PutLogEvents'],
300
+ Resource: '*',
301
+ },
302
+ {
303
+ Effect: 'Allow',
304
+ Action: ['ecr:GetAuthorizationToken'],
305
+ Resource: '*',
306
+ },
307
+ {
308
+ Effect: 'Allow',
309
+ Action: [
310
+ 'ecr:BatchCheckLayerAvailability',
311
+ 'ecr:CompleteLayerUpload',
312
+ 'ecr:InitiateLayerUpload',
313
+ 'ecr:PutImage',
314
+ 'ecr:UploadLayerPart',
315
+ ],
316
+ Resource: {
317
+ 'Fn::GetAtt': [exports.ECR_REPOSITORY_LOGICAL_ID, 'Arn'],
318
+ },
319
+ },
320
+ ],
321
+ },
322
+ },
323
+ ],
324
+ },
325
+ };
326
+ resources[exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID] =
327
+ (0, exports.getRepositoryImageBuilder)();
328
+ const cicdConfig = {
329
+ ...(0, command_options_1.getCicdConfig)(),
330
+ 'ssh-key': '/root/.ssh/id_rsa',
331
+ environment: (0, utils_1.getEnvironment)(),
332
+ };
333
+ resources[exports.IMAGE_UPDATER_SCHEDULE_SERVERLESS_FUNCTION_LOGICAL_ID] = {
334
+ Type: 'AWS::Serverless::Function',
335
+ Properties: {
336
+ ...commonFunctionProperties,
337
+ Events: {
338
+ Schedule: {
339
+ Type: 'Schedule',
340
+ Properties: {
341
+ Schedule: 'rate(7 days)',
342
+ },
343
+ },
344
+ },
345
+ Environment: {
346
+ Variables: {
347
+ [exports.PROCESS_ENV_REPOSITORY_IMAGE_CODE_BUILD_PROJECT_NAME]: {
348
+ Ref: exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID,
349
+ },
350
+ CICD_CONFIG: JSON.stringify(cicdConfig),
351
+ ...executeEcsTaskVariables,
352
+ },
353
+ },
354
+ Handler: 'index.imageUpdaterScheduleHandler',
355
+ },
356
+ };
357
+ })();
358
+ const createApiResources = () => {
359
+ resources[exports.API_LOGICAL_ID] = {
360
+ Type: 'AWS::Serverless::Api',
361
+ Properties: {
362
+ Auth: {
363
+ ApiKeyRequired: false,
364
+ },
365
+ StageName: 'v1',
366
+ },
367
+ };
368
+ resources[exports.FUNCTION_IAM_ROLE_LOGICAL_ID] = {
369
+ Type: 'AWS::IAM::Role',
370
+ Properties: {
371
+ AssumeRolePolicyDocument: {
372
+ Version: '2012-10-17',
373
+ Statement: [
374
+ {
375
+ Effect: 'Allow',
376
+ Principal: {
377
+ Service: 'lambda.amazonaws.com',
378
+ },
379
+ Action: ['sts:AssumeRole'],
380
+ },
381
+ ],
382
+ },
383
+ ManagedPolicyArns: [
384
+ 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole',
385
+ ],
386
+ Path: (0, utils_1.getIamPath)(),
387
+ Policies: [
388
+ {
389
+ PolicyName: `${exports.FUNCTION_IAM_ROLE_LOGICAL_ID}Policy`,
390
+ PolicyDocument: {
391
+ Version: '2012-10-17',
392
+ Statement: [
393
+ {
394
+ Effect: 'Allow',
395
+ Action: ['codebuild:StartBuild'],
396
+ Resource: {
397
+ 'Fn::GetAtt': [
398
+ exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID,
399
+ 'Arn',
400
+ ],
401
+ },
402
+ },
403
+ {
404
+ Effect: 'Allow',
405
+ Action: ['iam:PassRole'],
406
+ Resource: [
407
+ {
408
+ 'Fn::GetAtt': [
409
+ exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_EXECUTION_ROLE_LOGICAL_ID,
410
+ 'Arn',
411
+ ],
412
+ },
413
+ {
414
+ 'Fn::GetAtt': [
415
+ exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_TASK_ROLE_LOGICAL_ID,
416
+ 'Arn',
417
+ ],
418
+ },
419
+ ],
420
+ },
421
+ {
422
+ Effect: 'Allow',
423
+ Action: ['ecs:DescribeTasks'],
424
+ Resource: '*',
425
+ },
426
+ {
427
+ Effect: 'Allow',
428
+ Action: ['ecs:RunTask'],
429
+ Resource: [
430
+ {
431
+ Ref: exports.REPOSITORY_ECS_TASK_DEFINITION_LOGICAL_ID,
432
+ },
433
+ ],
434
+ },
435
+ {
436
+ Action: [
437
+ 'codepipeline:PutApprovalResult',
438
+ 'codepipeline:GetJobDetails',
439
+ 'codepipeline:GetPipelineState',
440
+ 'codepipeline:PutJobSuccessResult',
441
+ 'codepipeline:PutJobFailureResult',
442
+ ],
443
+ Effect: 'Allow',
444
+ Resource: '*',
445
+ },
446
+ {
447
+ Action: 's3:*',
448
+ Effect: 'Allow',
449
+ Resource: {
450
+ 'Fn::Sub': [
451
+ `arn:aws:s3:::\${BucketName}/${triggerPipelinesObjectKeyPrefix}*`,
452
+ {
453
+ BucketName: {
454
+ 'Fn::ImportValue': config_1.BASE_STACK_BUCKET_NAME_EXPORTED_NAME,
455
+ },
456
+ },
457
+ ],
458
+ },
459
+ },
460
+ ],
461
+ },
462
+ },
463
+ ],
464
+ },
465
+ };
466
+ /**
467
+ * Called after ECS task execution success or failure.
468
+ */
469
+ resources[exports.ECS_TASK_REPORT_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID] = {
470
+ Type: 'AWS::Serverless::Function',
471
+ Properties: {
472
+ ...commonFunctionProperties,
473
+ Environment: {
474
+ Variables: {
475
+ ECS_TASK_LOGS_LOG_GROUP: {
476
+ Ref: exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGS_LOG_GROUP_LOGICAL_ID,
477
+ },
478
+ ECS_TASK_CONTAINER_NAME: exports.REPOSITORY_ECS_TASK_CONTAINER_NAME,
479
+ SLACK_WEBHOOK_URL: slackWebhookUrl,
480
+ },
481
+ },
482
+ Handler: 'index.ecsTaskReportHandler',
483
+ },
484
+ };
485
+ resources.CicdApiV1ServerlessFunction = {
486
+ Type: 'AWS::Serverless::Function',
487
+ Properties: {
488
+ ...commonFunctionProperties,
489
+ Events: {
490
+ ApiEvent: {
491
+ Type: 'Api',
492
+ Properties: {
493
+ Method: 'POST',
494
+ Path: '/cicd',
495
+ RestApiId: { Ref: exports.API_LOGICAL_ID },
496
+ },
497
+ },
498
+ },
499
+ Environment: {
500
+ Variables: {
501
+ [exports.PROCESS_ENV_REPOSITORY_IMAGE_CODE_BUILD_PROJECT_NAME]: {
502
+ Ref: exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID,
503
+ },
504
+ ...executeEcsTaskVariables,
505
+ },
506
+ },
507
+ Handler: 'index.cicdApiV1Handler',
508
+ },
509
+ };
510
+ resources.GitHubWebhooksApiV1ServerlessFunction = {
511
+ Type: 'AWS::Serverless::Function',
512
+ Properties: {
513
+ ...commonFunctionProperties,
514
+ Events: {
515
+ ApiEvent: {
516
+ Type: 'Api',
517
+ Properties: {
518
+ Method: 'POST',
519
+ Path: '/github/webhooks',
520
+ RestApiId: { Ref: exports.API_LOGICAL_ID },
521
+ },
522
+ },
523
+ },
524
+ Environment: {
525
+ Variables: {
526
+ BASE_STACK_BUCKET_NAME: {
527
+ 'Fn::ImportValue': config_1.BASE_STACK_BUCKET_NAME_EXPORTED_NAME,
528
+ },
529
+ TRIGGER_PIPELINES_OBJECT_KEY_PREFIX: triggerPipelinesObjectKeyPrefix,
530
+ PIPELINES_JSON: JSON.stringify(pipelines),
531
+ ...executeEcsTaskVariables,
532
+ },
533
+ },
534
+ Handler: 'index.githubWebhooksApiV1Handler',
535
+ },
536
+ };
537
+ };
538
+ createApiResources();
539
+ /**
540
+ * ECS
541
+ */
542
+ (() => {
543
+ resources[exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGICAL_ID] = {
544
+ Type: 'AWS::ECS::Cluster',
545
+ Properties: {},
546
+ };
547
+ resources[exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGS_LOG_GROUP_LOGICAL_ID] = {
548
+ Type: 'AWS::Logs::LogGroup',
549
+ DeletionPolicy: 'Delete',
550
+ Properties: {},
551
+ };
552
+ /**
553
+ * Used to start the container.
554
+ */
555
+ resources[exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_EXECUTION_ROLE_LOGICAL_ID] =
556
+ {
557
+ Type: 'AWS::IAM::Role',
558
+ Properties: {
559
+ AssumeRolePolicyDocument: {
560
+ Version: '2012-10-17',
561
+ Statement: [
562
+ {
563
+ Effect: 'Allow',
564
+ Principal: {
565
+ Service: 'ecs-tasks.amazonaws.com',
566
+ },
567
+ Action: 'sts:AssumeRole',
568
+ },
569
+ ],
570
+ },
571
+ ManagedPolicyArns: [
572
+ 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy',
573
+ ],
574
+ Path: (0, utils_1.getIamPath)(),
575
+ },
576
+ };
577
+ /**
578
+ * Used inside de container execution.
579
+ */
580
+ resources[exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_TASK_ROLE_LOGICAL_ID] = {
581
+ Type: 'AWS::IAM::Role',
582
+ Properties: {
583
+ AssumeRolePolicyDocument: {
584
+ Version: '2012-10-17',
585
+ Statement: [
586
+ {
587
+ Effect: 'Allow',
588
+ Principal: {
589
+ Service: 'ecs-tasks.amazonaws.com',
590
+ },
591
+ Action: 'sts:AssumeRole',
592
+ },
593
+ ],
594
+ },
595
+ ManagedPolicyArns: [
596
+ 'arn:aws:iam::aws:policy/job-function/ViewOnlyAccess',
597
+ ],
598
+ Path: (0, utils_1.getIamPath)(),
599
+ /**
600
+ * TODO: improve the policies rules.
601
+ */
602
+ Policies: [
603
+ {
604
+ PolicyName: `${exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_TASK_ROLE_LOGICAL_ID}Policy`,
605
+ PolicyDocument: {
606
+ Version: '2012-10-17',
607
+ Statement: [
608
+ {
609
+ Effect: 'Allow',
610
+ Action: ['*'],
611
+ Resource: '*',
612
+ },
613
+ ],
614
+ },
615
+ },
616
+ ],
617
+ },
618
+ };
619
+ resources[exports.REPOSITORY_ECS_TASK_DEFINITION_LOGICAL_ID] = {
620
+ Type: 'AWS::ECS::TaskDefinition',
621
+ Properties: {
622
+ ContainerDefinitions: [
623
+ {
624
+ Environment: [
625
+ {
626
+ /**
627
+ * https://docs.aws.amazon.com/AmazonECS/latest/developerguide/container-metadata.html#enable-metadata
628
+ */
629
+ Name: 'ECS_ENABLE_CONTAINER_METADATA',
630
+ Value: 'true',
631
+ },
632
+ {
633
+ Name: 'CI',
634
+ Value: 'true',
635
+ },
636
+ ...taskEnvironment.map((te) => ({
637
+ Name: te.name,
638
+ Value: te.value,
639
+ })),
640
+ ],
641
+ Image: {
642
+ 'Fn::Sub': [
643
+ // eslint-disable-next-line no-template-curly-in-string
644
+ '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RepositoryECR}:latest',
645
+ {
646
+ RepositoryECR: { Ref: exports.ECR_REPOSITORY_LOGICAL_ID },
647
+ },
648
+ ],
649
+ },
650
+ LogConfiguration: {
651
+ LogDriver: 'awslogs',
652
+ Options: {
653
+ 'awslogs-group': {
654
+ Ref: exports.REPOSITORY_TASKS_ECS_CLUSTER_LOGS_LOG_GROUP_LOGICAL_ID,
655
+ },
656
+ 'awslogs-region': { Ref: 'AWS::Region' },
657
+ 'awslogs-stream-prefix': 'ecs',
658
+ },
659
+ },
660
+ Name: exports.REPOSITORY_ECS_TASK_CONTAINER_NAME,
661
+ },
662
+ ],
663
+ Cpu: cpu,
664
+ ExecutionRoleArn: {
665
+ 'Fn::GetAtt': [
666
+ exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_EXECUTION_ROLE_LOGICAL_ID,
667
+ 'Arn',
668
+ ],
669
+ },
670
+ Memory: memory,
671
+ NetworkMode: 'awsvpc',
672
+ RequiresCompatibilities: ['FARGATE'],
673
+ TaskRoleArn: {
674
+ 'Fn::GetAtt': [
675
+ exports.REPOSITORY_TASKS_ECS_TASK_DEFINITION_TASK_ROLE_LOGICAL_ID,
676
+ 'Arn',
677
+ ],
678
+ },
679
+ },
680
+ };
681
+ })();
682
+ /**
683
+ * Pipelines
684
+ */
685
+ if (pipelines.includes('main') || pipelines.includes('tag')) {
686
+ resources[exports.PIPELINES_ARTIFACT_STORE_S3_BUCKET_LOGICAL_ID] = {
687
+ Type: 'AWS::S3::Bucket',
688
+ Properties: {
689
+ LifecycleConfiguration: {
690
+ Rules: [
691
+ {
692
+ /**
693
+ * We won't use the artifacts forever.
694
+ */
695
+ ExpirationInDays: 7,
696
+ Status: 'Enabled',
697
+ },
698
+ ],
699
+ },
700
+ },
701
+ };
702
+ resources[exports.PIPELINES_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID] = {
703
+ Type: 'AWS::Lambda::Function',
704
+ Properties: {
705
+ Code: {
706
+ S3Bucket: s3.bucket,
707
+ S3Key: s3.key,
708
+ S3ObjectVersion: s3.versionId,
709
+ },
710
+ Environment: {
711
+ Variables: {
712
+ ...executeEcsTaskVariables,
713
+ },
714
+ },
715
+ Handler: 'index.pipelinesHandler',
716
+ MemorySize: 128,
717
+ Role: {
718
+ 'Fn::GetAtt': [exports.FUNCTION_IAM_ROLE_LOGICAL_ID, 'Arn'],
719
+ },
720
+ Runtime: 'nodejs14.x',
721
+ Timeout: 60,
722
+ },
723
+ };
724
+ resources[exports.PIPELINES_ROLE_LOGICAL_ID] = {
725
+ Type: 'AWS::IAM::Role',
726
+ Properties: {
727
+ AssumeRolePolicyDocument: {
728
+ Version: '2012-10-17',
729
+ Statement: [
730
+ {
731
+ Effect: 'Allow',
732
+ Principal: {
733
+ Service: 'codepipeline.amazonaws.com',
734
+ },
735
+ Action: 'sts:AssumeRole',
736
+ },
737
+ ],
738
+ },
739
+ ManagedPolicyArns: [],
740
+ Path: (0, utils_1.getIamPath)(),
741
+ Policies: [
742
+ {
743
+ PolicyName: `${exports.PIPELINES_ROLE_LOGICAL_ID}Policy`,
744
+ PolicyDocument: {
745
+ Version: '2012-10-17',
746
+ Statement: [
747
+ {
748
+ Effect: 'Allow',
749
+ Action: 'lambda:InvokeFunction',
750
+ Resource: [
751
+ {
752
+ 'Fn::GetAtt': [
753
+ exports.PIPELINES_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID,
754
+ 'Arn',
755
+ ],
756
+ },
757
+ ],
758
+ },
759
+ {
760
+ Effect: 'Allow',
761
+ Action: 's3:*',
762
+ Resource: [
763
+ {
764
+ 'Fn::GetAtt': [
765
+ exports.PIPELINES_ARTIFACT_STORE_S3_BUCKET_LOGICAL_ID,
766
+ 'Arn',
767
+ ],
768
+ },
769
+ {
770
+ 'Fn::Sub': `arn:aws:s3:::\${${exports.PIPELINES_ARTIFACT_STORE_S3_BUCKET_LOGICAL_ID}}/*`,
771
+ },
772
+ ],
773
+ },
774
+ {
775
+ Effect: 'Allow',
776
+ Action: 's3:*',
777
+ Resource: {
778
+ 'Fn::Sub': [
779
+ `arn:aws:s3:::\${BucketName}/${triggerPipelinesObjectKeyPrefix}*`,
780
+ {
781
+ BucketName: {
782
+ 'Fn::ImportValue': config_1.BASE_STACK_BUCKET_NAME_EXPORTED_NAME,
783
+ },
784
+ },
785
+ ],
786
+ },
787
+ },
788
+ {
789
+ Effect: 'Allow',
790
+ Action: ['s3:Get*', 's3:List*'],
791
+ Resource: {
792
+ 'Fn::Sub': [
793
+ `arn:aws:s3:::\${BucketName}`,
794
+ {
795
+ BucketName: {
796
+ 'Fn::ImportValue': config_1.BASE_STACK_BUCKET_NAME_EXPORTED_NAME,
797
+ },
798
+ },
799
+ ],
800
+ },
801
+ },
802
+ ],
803
+ },
804
+ },
805
+ ],
806
+ },
807
+ };
808
+ const getCodePipelinePipeline = (pipeline) => {
809
+ const pipelinePascalCase = (0, change_case_1.pascalCase)(pipeline);
810
+ const pipelineS3SourceOutputName = `Pipeline${pipelinePascalCase}S3SourceOutput`;
811
+ return {
812
+ Type: 'AWS::CodePipeline::Pipeline',
813
+ Properties: {
814
+ ArtifactStore: {
815
+ Location: { Ref: exports.PIPELINES_ARTIFACT_STORE_S3_BUCKET_LOGICAL_ID },
816
+ Type: 'S3',
817
+ },
818
+ RestartExecutionOnUpdate: false,
819
+ RoleArn: {
820
+ 'Fn::GetAtt': [exports.PIPELINES_ROLE_LOGICAL_ID, 'Arn'],
821
+ },
822
+ Stages: [
823
+ {
824
+ Actions: [
825
+ {
826
+ ActionTypeId: {
827
+ Category: 'Source',
828
+ Owner: 'AWS',
829
+ Provider: 'S3',
830
+ Version: 1,
831
+ },
832
+ Configuration: {
833
+ S3Bucket: {
834
+ 'Fn::ImportValue': config_1.BASE_STACK_BUCKET_NAME_EXPORTED_NAME,
835
+ },
836
+ S3ObjectKey: (0, getTriggerPipelineObjectKey_1.getTriggerPipelinesObjectKey)({
837
+ prefix: triggerPipelinesObjectKeyPrefix,
838
+ pipeline,
839
+ }),
840
+ },
841
+ Name: `Pipeline${pipelinePascalCase}S3SourceAction`,
842
+ OutputArtifacts: [
843
+ {
844
+ Name: pipelineS3SourceOutputName,
845
+ },
846
+ ],
847
+ },
848
+ ],
849
+ Name: `Pipeline${pipelinePascalCase}S3SourceStage`,
850
+ },
851
+ {
852
+ Actions: [
853
+ {
854
+ ActionTypeId: {
855
+ Category: 'Invoke',
856
+ Owner: 'AWS',
857
+ Provider: 'Lambda',
858
+ Version: 1,
859
+ },
860
+ Configuration: {
861
+ FunctionName: {
862
+ Ref: exports.PIPELINES_HANDLER_LAMBDA_FUNCTION_LOGICAL_ID,
863
+ },
864
+ UserParameters: (() => pipeline)(),
865
+ },
866
+ InputArtifacts: [
867
+ {
868
+ Name: pipelineS3SourceOutputName,
869
+ },
870
+ ],
871
+ Name: `Pipeline${pipelinePascalCase}RunECSTasksAction`,
872
+ },
873
+ {
874
+ ActionTypeId: {
875
+ Category: 'Approval',
876
+ Owner: 'AWS',
877
+ Provider: 'Manual',
878
+ Version: 1,
879
+ },
880
+ Name: config_2.PIPELINE_ECS_TASK_EXECUTION_MANUAL_APPROVAL_ACTION_NAME,
881
+ },
882
+ ],
883
+ Name: config_2.PIPELINE_ECS_TASK_EXECUTION_STAGE_NAME,
884
+ },
885
+ ],
886
+ },
887
+ };
888
+ };
889
+ if (pipelines.includes('main')) {
890
+ resources[exports.PIPELINES_MAIN_LOGICAL_ID] = getCodePipelinePipeline('main');
891
+ }
892
+ if (pipelines.includes('tag')) {
893
+ resources[exports.PIPELINES_TAG_LOGICAL_ID] = getCodePipelinePipeline('tag');
894
+ }
895
+ }
896
+ return {
897
+ AWSTemplateFormatVersion: '2010-09-09',
898
+ Transform: 'AWS::Serverless-2016-10-31',
899
+ Resources: resources,
900
+ Parameters: {
901
+ SSHKey: {
902
+ NoEcho: true,
903
+ Type: 'String',
904
+ },
905
+ SSHUrl: {
906
+ Type: 'String',
907
+ },
908
+ },
909
+ Outputs: {
910
+ [exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID]: {
911
+ Value: { Ref: exports.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID },
912
+ },
913
+ ApiV1Endpoint: {
914
+ Description: 'CICD API v1 stage endpoint.',
915
+ Value: {
916
+ 'Fn::Sub': `https://\${${exports.API_LOGICAL_ID}}.execute-api.\${AWS::Region}.amazonaws.com/v1/`,
917
+ },
918
+ },
919
+ },
920
+ };
921
+ };
922
+ exports.getCicdTemplate = getCicdTemplate;