UNPKG

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