Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
['arn:aws:s3:::',
cf.select(1,
cf.split('s3://', cf.ref('DatabaseDump'))
)]
)]
}]
}
}],
RoleName: cf.join('-', [cf.stackName, 'ec2', 'database-dump-access', 'role'])
}
},
TaskingManagerEC2InstanceProfile: {
Type: "AWS::IAM::InstanceProfile",
Properties: {
Roles: cf.if('DatabaseDumpFileGiven', [cf.ref('TaskingManagerEC2Role'), cf.ref('TaskingManagerDatabaseDumpAccessRole')], [cf.ref('TaskingManagerEC2Role')]),
InstanceProfileName: cf.join('-', [cf.stackName, 'ec2', 'instance', 'profile'])
}
},
TaskingManagerLoadBalancer: {
Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer',
Properties: {
Name: cf.stackName,
SecurityGroups: [cf.importValue(cf.join('-', ['hotosm-network-production', cf.ref('Environment'), 'elbs-security-group', cf.region]))],
Subnets: cf.split(',', cf.ref('ELBSubnets')),
Type: 'application'
}
},
TaskingManagerTargetGroup: {
Type: 'AWS::ElasticLoadBalancingV2::TargetGroup',
Properties: {
HealthCheckIntervalSeconds: 60,
HealthCheckPort: 8000,
's3:GetObject',
's3:GetObjectAcl',
's3:ListObjects',
's3:ListBucket'
],
Effect: 'Allow',
Resource: [cf.join('',
['arn:aws:s3:::',
cf.select(1,
cf.split('s3://', cf.ref('DatabaseDump'))
)]
)]
}]
}
}],
RoleName: cf.join('-', [cf.stackName, 'ec2', 'database-dump-access', 'role'])
}
},
TaskingManagerEC2InstanceProfile: {
Type: "AWS::IAM::InstanceProfile",
Properties: {
Roles: cf.if('DatabaseDumpFileGiven', [cf.ref('TaskingManagerDatabaseDumpAccessRole')], [cf.ref('TaskingManagerEC2Role')]),
InstanceProfileName: cf.join('-', [cf.stackName, 'ec2', 'instance', 'profile'])
}
},
TaskingManagerLoadBalancer: {
Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer',
Properties: {
Name: cf.stackName,
SecurityGroups: [cf.importValue(cf.join('-', ['hotosm-network-production', cf.ref('NetworkEnvironment'), 'elbs-security-group', cf.region]))],
Subnets: cf.split(',', cf.ref('ELBSubnets')),
Type: 'application'
}
}],
RoleName: cf.join('-', [cf.stackName, 'ec2', 'database-dump-access', 'role'])
}
},
TaskingManagerEC2InstanceProfile: {
Type: "AWS::IAM::InstanceProfile",
Properties: {
Roles: cf.if('DatabaseDumpFileGiven', [cf.ref('TaskingManagerDatabaseDumpAccessRole')], [cf.ref('TaskingManagerEC2Role')]),
InstanceProfileName: cf.join('-', [cf.stackName, 'ec2', 'instance', 'profile'])
}
},
TaskingManagerLoadBalancer: {
Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer',
Properties: {
Name: cf.stackName,
SecurityGroups: [cf.importValue(cf.join('-', ['hotosm-network-production', cf.ref('NetworkEnvironment'), 'elbs-security-group', cf.region]))],
Subnets: cf.split(',', cf.ref('ELBSubnets')),
Type: 'application'
}
},
TaskingManagerTargetGroup: {
Type: 'AWS::ElasticLoadBalancingV2::TargetGroup',
Properties: {
HealthCheckIntervalSeconds: 60,
HealthCheckPort: 8000,
HealthCheckProtocol: 'HTTP',
HealthCheckTimeoutSeconds: 10,
HealthyThresholdCount: 3,
UnhealthyThresholdCount: 3,
Port: 8000,
Protocol: 'HTTP',
MLEnablerTargetGroup: {
Type: "AWS::ElasticLoadBalancingV2::TargetGroup",
Properties: {
Port: 5000,
Protocol: "HTTP",
VpcId: cf.importValue(cf.join("-", ["hotosm-network-production", "default-vpc", cf.region])),
TargetType: "ip",
Matcher: {
HttpCode: "200,202,302,304"
}
}
},
MLEnablerALB: {
Type: "AWS::ElasticLoadBalancingV2::LoadBalancer",
Properties: {
Name: cf.stackName,
SecurityGroups: [
cf.importValue(
cf.join("-", ["hotosm-network-production-production-elbs-security-group", cf.region])
)
],
Subnets: cf.split(",", cf.ref("ELBSubnets")),
Type: "application"
}
},
MLEnablerHTTPSListener: {
Type: 'AWS::ElasticLoadBalancingV2::Listener',
Properties: {
Certificates: [ {
CertificateArn: cf.arn('acm', cf.ref('SSLCertificateIdentifier'))
}],
DefaultActions: [{
Properties: {
ClusterName: cf.join("-", [cf.stackName, "cluster"])
}
},
MLEnablerTaskDefinition: {
Type: "AWS::ECS::TaskDefinition",
Properties: {
Family: cf.stackName,
Cpu: cf.ref("ContainerCpu"),
Memory: cf.ref("ContainerMemory"),
NetworkMode: "awsvpc",
RequiresCompatibilities: ["FARGATE"],
Tags: [
{
Key: "Name",
Value: cf.stackName
}
],
ContainerDefinitions: [
{
Name: "app",
Image: cf.join(":", ["hotosm/ml-enabler", cf.ref("ImageTag")]),
PortMappings: [
{
ContainerPort: 5000
}
],
Environment: [
{
Name:"POSTGRES_DB",
Value: cf.ref("DatabaseName")
},
Name:"POSTGRES_PORT",
Value: "5432"
},
{
Name: "FLASK_APP",
Value: "ml_enabler"
},
{
Name: "ECS_LOG_LEVEL",
Value: "debug"
}
],
LogConfiguration: {
LogDriver: "awslogs",
Options: {
"awslogs-group": cf.join("-", ["awslogs", cf.stackName]),
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": cf.join("-", ["awslogs", cf.stackName])
}
},
Essential: true
},
{
Name: "migration",
Image: cf.join(":", ["hotosm/ml-enabler", cf.ref("ImageTag")]),
Environment: [
{
Name:"POSTGRES_DB",
Value: cf.ref("DatabaseName")
},
{
Name:"POSTGRES_USER",
},
DatabaseUser: {
Type: "String",
Description: "Database Username"
},
DatabasePassword: {
Type: "String",
Description: "Database User Password"
}
};
const Resources = {
MLEnablerECSCluster: {
Type: "AWS::ECS::Cluster",
Properties: {
ClusterName: cf.join("-", [cf.stackName, "cluster"])
}
},
MLEnablerTaskDefinition: {
Type: "AWS::ECS::TaskDefinition",
Properties: {
Family: cf.stackName,
Cpu: cf.ref("ContainerCpu"),
Memory: cf.ref("ContainerMemory"),
NetworkMode: "awsvpc",
RequiresCompatibilities: ["FARGATE"],
Tags: [
{
Key: "Name",
Value: cf.stackName
}
],
Description: 'Subscribe to this topic to receive emails when tasks fail or retry',
Properties: {
Subscription: [
{
Endpoint: options.notificationEmail,
Protocol: 'email'
}
]
}
};
Resources[prefixed('DeadLetterQueue')] = {
Type: 'AWS::SQS::Queue',
Description: 'List of messages that failed to process 14 times',
Properties: {
QueueName: cf.join([cf.stackName, '-', prefixed('DeadLetterQueue')]),
MessageRetentionPeriod: 1209600
}
};
if (options.fifo) {
Resources[prefixed('DeadLetterQueue')].Properties.FifoQueue = true;
Resources[prefixed('DeadLetterQueue')].Properties.ContentBasedDeduplication = true;
Resources[prefixed('DeadLetterQueue')].Properties.QueueName = cf.join([cf.stackName, '-', prefixed('DeadLetterQueue'), '.fifo']);
}
Resources[prefixed('Queue')] = {
Type: 'AWS::SQS::Queue',
Properties: {
VisibilityTimeout: 180,
QueueName: cf.join([cf.stackName, '-', prefixed('Queue')]),
MessageRetentionPeriod: options.messageRetention,
TargetPipeline: cf.ref('Pipeline'),
TargetPipelineVersion: cf.getAtt('Pipeline', 'Version'),
TargetAction: 'GitHub',
Filters: [
{
JsonPath: '$.ref',
MatchEquals: 'refs/heads/{Branch}'
}
],
RegisterWithThirdParty: true
}
},
Pipeline: {
Type: 'AWS::CodePipeline::Pipeline',
Properties: {
Name: cf.stackName,
RoleArn: cf.getAtt('PipelineRole', 'Arn'),
ArtifactStore: {
Type: 'S3',
Location: 'watchbot-binaries'
},
Stages: [
{
Name: 'Source',
Actions: [
{
Name: 'GitHub',
ActionTypeId: {
Category: 'Source',
Owner: 'ThirdParty',
Version: '1',
Provider: 'GitHub'
}
};
const Conditions = {
UseASnapshot: cf.notEquals(cf.ref('DBSnapshot'), ''),
DatabaseDumpFileGiven: cf.notEquals(cf.ref('DatabaseDump'), ''),
IsTaskingManagerProduction: cf.equals(cf.ref('AutoscalingPolicy'), 'Production (max 12)'),
IsTaskingManagerDemo: cf.equals(cf.ref('AutoscalingPolicy'), 'Demo (max 3)')
};
const Resources = {
TaskingManagerASG: {
DependsOn: 'TaskingManagerLaunchConfiguration',
Type: 'AWS::AutoScaling::AutoScalingGroup',
Properties: {
AutoScalingGroupName: cf.stackName,
Cooldown: 600,
MinSize: cf.if('IsTaskingManagerProduction', 3, 1),
DesiredCapacity: cf.if('IsTaskingManagerProduction', 3, 1),
MaxSize: cf.if('IsTaskingManagerProduction', 12, cf.if('IsTaskingManagerDemo', 3, 1)),
HealthCheckGracePeriod: 600,
LaunchConfigurationName: cf.ref('TaskingManagerLaunchConfiguration'),
TargetGroupARNs: [ cf.ref('TaskingManagerTargetGroup') ],
HealthCheckType: 'EC2',
AvailabilityZones: ['us-east-1a', 'us-east-1b', 'us-east-1c', 'us-east-1d', 'us-east-1f']
},
UpdatePolicy: {
AutoScalingRollingUpdate: {
PauseTime: 'PT60M',
WaitOnResourceSignals: true
}
}