@cumulus/deployment
Version:
Deployment templates for cumulus
1,247 lines (1,155 loc) • 35.4 kB
YAML
AWSTemplateFormatVersion: '2010-09-09'
Description: 'stack: {{stackName}} | deployed by Kes'
Parameters:
CmrPassword:
Type: String
Description: 'Password used to publish CMR records. This is encrypted by Custom::Cumulus'
Default: ""
NoEcho: true
DockerPassword:
Type: String
Description: 'Password used to access a private docker repository (not required)'
Default: ""
NoEcho: true
DockerEmail:
Type: String
Description: 'Email used to login to a private docker repository (not required)'
Default: ""
NoEcho: true
LaunchpadPassphrase:
Type: String
Description: 'Passphrase of the Launchpad PIK certificate. This is encrypted by Custom::Cumulus'
Default: ""
NoEcho: true
{{#if es.name}}
{{es.name}}DomainEndpoint:
Type: String
Description: 'ElasticSearch domain endpoint'
NoEcho: true
{{/if}}
{{#each dynamos}}
{{@key}}DynamoDBStreamArn:
Type: String
Description: 'DynamoDBStreamArn for {{@key}}'
NoEcho: true
{{/each}}
Resources:
#################################################
# BEGIN
#################################################
{{#each nested_templates}}
{{#ifEquals @key "WorkflowLambdaVersions"}}
{{#ifEquals ../useWorkflowLambdaVersions true}}
{{@key}}NestedStack:
Type: "AWS::CloudFormation::Stack"
Properties:
Parameters:
{{#each ../workflowLambdas}}
{{@key}}LambdaFunction:
Ref: {{@key}}LambdaFunction
{{/each}}
TemplateURL: {{this.url}}
{{/ifEquals}}
{{/ifEquals}}
{{#ifNotEquals @key "WorkflowLambdaVersions"}}
{{#ifDeployApi @key ../deployDistributionApi}}
{{@key}}NestedStack:
Type: "AWS::CloudFormation::Stack"
Properties:
Parameters:
CmrPassword:
Fn::GetAtt:
- CumulusCustomResource
- CmrPassword
LaunchpadPassphrase:
Fn::GetAtt:
- CumulusCustomResource
- LaunchpadPassphrase
{{#if ../../es.name}}
ElasticSearchDomain:
Ref: {{../../es.name}}DomainEndpoint
{{/if}}
log2elasticsearchLambdaFunctionArn:
Fn::GetAtt:
- log2elasticsearchLambdaFunction
- Arn
{{#ifEquals @key "CumulusApiBackend"}}
# Only the backend API lambdas need these references.
EcsCluster:
Ref: CumulusECSCluster
AsyncOperationTaskDefinition:
Ref: AsyncOperationTaskDefinition
BulkDeleteLambdaFunctionArn:
Fn::GetAtt:
- BulkDeleteLambdaFunction
- Arn
CreateReconciliationReportLambdaFunctionArn:
Fn::GetAtt:
- CreateReconciliationReportLambdaFunction
- Arn
EmsIngestReportLambdaFunctionArn:
Fn::GetAtt:
- EmsIngestReportLambdaFunction
- Arn
EmsDistributionReportLambdaFunctionArn:
Fn::GetAtt:
- EmsDistributionReportLambdaFunction
- Arn
EmsProductMetadataReportLambdaFunctionArn:
Fn::GetAtt:
- EmsProductMetadataReportLambdaFunction
- Arn
messageConsumerLambdaFunctionArn:
Fn::GetAtt:
- messageConsumerLambdaFunction
- Arn
ScheduleSFLambdaFunctionArn:
Fn::GetAtt:
- ScheduleSFLambdaFunction
- Arn
KinesisInboundEventLoggerLambdaFunctionArn:
Fn::GetAtt:
- KinesisInboundEventLoggerLambdaFunction
- Arn
IndexFromDatabaseLambdaFunctionArn:
Fn::GetAtt:
- IndexFromDatabaseLambdaFunction
- Arn
BulkOperationLambdaFunctionArn:
Fn::GetAtt:
- BulkOperationLambdaFunction
- Arn
# The backend API needs a reference to the distributionRestApi so
# it can construct values for the DISTRIBUTION_REDIRECT_ENDPOINT
# environment variable. The /granules endpoint uses this variable.
{{#ifEquals ../../deployDistributionApi true}}
distributionRestApi:
Fn::GetAtt:
- CumulusApiDistributionNestedStack
- Outputs.distributionRestApiResource
{{/ifEquals}}
{{/ifEquals}}
{{# each ../../dynamos}}
{{@key}}DynamoDB: {{../../../prefix}}-{{@key}}
{{/each}}
{{# if ../../vpc }}
SecurityGroupId: {{../../vpc.securityGroup}}
{{/if}}
TemplateURL: {{../this.url}}
{{/ifDeployApi}}
{{/ifNotEquals}}
{{/each}}
#################################################
# Nested CloudFormation Templates config BEGIN
#################################################
#################################################
# Cumulus Custom Resource BEGIN
#################################################
CumulusCustomResource:
Type: Custom::Cumulus
Properties:
ServiceToken:
Fn::GetAtt:
- CustomBootstrapLambdaFunction
- Arn
Cmr:
Password:
Ref: CmrPassword
Launchpad:
Passphrase:
Ref: LaunchpadPassphrase
{{# if es.name}}
ElasticSearch:
host:
Ref: {{es.name}}DomainEndpoint
version: {{es.elasticSearchMapping}}
{{/if}}
{{# if dynamos}}
DynamoDBTables:
{{#each dynamos}}
- name: {{../prefix}}-{{@key}}
pointInTime: {{this.pointInTime}}
{{/each}}
{{/if}}
Users:
table: {{prefix}}-UsersTable
records:
{{# each users}}
- username: {{username}}
password: OAuth
{{/each}}
#################################################
# Cumulus Custom Resource END
#################################################
#################################################
# SNS config BEGIN
#################################################
{{#each sns}}
{{#if this.arn}}
{{#each this.subscriptions}}
# Subscriptions only
{{@../key}}{{@key}}Subscription:
Type: "AWS::SNS::Subscription"
Properties:
{{# if this.endpoint.function}}
Endpoint:
{{this.endpoint.function}}:
{{#each this.endpoint.array}}
- {{@this}}
{{/each}}
{{else}}
Endpoint: {{this.endpoint}}
{{/if}}
Protocol: {{this.protocol}}
TopicArn: {{../this.arn}}
{{/each}}
{{else}}
{{@key}}Sns:
Type: "AWS::SNS::Topic"
Properties:
DisplayName: {{../prefix}}-{{@key}}
Subscription:
{{#each this.subscriptions}}
{{# if this.endpoint.function}}
- Endpoint:
{{this.endpoint.function}}:
{{#each this.endpoint.array}}
- {{@this}}
{{/each}}
{{else}}
- Endpoint: {{this.endpoint}}
{{/if}}
Protocol: {{this.protocol}}
{{/each}}
{{/if}}
{{# each this.subscriptions}}
{{@../key}}{{@key}}SubscriptionPermission:
Type: AWS::Lambda::Permission
Properties:
{{# if this.endpoint.function}}
FunctionName:
{{this.endpoint.function}}:
{{#each this.endpoint.array}}
- {{@this}}
{{/each}}
{{else}}
FunctionName: {{this.endpoint}}
{{/if}}
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn:
{{#if ../this.arn}}
{{../this.arn}}
{{else}}
Ref: {{@../key}}Sns
{{/if}}
{{/each}}
{{/each}}
#################################################
# SNS config END
#################################################
#################################################
# SQS config BEGIN
#################################################
{{#each sqs}}
{{@key}}SQS:
Type: AWS::SQS::Queue
Properties:
QueueName: {{../prefix}}-{{@key}}
ReceiveMessageWaitTimeSeconds: 20
{{#if this.retry}}
RedrivePolicy:
deadLetterTargetArn:
Fn::GetAtt:
- {{@key}}FailedSQS
- Arn
maxReceiveCount: {{this.retry}}
{{/if}}
VisibilityTimeout: {{this.visibilityTimeout}}
{{#if this.retry}}
{{@key}}FailedSQS:
Type: AWS::SQS::Queue
Properties:
QueueName: {{../prefix}}-{{@key}}-failed
{{/if}}
{{# each this.consumer }}
{{@../key}}WatcherRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: {{this.schedule}}
State: {{# if this.state}}{{this.state}}{{ else }}DISABLED{{/if}}
Targets:
- Id: {{@../key}}WatcherScheduler
Input:
Fn::Sub: '{"queueUrl": "${ {{@../key}}SQS}", "messageLimit": {{this.messageLimit}}, "timeLimit": 60 }'
Arn:
Fn::GetAtt:
- {{this.lambda}}LambdaFunction
- Arn
{{@../key}}InvokeLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt:
- {{this.lambda}}LambdaFunction
- Arn
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn:
Fn::GetAtt:
- {{@../key}}WatcherRule
- Arn
{{/each}}
{{/each}}
#################################################
# SQS config END
#################################################
#################################################
# Step Functions config BEGIN
#################################################
{{#each activities}}
{{name}}Activity:
Type: AWS::StepFunctions::Activity
Properties:
Name: {{../prefix}}-{{name}}-Activity
{{/each}}
{{#each stepFunctions}}
{{../prefixNoDash}}{{@key}}StateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
DefinitionString:
{{#ifEquals ../useWorkflowLambdaVersions true}}
Fn::Sub:
- |
{{{ToJson this}}}
-
{{#each ../workflowLambdas}}
{{@key}}LambdaAliasOutput:
Fn::GetAtt:
- WorkflowLambdaVersionsNestedStack
- Outputs.{{@key}}LambdaAliasOutput
{{/each}}
stackName: {{../stackName}}
{{/ifEquals}}
{{#ifNotEquals ../useWorkflowLambdaVersions true}}
Fn::Sub: |
{{{ToJson this}}}
{{/ifNotEquals}}
RoleArn: {{../iams.stepRoleArn}}
{{/each}}
#################################################
# Step Functions config END
#################################################
#################################################
# CloudWatch RULE config BEGIN
#################################################
{{# each rules }}
{{@key}}Rule:
Type: AWS::Events::Rule
{{# if this.stateMachines}}
DependsOn:
{{#each this.stateMachines}}
- {{this}}
{{/each}}
{{/if}}
Properties:
{{# if this.schedule}}
ScheduleExpression: {{this.schedule}}
{{/if}}
{{# if this.eventPattern}}
EventPattern:
Fn::Sub: |
{{{ToJson this.eventPattern}}}
{{/if}}
State: {{# if this.state}}{{this.state}}{{ else }}DISABLED{{/if}}
Targets:
{{# each this.targets}}
- Id: {{@../key}}WatcherScheduler
{{# if input}}
Input: '{{{ToJson this.input}}}'
{{/if}}
Arn:
Fn::GetAtt:
- {{lambda}}LambdaFunction
- Arn
{{/each}}
{{# each targets}}
{{@../key}}RuleLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt:
- {{lambda}}LambdaFunction
- Arn
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn:
Fn::GetAtt:
- {{@../key}}Rule
- Arn
{{/each}}
{{/each}}
#################################################
# CloudWatch RULE config END
#################################################
{{# if dynamo2ElasticSearch}}
#################################################
# DynamoDB Event Source Mapping BEGIN
#################################################
{{#each dynamo2ElasticSearch.tables}}
{{this}}EventSourceMapping:
Type: AWS::Lambda::EventSourceMapping
Properties:
EventSourceArn:
Ref:
{{this}}DynamoDBStreamArn
FunctionName:
Ref: {{../dynamo2ElasticSearch.lambda}}LambdaFunction
BatchSize: {{../dynamo2ElasticSearch.batchSize}}
StartingPosition: {{../dynamo2ElasticSearch.startingPosition}}
{{/each}}
#################################################
# DynamoDB Event Source Mapping END
#################################################
{{/if}}
#################################################
# Lambda config BEGIN
#################################################
{{#each lambdas}}
{{@key}}LambdaFunction:
Type: AWS::Lambda::Function
Properties:
{{# if this.layers}}
Layers:
{{#each this.layers}}
- {{this}}
{{/each}}
{{/if}}
Code:
S3Bucket: {{this.bucket}}
S3Key: {{this.remote}}
FunctionName: {{../prefix}}-{{@key}}
Environment:
Variables:
stackName: {{../stackName}}
CMR_ENVIRONMENT: {{../cmr.cmrEnvironment}}
{{#if this.useElasticSearch }}
{{#if ../es.name}}
ES_HOST:
Ref: {{../es.name}}DomainEndpoint
{{/if}}
{{/if}}
{{#ifNotEquals this.useMessageAdapter true}}
{{#if this.envs.CUMULUS_MESSAGE_ADAPTER_DIR}}
{{else}}
CUMULUS_MESSAGE_ADAPTER_DIR: {{../cmaDir}}
{{/if}}
{{/ifNotEquals}}
{{#each this.tables}}
{{this}}: {{../../prefix}}-{{this}}
{{/each}}
{{# if this.useDistributionApi}}
{{# if ../api_distribution_url}}
DISTRIBUTION_ENDPOINT: {{../api_distribution_url}}
{{/if}}
{{#if ../deployDistributionApi}}
DISTRIBUTION_ENDPOINT:
Fn::GetAtt:
- CumulusApiDistributionNestedStack
- Outputs.distributionRestApiResourceUrl
{{/if}}
{{/if}}
{{#each this.envs}}
{{# if this.function}}
{{#if this.array}}
{{@key}}:
{{this.function}}:
{{#each this.array}}
- {{this}}
{{/each}}
{{/if}}
{{#if this.value}}
{{@key}}:
{{this.function}}: {{this.value}}
{{/if}}
{{else}}
{{@key}}: {{{this}}}
{{/if}}
{{/each}}
Handler: {{this.handler}}
MemorySize: {{this.memory}}
{{# if ../useXray}}
TracingConfig:
Mode: Active
{{/if}}
{{# if this.apiRole }}
Role: {{../iams.lambdaApiGatewayRoleArn}}
{{else if this.distributionRole}}
Role: {{../iams.distributionRoleArn}}
{{else}}
{{#ifEquals @key "executeMigrations"}}
Role: {{../iams.migrationRoleArn}}
{{/ifEquals}}
{{#ifNotEquals @key "executeMigrations"}}
Role: {{../iams.lambdaProcessingRoleArn}}
{{/ifNotEquals}}
{{/if}}
Runtime: {{# if this.runtime}}{{this.runtime}}{{else}}nodejs8.10{{/if}}
Timeout: {{this.timeout}}
{{# if this.deadletterqueue}}
DeadLetterConfig:
TargetArn:
Fn::GetAtt:
- {{this.deadletterqueue}}SQS
- Arn
{{/if}}
Tags:
- Key: Project
Value: {{../prefix}}
{{# if this.launchInVpc }}
{{# if ../vpc }}
VpcConfig:
SecurityGroupIds:
- {{../vpc.securityGroup}}
SubnetIds:
{{#each ../vpc.subnets}}
- {{this}}
{{/each}}
{{/if}}
{{/if}}
{{# if this.apiGateway }}
{{@key}}LambdaPermissionApiGateway:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName:
Fn::GetAtt:
- {{@key}}LambdaFunction
- Arn
Principal: apigateway.amazonaws.com
{{/if}}
{{# if this.logToElasticSearch }}
{{@key}}LogSubscription:
Type: AWS::Logs::SubscriptionFilter
DependsOn:
- {{@key}}LogGroup
- log2elasticsearchLambdaPermissionLog
Properties:
DestinationArn:
Fn::GetAtt:
- log2elasticsearchLambdaFunction
- Arn
LogGroupName: '/aws/lambda/{{../prefix}}-{{@key}}'
FilterPattern: ""
{{@key}}LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: '/aws/lambda/{{../prefix}}-{{@key}}'
RetentionInDays: 30
{{/if}}
{{#if this.logToSharedDestination }}
# Configure Lambda log subscription to shareLogDestination
{{@key}}LogSubscriptionToSharedDestination:
Type: AWS::Logs::SubscriptionFilter
DependsOn:
- {{@key}}LogGroup
Properties:
DestinationArn: "{{this.logToSharedDestination}}"
LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
FilterPattern: ""
{{@key}}LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
RetentionInDays: 30
{{/if}}
{{#ifEquals @key "ScheduleSF"}}
## Generic lambda permission for custom rules
## created in the dashboard
GenericLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt:
- ScheduleSFLambdaFunction
- Arn
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
{{/ifEquals}}
{{/each}}
log2elasticsearchLambdaPermissionLog:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName:
Fn::GetAtt:
- log2elasticsearchLambdaFunction
- Arn
Principal:
Fn::Sub: 'logs.${AWS::Region}.amazonaws.com'
#################################################
# Lambda config END
#################################################
#################################################
# ECS config BEGIN
#################################################
{{# if iams.instanceProfile}}
CumulusECSCluster:
Type: AWS::ECS::Cluster
CumulusContainerInstanceLaunch:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
{{# if vpc.subnets }}
AssociatePublicIpAddress: {{#if ecs.publicIp}}{{ecs.publicIp}}{{else}}false{{/if}}
{{/if}}
{{# if vpc.securityGroup}}
SecurityGroups:
- {{vpc.securityGroup}}
{{/if}}
{{# if ecs.efs.mount}}
- Fn::ImportValue:
"{{prefix}}-EFSSecurityGroup"
{{/if}}
ImageId: {{ecs.amiid}}
InstanceType: {{ecs.instanceType}}
IamInstanceProfile: {{iams.instanceProfile}}
BlockDeviceMappings:
- DeviceName: "/dev/xvdcz"
Ebs:
DeleteOnTermination: true
VolumeSize: {{ecs.volumeSize}}
{{# if ecs.keyPairName }}
KeyName: {{ ecs.keyPairName }}
{{/if}}
UserData:
Fn::Base64:
Fn::Sub:
- |
Content-Type: multipart/mixed; boundary="==BOUNDARY=="
MIME-Version: 1.0
--==BOUNDARY==
Content-Type: text/cloud-boothook; charset="us-ascii"
sed -i '/^\s*DOCKER_STORAGE_OPTIONS=/d' /etc/sysconfig/docker-storage
echo 'DOCKER_STORAGE_OPTIONS="--storage-driver {{ecs.docker.storageDriver}}"' >> /etc/sysconfig/docker-storage
{{#ifEquals ecs.docker.storageDriver "devicemapper"}}
sed -i '/^\s*OPTIONS=/d' /etc/sysconfig/docker
echo 'OPTIONS="--default-ulimit nofile=1024:4096 --storage-opt dm.basesize={{ecs.volumeSize}}G"' >> /etc/sysconfig/docker
{{/ifEquals}}
--==BOUNDARY==
Content-Type: text/x-shellscript; charset="us-ascii"
{{# if ecs.efs.mount }}
AZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
if ! rpm -q nfs-utils >/dev/null 2>&1; then
yum install -y nfs-utils
fi
mkdir -p {{ecs.efs.mount}}
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}}
chmod 777 {{ecs.efs.mount}}
service docker restart
{{/if}}
cat <<'EOF' >> /etc/ecs/ecs.config
ECS_CLUSTER=${CumulusECSCluster}
ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=1m
ECS_CONTAINER_STOP_TIMEOUT={{ecs.container_stop_timeout}}
EOF
{{#ifEquals ecs.docker.registry "dockerhub"}}
echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config
echo 'ECS_ENGINE_AUTH_DATA={"https://index.docker.io/v1/":{"username":"{{ecs.docker.username}}","password": "${DockerPassword}","email":"${DockerEmail}"}}' >> /etc/ecs/ecs.config
{{/ifEquals}}
if ! which aws >/dev/null 2>&1; then
yum install -y jq unzip
curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
unzip awscli-bundle.zip
./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
rm -rf ./awscli-bundle awscli-bundle.zip
fi
aws s3 cp s3://{{bucket}}/{{stackName}}/deployment-staging/task-reaper.sh /usr/local/bin/task-reaper.sh
chmod +x /usr/local/bin/task-reaper.sh
cat <<'EOF' >> /etc/cron.d/task-reaper
PATH=/bin:/usr/local/bin
AWS_DEFAULT_REGION=${AWS::Region}
LIFECYCLE_HOOK_NAME={{stackName}}-ecs-termination-hook
* * * * * root /usr/local/bin/task-reaper.sh >> /var/log/task-reaper.log 2>&1
EOF
--==BOUNDARY==--
{{# if ecs.efs.mount }}
- EFSFileSystemId:
Fn::ImportValue: "{{prefix}}-EFSFileSystemId"
{{else}}
# This is necessary because, if we are not setting a mount,
# the Fn::Sub function still requires a variable map
- Nothing: nothing
{{/if}}
CumulusECSAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
UpdatePolicy:
AutoScalingRollingUpdate:
MinInstancesInService: '{{ ecs.minInstances }}'
Properties:
AvailabilityZones:
{{# if ecs.availabilityZones }}
{{#each ecs.availabilityZones}}
- {{this}}
{{/each}}
{{else if ecs.availabilityZone }}
- {{ecs.availabilityZone}}
{{/if}}
{{# if vpc.subnets }}
VPCZoneIdentifier:
{{#each vpc.subnets}}
- {{this}}
{{/each}}
{{/if}}
LaunchConfigurationName:
Ref:
CumulusContainerInstanceLaunch
MinSize: '{{ ecs.minInstances }}'
DesiredCapacity: '{{ ecs.desiredInstances }}'
MaxSize: '{{ ecs.maxInstances }}'
Tags:
- Key: Name
Value: "{{prefix}}-cumulus-ecs"
PropagateAtLaunch: true
CumulusECSAutoScalingLifeCycleHook:
Type: AWS::AutoScaling::LifecycleHook
Properties:
LifecycleHookName: {{stackName}}-ecs-termination-hook
AutoScalingGroupName:
Ref:
CumulusECSAutoScalingGroup
DefaultResult: CONTINUE
HeartbeatTimeout: 150
LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING"
CumulusECSScaleOutPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: PercentChangeInCapacity
AutoScalingGroupName:
Ref:
CumulusECSAutoScalingGroup
EstimatedInstanceWarmup: 180
MetricAggregationType: Average
PolicyType: StepScaling
StepAdjustments:
- MetricIntervalLowerBound: 0
ScalingAdjustment: {{ecs.clusterAutoscaling.scaleOutAdjustmentPercent}}
CumulusECSMemoryScaleOutAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
ActionsEnabled: true
AlarmActions:
- Ref: CumulusECSScaleOutPolicy
ComparisonOperator: GreaterThanThreshold
DatapointsToAlarm: 1
Dimensions:
- Name: ClusterName
Value:
Ref:
CumulusECSCluster
EvaluationPeriods: 1
MetricName: MemoryReservation
Namespace: AWS/ECS
Period: 60
Statistic: Average
Threshold: {{ecs.clusterAutoscaling.scaleOutThresholdPercent}}
Unit: Percent
CumulusECSCPUScaleOutAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
ActionsEnabled: true
AlarmActions:
- Ref: CumulusECSScaleOutPolicy
ComparisonOperator: GreaterThanThreshold
DatapointsToAlarm: 1
Dimensions:
- Name: ClusterName
Value:
Ref:
CumulusECSCluster
EvaluationPeriods: 1
MetricName: CPUReservation
Namespace: AWS/ECS
Period: 60
Statistic: Average
Threshold: {{ecs.clusterAutoscaling.scaleOutThresholdPercent}}
Unit: Percent
CumulusECSScaleInPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: PercentChangeInCapacity
AutoScalingGroupName:
Ref:
CumulusECSAutoScalingGroup
MetricAggregationType: Average
PolicyType: StepScaling
StepAdjustments:
- MetricIntervalUpperBound: 0
ScalingAdjustment: {{ecs.clusterAutoscaling.scaleInAdjustmentPercent}}
CumulusECSMemoryScaleInAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
ActionsEnabled: true
AlarmActions:
- Ref: CumulusECSScaleInPolicy
ComparisonOperator: LessThanThreshold
DatapointsToAlarm: 1
Dimensions:
- Name: ClusterName
Value:
Ref:
CumulusECSCluster
EvaluationPeriods: 1
MetricName: MemoryReservation
Namespace: AWS/ECS
Period: 60
Statistic: Average
Threshold: {{ecs.clusterAutoscaling.scaleInThresholdPercent}}
Unit: Percent
CumulusECSCPUScaleInAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
ActionsEnabled: true
AlarmActions:
- Ref: CumulusECSScaleInPolicy
ComparisonOperator: LessThanThreshold
DatapointsToAlarm: 1
Dimensions:
- Name: ClusterName
Value:
Ref:
CumulusECSCluster
EvaluationPeriods: 1
MetricName: CPUReservation
Namespace: AWS/ECS
Period: 60
Statistic: Average
Threshold: {{ecs.clusterAutoscaling.scaleInThresholdPercent}}
Unit: Percent
{{#each ecs.services}}
# adding TaskDefinition for Lambda/ECS services
{{@key}}TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
{{# if this.volumes}}
Volumes:
{{# each this.volumes}}
- Name: {{name}}
Host:
SourcePath: {{path}}
{{/each}}
{{/if}}
{{# if this.networkMode}}
NetworkMode: {{this.networkMode}}
{{/if}}
ContainerDefinitions:
- Name: {{@key}}
Cpu: {{#if this.cpu }}{{ this.cpu }}{{ else }}10{{/if}}
Essential: true
{{# if this.volumes}}
MountPoints:
{{# each this.volumes}}
- SourceVolume: {{name}}
ContainerPath: {{dst}}
{{/each}}
{{/if}}
{{# if this.privileged }}
Privileged: true
{{/if}}
Environment:
{{#each this.envs}}
{{# if this.function}}
{{#if this.array}}
- Name: {{@key}}
Value:
{{this.function}}:
{{#each this.array}}
- {{this}}
{{/each}}
{{/if}}
{{#if this.value}}
- Name: {{@key}}
Value:
{{this.function}}: {{this.value}}
{{/if}}
{{else}}
- Name: {{@key}}
Value: {{{this}}}
{{/if}}
{{/each}}
{{# if ../ecs.docker}}
Image: {{image}}
{{else}}
Image:
Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/{{image}}
{{/if}}
MemoryReservation: {{#if this.memory }}{{ this.memory }}{{ else }}256{{/if}}
{{# if this.commands }}
Command:
{{# each this.commands }}
{{# if this.function}}
- {{this.function}}: {{this.value}}
{{else}}
- {{{ @this }}}
{{/if}}
{{/each}}
{{/if}}
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group:
Ref: {{@key}}EcsLogs
awslogs-region:
Fn::Sub: ${AWS::Region}
{{@key}}EcsLogs:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: {{../prefix}}-{{@key}}EcsLogs
RetentionInDays: 30
{{@key}}EcsLogSubscription:
Type: AWS::Logs::SubscriptionFilter
DependsOn:
- {{@key}}EcsLogs
- log2elasticsearchLambdaPermissionLog
Properties:
DestinationArn:
Fn::GetAtt:
- log2elasticsearchLambdaFunction
- Arn
LogGroupName: {{../prefix}}-{{@key}}EcsLogs
FilterPattern: ""
{{@key}}ECSService:
Type: AWS::ECS::Service
DependsOn:
- CumulusECSAutoScalingGroup
Properties:
Cluster:
Ref: CumulusECSCluster
DesiredCount: {{# if this.count}}{{this.count}}{{ else }}0{{/if}}
TaskDefinition:
Ref: {{@key}}TaskDefinition
DeploymentConfiguration:
MaximumPercent: 100
MinimumHealthyPercent: 0
{{@key}}ECSServiceTaskCountLowAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: There are less tasks running than the desired
AlarmName: {{../prefix}}-{{@key}}-TaskCountLowAlarm
ComparisonOperator: LessThanThreshold
EvaluationPeriods: 1
MetricName: MemoryUtilization
Statistic: SampleCount
Threshold: {{# if this.count}}{{this.count}}{{ else }} 0 {{/if}}
Period: 60
Namespace: AWS/ECS
Dimensions:
- Name: ClusterName
Value:
Ref: CumulusECSCluster
- Name: ServiceName
Value:
Fn::GetAtt:
- {{@key}}ECSService
- Name
{{# if this.alarms}}
# the service has cumstom alarms
{{# each this.alarms}}
{{@../key}}{{@key}}Alarm:
Type: AWS::CloudWatch::Alarm
Properties:
{{#if alarm_description}}
AlarmDescription: {{ alarm_description }}
{{/if}}
AlarmName: {{../../prefix}}-{{@../key}}-{{@key}}Alarm
ComparisonOperator: {{ comparison_operator }}
EvaluationPeriods: {{#if evaluation_periods }}{{ evaluation_periods }}{{ else }}5{{/if}}
MetricName: {{ metric }}
Statistic: {{#if statistic }}{{ statistic }}{{ else }}Average{{/if}}
Threshold: {{ threshold }}
Period: {{#if period }}{{ period }}{{ else }}60{{/if}}
Namespace: AWS/ECS
Dimensions:
- Name: ClusterName
Value:
Ref: CumulusECSCluster
- Name: ServiceName
Value:
Fn::GetAtt:
- {{@../key}}ECSService
- Name
{{/each}}
{{/if}}
{{/each}}
{{#each ecs.tasks}}
# adding TaskDefinition for Lambda/ECS tasks
{{@key}}TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
{{# if this.volumes}}
Volumes:
{{# each this.volumes}}
- Name: {{name}}
Host:
SourcePath: {{path}}
{{/each}}
{{/if}}
{{# if this.networkMode}}
NetworkMode: {{this.networkMode}}
{{/if}}
ContainerDefinitions:
- Name: {{@key}}
Cpu: {{#if this.cpu }}{{ this.cpu }}{{ else }}10{{/if}}
Essential: true
{{# if this.volumes}}
MountPoints:
{{# each this.volumes}}
- SourceVolume: {{name}}
ContainerPath: {{dst}}
{{/each}}
{{/if}}
{{# if this.privileged }}
Privileged: true
{{/if}}
Environment:
{{#each this.envs}}
{{# if this.function}}
{{#if this.array}}
- Name: {{@key}}
Value:
{{this.function}}:
{{#each this.array}}
- {{this}}
{{/each}}
{{/if}}
{{#if this.value}}
- Name: {{@key}}
Value:
{{this.function}}: {{this.value}}
{{/if}}
{{else}}
- Name: {{@key}}
Value: {{{this}}}
{{/if}}
{{/each}}
{{# if ../ecs.docker}}
Image: {{image}}
{{else}}
Image:
Fn::Sub: ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/{{image}}
{{/if}}
MemoryReservation: {{#if this.memory }}{{ this.memory }}{{ else }}256{{/if}}
{{# if this.commands }}
Command:
{{# each this.commands }}
{{# if this.function}}
- {{this.function}}: {{this.value}}
{{else}}
- {{{ @this }}}
{{/if}}
{{/each}}
{{/if}}
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group:
Ref: {{@key}}EcsLogs
awslogs-region:
Fn::Sub: ${AWS::Region}
{{@key}}EcsLogs:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: {{../prefix}}-{{@key}}EcsLogs
RetentionInDays: 30
{{@key}}EcsLogSubscription:
Type: AWS::Logs::SubscriptionFilter
DependsOn:
- {{@key}}EcsLogs
- log2elasticsearchLambdaPermissionLog
Properties:
DestinationArn:
Fn::GetAtt:
- log2elasticsearchLambdaFunction
- Arn
LogGroupName: {{../prefix}}-{{@key}}EcsLogs
FilterPattern: ""
{{/each}}
{{/if}}
#################################################
# ECS config END
#################################################
#################################################
# CloudWatch Dashboard BEGIN
#################################################
CumulusCloudWatchDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: {{prefix}}-CloudWatch-Dashboard
DashboardBody: '{{#buildCWDashboard dashboard ecs es prefix}}{{/buildCWDashboard}}'
#################################################
# CloudWatch Dashboard END
#################################################
Outputs:
Api:
{{# if api_backend_url}}
Value: {{api_backend_url}}
{{else}}
Value:
Fn::GetAtt:
- CumulusApiBackendNestedStack
- Outputs.backendRestApiResourceUrl
{{/if}}
{{# if api_distribution_url}}
Distribution:
Value: {{api_distribution_url}}
{{/if}}
{{#if deployDistributionApi}}
Distribution:
Value:
Fn::GetAtt:
- CumulusApiDistributionNestedStack
- Outputs.distributionRestApiResourceUrl
{{/if}}
ApiId:
Value:
Fn::GetAtt:
- CumulusApiBackendNestedStack
- Outputs.backendRestApiResource
{{#if deployDistributionApi}}
DistributionId:
Value:
Fn::GetAtt:
- CumulusApiDistributionNestedStack
- Outputs.distributionRestApiResource
{{/if}}
ApiStage:
Value: {{apiStage}}
{{#each stepFunctions}}
{{@key}}StateMachine:
Value:
Ref: {{../prefixNoDash}}{{@key}}StateMachine
{{/each}}
{{#each sqs}}
{{@key}}SQSOutput:
Value:
Ref: {{@key}}SQS
{{/each}}
{{#each sns}}
{{#if this.arn}}
{{@key}}:
Value: {{this.arn}}
{{else}}
{{@key}}SnsArn:
Value:
Ref: {{@key}}Sns
{{/if}}
{{/each}}
EncryptedCmrPassword:
Value:
Fn::GetAtt:
- CumulusCustomResource
- CmrPassword
EncryptedLaunchpadPassphrase:
Value:
Fn::GetAtt:
- CumulusCustomResource
- LaunchpadPassphrase