UNPKG

35.4 kBYAMLView Raw
1AWSTemplateFormatVersion: '2010-09-09'
2Description: 'stack: {{stackName}} | deployed by Kes'
3Parameters:
4 CmrPassword:
5 Type: String
6 Description: 'Password used to publish CMR records. This is encrypted by Custom::Cumulus'
7 Default: ""
8 NoEcho: true
9 DockerPassword:
10 Type: String
11 Description: 'Password used to access a private docker repository (not required)'
12 Default: ""
13 NoEcho: true
14 DockerEmail:
15 Type: String
16 Description: 'Email used to login to a private docker repository (not required)'
17 Default: ""
18 NoEcho: true
19 LaunchpadPassphrase:
20 Type: String
21 Description: 'Passphrase of the Launchpad PIK certificate. This is encrypted by Custom::Cumulus'
22 Default: ""
23 NoEcho: true
24{{#if es.name}}
25 {{es.name}}DomainEndpoint:
26 Type: String
27 Description: 'ElasticSearch domain endpoint'
28 NoEcho: true
29{{/if}}
30{{#each dynamos}}
31 {{@key}}DynamoDBStreamArn:
32 Type: String
33 Description: 'DynamoDBStreamArn for {{@key}}'
34 NoEcho: true
35{{/each}}
36
37Resources:
38
39 #################################################
40 # BEGIN
41 #################################################
42
43
44{{#each nested_templates}}
45{{#ifEquals @key "WorkflowLambdaVersions"}}
46{{#ifEquals ../useWorkflowLambdaVersions true}}
47 {{@key}}NestedStack:
48 Type: "AWS::CloudFormation::Stack"
49 Properties:
50 Parameters:
51 {{#each ../workflowLambdas}}
52 {{@key}}LambdaFunction:
53 Ref: {{@key}}LambdaFunction
54 {{/each}}
55 TemplateURL: {{this.url}}
56{{/ifEquals}}
57{{/ifEquals}}
58{{#ifNotEquals @key "WorkflowLambdaVersions"}}
59{{#ifDeployApi @key ../deployDistributionApi}}
60 {{@key}}NestedStack:
61 Type: "AWS::CloudFormation::Stack"
62 Properties:
63 Parameters:
64 CmrPassword:
65 Fn::GetAtt:
66 - CumulusCustomResource
67 - CmrPassword
68 LaunchpadPassphrase:
69 Fn::GetAtt:
70 - CumulusCustomResource
71 - LaunchpadPassphrase
72 {{#if ../../es.name}}
73 ElasticSearchDomain:
74 Ref: {{../../es.name}}DomainEndpoint
75 {{/if}}
76 log2elasticsearchLambdaFunctionArn:
77 Fn::GetAtt:
78 - log2elasticsearchLambdaFunction
79 - Arn
80 {{#ifEquals @key "CumulusApiBackend"}}
81 # Only the backend API lambdas need these references.
82 EcsCluster:
83 Ref: CumulusECSCluster
84 AsyncOperationTaskDefinition:
85 Ref: AsyncOperationTaskDefinition
86 BulkDeleteLambdaFunctionArn:
87 Fn::GetAtt:
88 - BulkDeleteLambdaFunction
89 - Arn
90 CreateReconciliationReportLambdaFunctionArn:
91 Fn::GetAtt:
92 - CreateReconciliationReportLambdaFunction
93 - Arn
94 EmsIngestReportLambdaFunctionArn:
95 Fn::GetAtt:
96 - EmsIngestReportLambdaFunction
97 - Arn
98 EmsDistributionReportLambdaFunctionArn:
99 Fn::GetAtt:
100 - EmsDistributionReportLambdaFunction
101 - Arn
102 EmsProductMetadataReportLambdaFunctionArn:
103 Fn::GetAtt:
104 - EmsProductMetadataReportLambdaFunction
105 - Arn
106 messageConsumerLambdaFunctionArn:
107 Fn::GetAtt:
108 - messageConsumerLambdaFunction
109 - Arn
110 ScheduleSFLambdaFunctionArn:
111 Fn::GetAtt:
112 - ScheduleSFLambdaFunction
113 - Arn
114 KinesisInboundEventLoggerLambdaFunctionArn:
115 Fn::GetAtt:
116 - KinesisInboundEventLoggerLambdaFunction
117 - Arn
118 IndexFromDatabaseLambdaFunctionArn:
119 Fn::GetAtt:
120 - IndexFromDatabaseLambdaFunction
121 - Arn
122 BulkOperationLambdaFunctionArn:
123 Fn::GetAtt:
124 - BulkOperationLambdaFunction
125 - Arn
126 # The backend API needs a reference to the distributionRestApi so
127 # it can construct values for the DISTRIBUTION_REDIRECT_ENDPOINT
128 # environment variable. The /granules endpoint uses this variable.
129 {{#ifEquals ../../deployDistributionApi true}}
130 distributionRestApi:
131 Fn::GetAtt:
132 - CumulusApiDistributionNestedStack
133 - Outputs.distributionRestApiResource
134 {{/ifEquals}}
135 {{/ifEquals}}
136 {{# each ../../dynamos}}
137 {{@key}}DynamoDB: {{../../../prefix}}-{{@key}}
138 {{/each}}
139 {{# if ../../vpc }}
140 SecurityGroupId: {{../../vpc.securityGroup}}
141 {{/if}}
142 TemplateURL: {{../this.url}}
143{{/ifDeployApi}}
144{{/ifNotEquals}}
145{{/each}}
146
147 #################################################
148 # Nested CloudFormation Templates config BEGIN
149 #################################################
150
151 #################################################
152 # Cumulus Custom Resource BEGIN
153 #################################################
154 CumulusCustomResource:
155 Type: Custom::Cumulus
156 Properties:
157 ServiceToken:
158 Fn::GetAtt:
159 - CustomBootstrapLambdaFunction
160 - Arn
161 Cmr:
162 Password:
163 Ref: CmrPassword
164 Launchpad:
165 Passphrase:
166 Ref: LaunchpadPassphrase
167 {{# if es.name}}
168 ElasticSearch:
169 host:
170 Ref: {{es.name}}DomainEndpoint
171 version: {{es.elasticSearchMapping}}
172 {{/if}}
173 {{# if dynamos}}
174 DynamoDBTables:
175 {{#each dynamos}}
176 - name: {{../prefix}}-{{@key}}
177 pointInTime: {{this.pointInTime}}
178 {{/each}}
179 {{/if}}
180 Users:
181 table: {{prefix}}-UsersTable
182 records:
183 {{# each users}}
184 - username: {{username}}
185 password: OAuth
186 {{/each}}
187
188 #################################################
189 # Cumulus Custom Resource END
190 #################################################
191
192 #################################################
193
194 # SNS config BEGIN
195 #################################################
196{{#each sns}}
197 {{#if this.arn}}
198 {{#each this.subscriptions}}
199 # Subscriptions only
200 {{@../key}}{{@key}}Subscription:
201 Type: "AWS::SNS::Subscription"
202 Properties:
203 {{# if this.endpoint.function}}
204 Endpoint:
205 {{this.endpoint.function}}:
206 {{#each this.endpoint.array}}
207 - {{@this}}
208 {{/each}}
209 {{else}}
210 Endpoint: {{this.endpoint}}
211 {{/if}}
212 Protocol: {{this.protocol}}
213 TopicArn: {{../this.arn}}
214 {{/each}}
215 {{else}}
216 {{@key}}Sns:
217 Type: "AWS::SNS::Topic"
218 Properties:
219 DisplayName: {{../prefix}}-{{@key}}
220 Subscription:
221 {{#each this.subscriptions}}
222 {{# if this.endpoint.function}}
223 - Endpoint:
224 {{this.endpoint.function}}:
225 {{#each this.endpoint.array}}
226 - {{@this}}
227 {{/each}}
228 {{else}}
229 - Endpoint: {{this.endpoint}}
230 {{/if}}
231 Protocol: {{this.protocol}}
232 {{/each}}
233 {{/if}}
234
235 {{# each this.subscriptions}}
236 {{@../key}}{{@key}}SubscriptionPermission:
237 Type: AWS::Lambda::Permission
238 Properties:
239 {{# if this.endpoint.function}}
240 FunctionName:
241 {{this.endpoint.function}}:
242 {{#each this.endpoint.array}}
243 - {{@this}}
244 {{/each}}
245 {{else}}
246 FunctionName: {{this.endpoint}}
247 {{/if}}
248 Action: lambda:InvokeFunction
249 Principal: sns.amazonaws.com
250 SourceArn:
251 {{#if ../this.arn}}
252 {{../this.arn}}
253 {{else}}
254 Ref: {{@../key}}Sns
255 {{/if}}
256 {{/each}}
257
258{{/each}}
259 #################################################
260 # SNS config END
261 #################################################
262
263 #################################################
264 # SQS config BEGIN
265 #################################################
266{{#each sqs}}
267 {{@key}}SQS:
268 Type: AWS::SQS::Queue
269 Properties:
270 QueueName: {{../prefix}}-{{@key}}
271 ReceiveMessageWaitTimeSeconds: 20
272 {{#if this.retry}}
273 RedrivePolicy:
274 deadLetterTargetArn:
275 Fn::GetAtt:
276 - {{@key}}FailedSQS
277 - Arn
278 maxReceiveCount: {{this.retry}}
279 {{/if}}
280 VisibilityTimeout: {{this.visibilityTimeout}}
281
282{{#if this.retry}}
283 {{@key}}FailedSQS:
284 Type: AWS::SQS::Queue
285 Properties:
286 QueueName: {{../prefix}}-{{@key}}-failed
287
288{{/if}}
289
290{{# each this.consumer }}
291 {{@../key}}WatcherRule:
292 Type: AWS::Events::Rule
293 Properties:
294 ScheduleExpression: {{this.schedule}}
295 State: {{# if this.state}}{{this.state}}{{ else }}DISABLED{{/if}}
296 Targets:
297 - Id: {{@../key}}WatcherScheduler
298 Input:
299 Fn::Sub: '{"queueUrl": "${ {{@../key}}SQS}", "messageLimit": {{this.messageLimit}}, "timeLimit": 60 }'
300 Arn:
301 Fn::GetAtt:
302 - {{this.lambda}}LambdaFunction
303 - Arn
304
305 {{@../key}}InvokeLambdaPermission:
306 Type: AWS::Lambda::Permission
307 Properties:
308 FunctionName:
309 Fn::GetAtt:
310 - {{this.lambda}}LambdaFunction
311 - Arn
312 Action: lambda:InvokeFunction
313 Principal: events.amazonaws.com
314 SourceArn:
315 Fn::GetAtt:
316 - {{@../key}}WatcherRule
317 - Arn
318
319{{/each}}
320{{/each}}
321 #################################################
322 # SQS config END
323 #################################################
324
325 #################################################
326 # Step Functions config BEGIN
327 #################################################
328{{#each activities}}
329 {{name}}Activity:
330 Type: AWS::StepFunctions::Activity
331 Properties:
332 Name: {{../prefix}}-{{name}}-Activity
333{{/each}}
334
335{{#each stepFunctions}}
336 {{../prefixNoDash}}{{@key}}StateMachine:
337 Type: AWS::StepFunctions::StateMachine
338 Properties:
339 DefinitionString:
340 {{#ifEquals ../useWorkflowLambdaVersions true}}
341 Fn::Sub:
342 - |
343 {{{ToJson this}}}
344 -
345 {{#each ../workflowLambdas}}
346 {{@key}}LambdaAliasOutput:
347 Fn::GetAtt:
348 - WorkflowLambdaVersionsNestedStack
349 - Outputs.{{@key}}LambdaAliasOutput
350 {{/each}}
351 stackName: {{../stackName}}
352 {{/ifEquals}}
353 {{#ifNotEquals ../useWorkflowLambdaVersions true}}
354 Fn::Sub: |
355 {{{ToJson this}}}
356 {{/ifNotEquals}}
357 RoleArn: {{../iams.stepRoleArn}}
358
359{{/each}}
360 #################################################
361 # Step Functions config END
362 #################################################
363
364 #################################################
365 # CloudWatch RULE config BEGIN
366 #################################################
367
368{{# each rules }}
369 {{@key}}Rule:
370 Type: AWS::Events::Rule
371 {{# if this.stateMachines}}
372 DependsOn:
373 {{#each this.stateMachines}}
374 - {{this}}
375 {{/each}}
376 {{/if}}
377 Properties:
378 {{# if this.schedule}}
379 ScheduleExpression: {{this.schedule}}
380 {{/if}}
381 {{# if this.eventPattern}}
382 EventPattern:
383 Fn::Sub: |
384 {{{ToJson this.eventPattern}}}
385 {{/if}}
386 State: {{# if this.state}}{{this.state}}{{ else }}DISABLED{{/if}}
387 Targets:
388 {{# each this.targets}}
389 - Id: {{@../key}}WatcherScheduler
390 {{# if input}}
391 Input: '{{{ToJson this.input}}}'
392 {{/if}}
393 Arn:
394 Fn::GetAtt:
395 - {{lambda}}LambdaFunction
396 - Arn
397 {{/each}}
398
399 {{# each targets}}
400 {{@../key}}RuleLambdaPermission:
401 Type: AWS::Lambda::Permission
402 Properties:
403 FunctionName:
404 Fn::GetAtt:
405 - {{lambda}}LambdaFunction
406 - Arn
407 Action: lambda:InvokeFunction
408 Principal: events.amazonaws.com
409 SourceArn:
410 Fn::GetAtt:
411 - {{@../key}}Rule
412 - Arn
413 {{/each}}
414{{/each}}
415
416 #################################################
417 # CloudWatch RULE config END
418 #################################################
419
420{{# if dynamo2ElasticSearch}}
421 #################################################
422 # DynamoDB Event Source Mapping BEGIN
423 #################################################
424
425 {{#each dynamo2ElasticSearch.tables}}
426 {{this}}EventSourceMapping:
427 Type: AWS::Lambda::EventSourceMapping
428 Properties:
429 EventSourceArn:
430 Ref:
431 {{this}}DynamoDBStreamArn
432 FunctionName:
433 Ref: {{../dynamo2ElasticSearch.lambda}}LambdaFunction
434 BatchSize: {{../dynamo2ElasticSearch.batchSize}}
435 StartingPosition: {{../dynamo2ElasticSearch.startingPosition}}
436 {{/each}}
437
438 #################################################
439 # DynamoDB Event Source Mapping END
440 #################################################
441{{/if}}
442
443
444 #################################################
445 # Lambda config BEGIN
446 #################################################
447{{#each lambdas}}
448 {{@key}}LambdaFunction:
449 Type: AWS::Lambda::Function
450 Properties:
451 {{# if this.layers}}
452 Layers:
453 {{#each this.layers}}
454 - {{this}}
455 {{/each}}
456 {{/if}}
457 Code:
458 S3Bucket: {{this.bucket}}
459 S3Key: {{this.remote}}
460 FunctionName: {{../prefix}}-{{@key}}
461 Environment:
462 Variables:
463 stackName: {{../stackName}}
464 CMR_ENVIRONMENT: {{../cmr.cmrEnvironment}}
465 {{#if this.useElasticSearch }}
466 {{#if ../es.name}}
467 ES_HOST:
468 Ref: {{../es.name}}DomainEndpoint
469 {{/if}}
470 {{/if}}
471 {{#ifNotEquals this.useMessageAdapter true}}
472 {{#if this.envs.CUMULUS_MESSAGE_ADAPTER_DIR}}
473 {{else}}
474 CUMULUS_MESSAGE_ADAPTER_DIR: {{../cmaDir}}
475 {{/if}}
476 {{/ifNotEquals}}
477 {{#each this.tables}}
478 {{this}}: {{../../prefix}}-{{this}}
479 {{/each}}
480 {{# if this.useDistributionApi}}
481 {{# if ../api_distribution_url}}
482 DISTRIBUTION_ENDPOINT: {{../api_distribution_url}}
483 {{/if}}
484 {{#if ../deployDistributionApi}}
485 DISTRIBUTION_ENDPOINT:
486 Fn::GetAtt:
487 - CumulusApiDistributionNestedStack
488 - Outputs.distributionRestApiResourceUrl
489 {{/if}}
490 {{/if}}
491 {{#each this.envs}}
492 {{# if this.function}}
493 {{#if this.array}}
494 {{@key}}:
495 {{this.function}}:
496 {{#each this.array}}
497 - {{this}}
498 {{/each}}
499 {{/if}}
500 {{#if this.value}}
501 {{@key}}:
502 {{this.function}}: {{this.value}}
503 {{/if}}
504 {{else}}
505 {{@key}}: {{{this}}}
506 {{/if}}
507 {{/each}}
508 Handler: {{this.handler}}
509 MemorySize: {{this.memory}}
510 {{# if ../useXray}}
511 TracingConfig:
512 Mode: Active
513 {{/if}}
514{{# if this.apiRole }}
515 Role: {{../iams.lambdaApiGatewayRoleArn}}
516{{else if this.distributionRole}}
517 Role: {{../iams.distributionRoleArn}}
518{{else}}
519{{#ifEquals @key "executeMigrations"}}
520 Role: {{../iams.migrationRoleArn}}
521{{/ifEquals}}
522{{#ifNotEquals @key "executeMigrations"}}
523 Role: {{../iams.lambdaProcessingRoleArn}}
524{{/ifNotEquals}}
525{{/if}}
526 Runtime: {{# if this.runtime}}{{this.runtime}}{{else}}nodejs8.10{{/if}}
527 Timeout: {{this.timeout}}
528 {{# if this.deadletterqueue}}
529 DeadLetterConfig:
530 TargetArn:
531 Fn::GetAtt:
532 - {{this.deadletterqueue}}SQS
533 - Arn
534 {{/if}}
535 Tags:
536 - Key: Project
537 Value: {{../prefix}}
538
539 {{# if this.launchInVpc }}
540 {{# if ../vpc }}
541 VpcConfig:
542 SecurityGroupIds:
543 - {{../vpc.securityGroup}}
544 SubnetIds:
545 {{#each ../vpc.subnets}}
546 - {{this}}
547 {{/each}}
548 {{/if}}
549 {{/if}}
550
551{{# if this.apiGateway }}
552 {{@key}}LambdaPermissionApiGateway:
553 Type: AWS::Lambda::Permission
554 Properties:
555 Action: lambda:InvokeFunction
556 FunctionName:
557 Fn::GetAtt:
558 - {{@key}}LambdaFunction
559 - Arn
560 Principal: apigateway.amazonaws.com
561{{/if}}
562
563{{# if this.logToElasticSearch }}
564 {{@key}}LogSubscription:
565 Type: AWS::Logs::SubscriptionFilter
566 DependsOn:
567 - {{@key}}LogGroup
568 - log2elasticsearchLambdaPermissionLog
569 Properties:
570 DestinationArn:
571 Fn::GetAtt:
572 - log2elasticsearchLambdaFunction
573 - Arn
574 LogGroupName: '/aws/lambda/{{../prefix}}-{{@key}}'
575 FilterPattern: ""
576
577 {{@key}}LogGroup:
578 Type: AWS::Logs::LogGroup
579 Properties:
580 LogGroupName: '/aws/lambda/{{../prefix}}-{{@key}}'
581 RetentionInDays: 30
582{{/if}}
583
584{{#if this.logToSharedDestination }}
585 # Configure Lambda log subscription to shareLogDestination
586 {{@key}}LogSubscriptionToSharedDestination:
587 Type: AWS::Logs::SubscriptionFilter
588 DependsOn:
589 - {{@key}}LogGroup
590 Properties:
591 DestinationArn: "{{this.logToSharedDestination}}"
592 LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
593 FilterPattern: ""
594
595 {{@key}}LogGroup:
596 Type: AWS::Logs::LogGroup
597 Properties:
598 LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
599 RetentionInDays: 30
600{{/if}}
601
602
603 {{#ifEquals @key "ScheduleSF"}}
604 ## Generic lambda permission for custom rules
605 ## created in the dashboard
606 GenericLambdaPermission:
607 Type: AWS::Lambda::Permission
608 Properties:
609 FunctionName:
610 Fn::GetAtt:
611 - ScheduleSFLambdaFunction
612 - Arn
613 Action: lambda:InvokeFunction
614 Principal: events.amazonaws.com
615 {{/ifEquals}}
616
617{{/each}}
618
619 log2elasticsearchLambdaPermissionLog:
620 Type: AWS::Lambda::Permission
621 Properties:
622 Action: lambda:InvokeFunction
623 FunctionName:
624 Fn::GetAtt:
625 - log2elasticsearchLambdaFunction
626 - Arn
627 Principal:
628 Fn::Sub: 'logs.${AWS::Region}.amazonaws.com'
629
630 #################################################
631 # Lambda config END
632 #################################################
633
634 #################################################
635 # ECS config BEGIN
636 #################################################
637{{# if iams.instanceProfile}}
638 CumulusECSCluster:
639 Type: AWS::ECS::Cluster
640
641 CumulusContainerInstanceLaunch:
642 Type: AWS::AutoScaling::LaunchConfiguration
643 Properties:
644 {{# if vpc.subnets }}
645 AssociatePublicIpAddress: {{#if ecs.publicIp}}{{ecs.publicIp}}{{else}}false{{/if}}
646 {{/if}}
647 {{# if vpc.securityGroup}}
648 SecurityGroups:
649 - {{vpc.securityGroup}}
650 {{/if}}
651 {{# if ecs.efs.mount}}
652 - Fn::ImportValue:
653 "{{prefix}}-EFSSecurityGroup"
654 {{/if}}
655
656 ImageId: {{ecs.amiid}}
657
658 InstanceType: {{ecs.instanceType}}
659 IamInstanceProfile: {{iams.instanceProfile}}
660 BlockDeviceMappings:
661 - DeviceName: "/dev/xvdcz"
662 Ebs:
663 DeleteOnTermination: true
664 VolumeSize: {{ecs.volumeSize}}
665 {{# if ecs.keyPairName }}
666 KeyName: {{ ecs.keyPairName }}
667 {{/if}}
668 UserData:
669 Fn::Base64:
670 Fn::Sub:
671 - |
672 Content-Type: multipart/mixed; boundary="==BOUNDARY=="
673 MIME-Version: 1.0
674
675 --==BOUNDARY==
676 Content-Type: text/cloud-boothook; charset="us-ascii"
677
678 sed -i '/^\s*DOCKER_STORAGE_OPTIONS=/d' /etc/sysconfig/docker-storage
679 echo 'DOCKER_STORAGE_OPTIONS="--storage-driver {{ecs.docker.storageDriver}}"' >> /etc/sysconfig/docker-storage
680
681 {{#ifEquals ecs.docker.storageDriver "devicemapper"}}
682 sed -i '/^\s*OPTIONS=/d' /etc/sysconfig/docker
683 echo 'OPTIONS="--default-ulimit nofile=1024:4096 --storage-opt dm.basesize={{ecs.volumeSize}}G"' >> /etc/sysconfig/docker
684 {{/ifEquals}}
685
686 --==BOUNDARY==
687 Content-Type: text/x-shellscript; charset="us-ascii"
688
689 {{# if ecs.efs.mount }}
690 AZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
691
692 if ! rpm -q nfs-utils >/dev/null 2>&1; then
693 yum install -y nfs-utils
694 fi
695
696 mkdir -p {{ecs.efs.mount}}
697 mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${!AZ}.${EFSFileSystemId}.efs.${AWS::Region}.amazonaws.com:/ {{ecs.efs.mount}}
698 chmod 777 {{ecs.efs.mount}}
699
700 service docker restart
701 {{/if}}
702
703 cat <<'EOF' >> /etc/ecs/ecs.config
704 ECS_CLUSTER=${CumulusECSCluster}
705 ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=1m
706 ECS_CONTAINER_STOP_TIMEOUT={{ecs.container_stop_timeout}}
707 EOF
708
709 {{#ifEquals ecs.docker.registry "dockerhub"}}
710 echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config
711 echo 'ECS_ENGINE_AUTH_DATA={"https://index.docker.io/v1/":{"username":"{{ecs.docker.username}}","password": "${DockerPassword}","email":"${DockerEmail}"}}' >> /etc/ecs/ecs.config
712 {{/ifEquals}}
713
714 if ! which aws >/dev/null 2>&1; then
715 yum install -y jq unzip
716 curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
717 unzip awscli-bundle.zip
718 ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
719 rm -rf ./awscli-bundle awscli-bundle.zip
720 fi
721
722 aws s3 cp s3://{{bucket}}/{{stackName}}/deployment-staging/task-reaper.sh /usr/local/bin/task-reaper.sh
723 chmod +x /usr/local/bin/task-reaper.sh
724
725 cat <<'EOF' >> /etc/cron.d/task-reaper
726 PATH=/bin:/usr/local/bin
727 AWS_DEFAULT_REGION=${AWS::Region}
728 LIFECYCLE_HOOK_NAME={{stackName}}-ecs-termination-hook
729 * * * * * root /usr/local/bin/task-reaper.sh >> /var/log/task-reaper.log 2>&1
730 EOF
731
732 --==BOUNDARY==--
733 {{# if ecs.efs.mount }}
734 - EFSFileSystemId:
735 Fn::ImportValue: "{{prefix}}-EFSFileSystemId"
736 {{else}}
737 # This is necessary because, if we are not setting a mount,
738 # the Fn::Sub function still requires a variable map
739 - Nothing: nothing
740 {{/if}}
741
742 CumulusECSAutoScalingGroup:
743 Type: AWS::AutoScaling::AutoScalingGroup
744 UpdatePolicy:
745 AutoScalingRollingUpdate:
746 MinInstancesInService: '{{ ecs.minInstances }}'
747 Properties:
748 AvailabilityZones:
749{{# if ecs.availabilityZones }}
750 {{#each ecs.availabilityZones}}
751 - {{this}}
752 {{/each}}
753{{else if ecs.availabilityZone }}
754 - {{ecs.availabilityZone}}
755{{/if}}
756 {{# if vpc.subnets }}
757 VPCZoneIdentifier:
758 {{#each vpc.subnets}}
759 - {{this}}
760 {{/each}}
761 {{/if}}
762 LaunchConfigurationName:
763 Ref:
764 CumulusContainerInstanceLaunch
765 MinSize: '{{ ecs.minInstances }}'
766 DesiredCapacity: '{{ ecs.desiredInstances }}'
767 MaxSize: '{{ ecs.maxInstances }}'
768 Tags:
769 - Key: Name
770 Value: "{{prefix}}-cumulus-ecs"
771 PropagateAtLaunch: true
772
773 CumulusECSAutoScalingLifeCycleHook:
774 Type: AWS::AutoScaling::LifecycleHook
775 Properties:
776 LifecycleHookName: {{stackName}}-ecs-termination-hook
777 AutoScalingGroupName:
778 Ref:
779 CumulusECSAutoScalingGroup
780 DefaultResult: CONTINUE
781 HeartbeatTimeout: 150
782 LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING"
783
784 CumulusECSScaleOutPolicy:
785 Type: AWS::AutoScaling::ScalingPolicy
786 Properties:
787 AdjustmentType: PercentChangeInCapacity
788 AutoScalingGroupName:
789 Ref:
790 CumulusECSAutoScalingGroup
791 EstimatedInstanceWarmup: 180
792 MetricAggregationType: Average
793 PolicyType: StepScaling
794 StepAdjustments:
795 - MetricIntervalLowerBound: 0
796 ScalingAdjustment: {{ecs.clusterAutoscaling.scaleOutAdjustmentPercent}}
797
798 CumulusECSMemoryScaleOutAlarm:
799 Type: AWS::CloudWatch::Alarm
800 Properties:
801 ActionsEnabled: true
802 AlarmActions:
803 - Ref: CumulusECSScaleOutPolicy
804 ComparisonOperator: GreaterThanThreshold
805 DatapointsToAlarm: 1
806 Dimensions:
807 - Name: ClusterName
808 Value:
809 Ref:
810 CumulusECSCluster
811 EvaluationPeriods: 1
812 MetricName: MemoryReservation
813 Namespace: AWS/ECS
814 Period: 60
815 Statistic: Average
816 Threshold: {{ecs.clusterAutoscaling.scaleOutThresholdPercent}}
817 Unit: Percent
818
819 CumulusECSCPUScaleOutAlarm:
820 Type: AWS::CloudWatch::Alarm
821 Properties:
822 ActionsEnabled: true
823 AlarmActions:
824 - Ref: CumulusECSScaleOutPolicy
825 ComparisonOperator: GreaterThanThreshold
826 DatapointsToAlarm: 1
827 Dimensions:
828 - Name: ClusterName
829 Value:
830 Ref:
831 CumulusECSCluster
832 EvaluationPeriods: 1
833 MetricName: CPUReservation
834 Namespace: AWS/ECS
835 Period: 60
836 Statistic: Average
837 Threshold: {{ecs.clusterAutoscaling.scaleOutThresholdPercent}}
838 Unit: Percent
839
840 CumulusECSScaleInPolicy:
841 Type: AWS::AutoScaling::ScalingPolicy
842 Properties:
843 AdjustmentType: PercentChangeInCapacity
844 AutoScalingGroupName:
845 Ref:
846 CumulusECSAutoScalingGroup
847 MetricAggregationType: Average
848 PolicyType: StepScaling
849 StepAdjustments:
850 - MetricIntervalUpperBound: 0
851 ScalingAdjustment: {{ecs.clusterAutoscaling.scaleInAdjustmentPercent}}
852
853 CumulusECSMemoryScaleInAlarm:
854 Type: AWS::CloudWatch::Alarm
855 Properties:
856 ActionsEnabled: true
857 AlarmActions:
858 - Ref: CumulusECSScaleInPolicy
859 ComparisonOperator: LessThanThreshold
860 DatapointsToAlarm: 1
861 Dimensions:
862 - Name: ClusterName
863 Value:
864 Ref:
865 CumulusECSCluster
866 EvaluationPeriods: 1
867 MetricName: MemoryReservation
868 Namespace: AWS/ECS
869 Period: 60
870 Statistic: Average
871 Threshold: {{ecs.clusterAutoscaling.scaleInThresholdPercent}}
872 Unit: Percent
873
874 CumulusECSCPUScaleInAlarm:
875 Type: AWS::CloudWatch::Alarm
876 Properties:
877 ActionsEnabled: true
878 AlarmActions:
879 - Ref: CumulusECSScaleInPolicy
880 ComparisonOperator: LessThanThreshold
881 DatapointsToAlarm: 1
882 Dimensions:
883 - Name: ClusterName
884 Value:
885 Ref:
886 CumulusECSCluster
887 EvaluationPeriods: 1
888 MetricName: CPUReservation
889 Namespace: AWS/ECS
890 Period: 60
891 Statistic: Average
892 Threshold: {{ecs.clusterAutoscaling.scaleInThresholdPercent}}
893 Unit: Percent
894
895{{#each ecs.services}}
896 # adding TaskDefinition for Lambda/ECS services
897 {{@key}}TaskDefinition:
898 Type: AWS::ECS::TaskDefinition
899 Properties:
900 {{# if this.volumes}}
901 Volumes:
902 {{# each this.volumes}}
903 - Name: {{name}}
904 Host:
905 SourcePath: {{path}}
906 {{/each}}
907 {{/if}}
908 {{# if this.networkMode}}
909 NetworkMode: {{this.networkMode}}
910 {{/if}}
911 ContainerDefinitions:
912 - Name: {{@key}}
913 Cpu: {{#if this.cpu }}{{ this.cpu }}{{ else }}10{{/if}}
914 Essential: true
915 {{# if this.volumes}}
916 MountPoints:
917 {{# each this.volumes}}
918 - SourceVolume: {{name}}
919 ContainerPath: {{dst}}
920 {{/each}}
921
922 {{/if}}
923 {{# if this.privileged }}
924 Privileged: true
925 {{/if}}
926
927 Environment:
928 {{#each this.envs}}
929 {{# if this.function}}
930 {{#if this.array}}
931 - Name: {{@key}}
932 Value:
933 {{this.function}}:
934 {{#each this.array}}
935 - {{this}}
936 {{/each}}
937 {{/if}}
938 {{#if this.value}}
939 - Name: {{@key}}
940 Value:
941 {{this.function}}: {{this.value}}
942 {{/if}}
943 {{else}}
944 - Name: {{@key}}
945 Value: {{{this}}}
946 {{/if}}
947 {{/each}}
948 {{# if ../ecs.docker}}
949 Image: {{image}}
950 {{else}}
951 Image:
952 Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/{{image}}
953 {{/if}}
954 MemoryReservation: {{#if this.memory }}{{ this.memory }}{{ else }}256{{/if}}
955 {{# if this.commands }}
956 Command:
957 {{# each this.commands }}
958 {{# if this.function}}
959 - {{this.function}}: {{this.value}}
960 {{else}}
961 - {{{ @this }}}
962 {{/if}}
963 {{/each}}
964 {{/if}}
965 LogConfiguration:
966 LogDriver: awslogs
967 Options:
968 awslogs-group:
969 Ref: {{@key}}EcsLogs
970 awslogs-region:
971 Fn::Sub: ${AWS::Region}
972
973 {{@key}}EcsLogs:
974 Type: AWS::Logs::LogGroup
975 Properties:
976 LogGroupName: {{../prefix}}-{{@key}}EcsLogs
977 RetentionInDays: 30
978
979 {{@key}}EcsLogSubscription:
980 Type: AWS::Logs::SubscriptionFilter
981 DependsOn:
982 - {{@key}}EcsLogs
983 - log2elasticsearchLambdaPermissionLog
984 Properties:
985 DestinationArn:
986 Fn::GetAtt:
987 - log2elasticsearchLambdaFunction
988 - Arn
989 LogGroupName: {{../prefix}}-{{@key}}EcsLogs
990 FilterPattern: ""
991
992 {{@key}}ECSService:
993 Type: AWS::ECS::Service
994 DependsOn:
995 - CumulusECSAutoScalingGroup
996 Properties:
997 Cluster:
998 Ref: CumulusECSCluster
999 DesiredCount: {{# if this.count}}{{this.count}}{{ else }}0{{/if}}
1000 TaskDefinition:
1001 Ref: {{@key}}TaskDefinition
1002 DeploymentConfiguration:
1003 MaximumPercent: 100
1004 MinimumHealthyPercent: 0
1005
1006 {{@key}}ECSServiceTaskCountLowAlarm:
1007 Type: AWS::CloudWatch::Alarm
1008 Properties:
1009 AlarmDescription: There are less tasks running than the desired
1010 AlarmName: {{../prefix}}-{{@key}}-TaskCountLowAlarm
1011 ComparisonOperator: LessThanThreshold
1012 EvaluationPeriods: 1
1013 MetricName: MemoryUtilization
1014 Statistic: SampleCount
1015 Threshold: {{# if this.count}}{{this.count}}{{ else }} 0 {{/if}}
1016 Period: 60
1017 Namespace: AWS/ECS
1018 Dimensions:
1019 - Name: ClusterName
1020 Value:
1021 Ref: CumulusECSCluster
1022 - Name: ServiceName
1023 Value:
1024 Fn::GetAtt:
1025 - {{@key}}ECSService
1026 - Name
1027
1028 {{# if this.alarms}}
1029 # the service has cumstom alarms
1030 {{# each this.alarms}}
1031 {{@../key}}{{@key}}Alarm:
1032 Type: AWS::CloudWatch::Alarm
1033 Properties:
1034 {{#if alarm_description}}
1035 AlarmDescription: {{ alarm_description }}
1036 {{/if}}
1037 AlarmName: {{../../prefix}}-{{@../key}}-{{@key}}Alarm
1038 ComparisonOperator: {{ comparison_operator }}
1039 EvaluationPeriods: {{#if evaluation_periods }}{{ evaluation_periods }}{{ else }}5{{/if}}
1040 MetricName: {{ metric }}
1041 Statistic: {{#if statistic }}{{ statistic }}{{ else }}Average{{/if}}
1042 Threshold: {{ threshold }}
1043 Period: {{#if period }}{{ period }}{{ else }}60{{/if}}
1044 Namespace: AWS/ECS
1045 Dimensions:
1046 - Name: ClusterName
1047 Value:
1048 Ref: CumulusECSCluster
1049 - Name: ServiceName
1050 Value:
1051 Fn::GetAtt:
1052 - {{@../key}}ECSService
1053 - Name
1054 {{/each}}
1055 {{/if}}
1056
1057{{/each}}
1058
1059{{#each ecs.tasks}}
1060 # adding TaskDefinition for Lambda/ECS tasks
1061 {{@key}}TaskDefinition:
1062 Type: AWS::ECS::TaskDefinition
1063 Properties:
1064 {{# if this.volumes}}
1065 Volumes:
1066 {{# each this.volumes}}
1067 - Name: {{name}}
1068 Host:
1069 SourcePath: {{path}}
1070 {{/each}}
1071 {{/if}}
1072 {{# if this.networkMode}}
1073 NetworkMode: {{this.networkMode}}
1074 {{/if}}
1075 ContainerDefinitions:
1076 - Name: {{@key}}
1077 Cpu: {{#if this.cpu }}{{ this.cpu }}{{ else }}10{{/if}}
1078 Essential: true
1079 {{# if this.volumes}}
1080 MountPoints:
1081 {{# each this.volumes}}
1082 - SourceVolume: {{name}}
1083 ContainerPath: {{dst}}
1084 {{/each}}
1085
1086 {{/if}}
1087 {{# if this.privileged }}
1088 Privileged: true
1089 {{/if}}
1090
1091 Environment:
1092 {{#each this.envs}}
1093 {{# if this.function}}
1094 {{#if this.array}}
1095 - Name: {{@key}}
1096 Value:
1097 {{this.function}}:
1098 {{#each this.array}}
1099 - {{this}}
1100 {{/each}}
1101 {{/if}}
1102 {{#if this.value}}
1103 - Name: {{@key}}
1104 Value:
1105 {{this.function}}: {{this.value}}
1106 {{/if}}
1107 {{else}}
1108 - Name: {{@key}}
1109 Value: {{{this}}}
1110 {{/if}}
1111 {{/each}}
1112 {{# if ../ecs.docker}}
1113 Image: {{image}}
1114 {{else}}
1115 Image:
1116 Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/{{image}}
1117 {{/if}}
1118 MemoryReservation: {{#if this.memory }}{{ this.memory }}{{ else }}256{{/if}}
1119 {{# if this.commands }}
1120 Command:
1121 {{# each this.commands }}
1122 {{# if this.function}}
1123 - {{this.function}}: {{this.value}}
1124 {{else}}
1125 - {{{ @this }}}
1126 {{/if}}
1127 {{/each}}
1128 {{/if}}
1129 LogConfiguration:
1130 LogDriver: awslogs
1131 Options:
1132 awslogs-group:
1133 Ref: {{@key}}EcsLogs
1134 awslogs-region:
1135 Fn::Sub: ${AWS::Region}
1136
1137 {{@key}}EcsLogs:
1138 Type: AWS::Logs::LogGroup
1139 Properties:
1140 LogGroupName: {{../prefix}}-{{@key}}EcsLogs
1141 RetentionInDays: 30
1142
1143 {{@key}}EcsLogSubscription:
1144 Type: AWS::Logs::SubscriptionFilter
1145 DependsOn:
1146 - {{@key}}EcsLogs
1147 - log2elasticsearchLambdaPermissionLog
1148 Properties:
1149 DestinationArn:
1150 Fn::GetAtt:
1151 - log2elasticsearchLambdaFunction
1152 - Arn
1153 LogGroupName: {{../prefix}}-{{@key}}EcsLogs
1154 FilterPattern: ""
1155{{/each}}
1156{{/if}}
1157 #################################################
1158 # ECS config END
1159 #################################################
1160
1161 #################################################
1162 # CloudWatch Dashboard BEGIN
1163 #################################################
1164 CumulusCloudWatchDashboard:
1165 Type: AWS::CloudWatch::Dashboard
1166 Properties:
1167 DashboardName: {{prefix}}-CloudWatch-Dashboard
1168 DashboardBody: '{{#buildCWDashboard dashboard ecs es prefix}}{{/buildCWDashboard}}'
1169 #################################################
1170 # CloudWatch Dashboard END
1171 #################################################
1172
1173Outputs:
1174
1175 Api:
1176 {{# if api_backend_url}}
1177 Value: {{api_backend_url}}
1178 {{else}}
1179 Value:
1180 Fn::GetAtt:
1181 - CumulusApiBackendNestedStack
1182 - Outputs.backendRestApiResourceUrl
1183 {{/if}}
1184
1185 {{# if api_distribution_url}}
1186 Distribution:
1187 Value: {{api_distribution_url}}
1188 {{/if}}
1189 {{#if deployDistributionApi}}
1190 Distribution:
1191 Value:
1192 Fn::GetAtt:
1193 - CumulusApiDistributionNestedStack
1194 - Outputs.distributionRestApiResourceUrl
1195 {{/if}}
1196
1197 ApiId:
1198 Value:
1199 Fn::GetAtt:
1200 - CumulusApiBackendNestedStack
1201 - Outputs.backendRestApiResource
1202
1203 {{#if deployDistributionApi}}
1204 DistributionId:
1205 Value:
1206 Fn::GetAtt:
1207 - CumulusApiDistributionNestedStack
1208 - Outputs.distributionRestApiResource
1209 {{/if}}
1210
1211 ApiStage:
1212 Value: {{apiStage}}
1213
1214{{#each stepFunctions}}
1215 {{@key}}StateMachine:
1216 Value:
1217 Ref: {{../prefixNoDash}}{{@key}}StateMachine
1218{{/each}}
1219
1220{{#each sqs}}
1221 {{@key}}SQSOutput:
1222 Value:
1223 Ref: {{@key}}SQS
1224{{/each}}
1225
1226{{#each sns}}
1227 {{#if this.arn}}
1228 {{@key}}:
1229 Value: {{this.arn}}
1230 {{else}}
1231 {{@key}}SnsArn:
1232 Value:
1233 Ref: {{@key}}Sns
1234 {{/if}}
1235{{/each}}
1236
1237 EncryptedCmrPassword:
1238 Value:
1239 Fn::GetAtt:
1240 - CumulusCustomResource
1241 - CmrPassword
1242 EncryptedLaunchpadPassphrase:
1243 Value:
1244 Fn::GetAtt:
1245 - CumulusCustomResource
1246 - LaunchpadPassphrase