Skip to content

Commit c3d2954

Browse files
committed
Add Insights stack
1 parent 262d548 commit c3d2954

File tree

4 files changed

+317
-0
lines changed

4 files changed

+317
-0
lines changed

spire/templates/apps-200A.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ Parameters:
8787

8888
FeederSharedAlbListenerRulePriorityPrefix: { Type: String }
8989

90+
InsightsSharedAlbListenerRulePriorityPrefix: { Type: String }
91+
9092
NetworksSharedAlbListenerRulePriorityPrefix: { Type: String }
9193

9294
RemixSharedAlbListenerRulePriorityPrefix: { Type: String }
@@ -299,6 +301,39 @@ Resources:
299301
TemplateURL: !Sub ${TemplateUrlPrefix}/feeder.yml
300302
TimeoutInMinutes: 20
301303

304+
InsightsStack:
305+
Type: AWS::CloudFormation::Stack
306+
DeletionPolicy: Delete
307+
UpdateReplacePolicy: Delete
308+
Properties:
309+
Parameters:
310+
NestedChangeSetScrubbingResourcesState: !Ref NestedChangeSetScrubbingResourcesState
311+
AlbFullName: !Ref AlbFullName
312+
AlbHttpsListenerArn: !Ref AlbHttpsListenerArn
313+
EcsClusterArn: !Ref EcsClusterArn
314+
VpcId: !Ref VpcId
315+
EcrImageTag: !Sub /prx/${EnvironmentTypeAbbreviation}/Spire/Dovetail-Insights/pkg/docker-image-tag
316+
NewRelicApiKeyPrxLite: !Ref NewRelicApiKeyPrxLite
317+
AlbListenerRulePriorityPrefix: !Ref InsightsSharedAlbListenerRulePriorityPrefix
318+
EnvironmentType: !Ref EnvironmentType
319+
EnvironmentTypeAbbreviation: !Ref EnvironmentTypeAbbreviation
320+
EnvironmentTypeLowercase: !Ref EnvironmentTypeLowercase
321+
RegionMode: !Ref RegionMode
322+
RootStackName: !Ref RootStackName
323+
RootStackId: !Ref RootStackId
324+
IdHostname: !Ref IdHostname
325+
Tags:
326+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
327+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
328+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
329+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
330+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
331+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
332+
- { Key: prx:dev:family, Value: Dovetail }
333+
- { Key: prx:dev:application, Value: Insights }
334+
TemplateURL: !Sub ${TemplateUrlPrefix}/dovetail-insights.yml
335+
TimeoutInMinutes: 20
336+
302337
NetworksStack:
303338
Type: AWS::CloudFormation::Stack
304339
DeletionPolicy: Delete
@@ -426,6 +461,9 @@ Outputs:
426461
FeederWebTargetGroupFullName:
427462
Value: !GetAtt FeederStack.Outputs.WebTargetGroupFullName
428463

464+
InsightsWebTargetGroupFullName:
465+
Value: !GetAtt InsightsStack.Outputs.WebTargetGroupFullName
466+
429467
NetworksPublicWebTargetGroupFullName:
430468
Value: !GetAtt NetworksStack.Outputs.PublicWebTargetGroupFullName
431469

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
# stacks/apps/dovetail-insights.yml
2+
# 200A
3+
#
4+
# The names of the SQS queues created by this template are intended to
5+
# implicitly match some configuration that exists within the CMS application.
6+
# The only part of the queue names that is passed to the application is the
7+
# prefix; if the stems change in other the template or the app config, things
8+
# will not function as expected.
9+
AWSTemplateFormatVersion: "2010-09-09"
10+
Transform: AWS::Serverless-2016-10-31
11+
12+
Description: >-
13+
Creates a dedicated load balancer and the ECS service for the public Insights
14+
web server.
15+
16+
Parameters:
17+
kWebContainerName:
18+
Type: String
19+
Default: insights-web
20+
kWebApplicationPort:
21+
Type: Number
22+
Default: 3000
23+
#######
24+
NestedChangeSetScrubbingResourcesState: { Type: String }
25+
AlbFullName: { Type: String }
26+
AlbHttpsListenerArn: { Type: String }
27+
EcsClusterArn: { Type: String }
28+
EnvironmentType: { Type: String }
29+
EnvironmentTypeAbbreviation: { Type: String }
30+
EnvironmentTypeLowercase: { Type: String }
31+
RegionMode: { Type: String }
32+
RootStackName: { Type: String }
33+
RootStackId: { Type: String }
34+
VpcId: { Type: AWS::EC2::VPC::Id }
35+
NewRelicApiKeyPrxLite: { Type: String }
36+
EcrImageTag: { Type: AWS::SSM::Parameter::Value<String> }
37+
AlbListenerRulePriorityPrefix: { Type: String }
38+
IdHostname: { Type: String }
39+
40+
Conditions:
41+
IsProduction: !Equals [!Ref EnvironmentType, Production]
42+
IsPrimaryRegion: !Equals [!Ref RegionMode, Primary]
43+
EnableNestedChangeSetScrubbingResources: !Equals [!Ref NestedChangeSetScrubbingResourcesState, Enabled]
44+
45+
Resources:
46+
NestedChangeSetScrubber: { Type: AWS::SNS::Topic, Condition: EnableNestedChangeSetScrubbingResources }
47+
48+
HostHeaderListenerRule:
49+
Type: AWS::ElasticLoadBalancingV2::ListenerRule
50+
Properties:
51+
Actions:
52+
- TargetGroupArn: !Ref WebTargetGroup
53+
Type: forward
54+
Conditions:
55+
- Field: host-header
56+
Values:
57+
- insights.dovetail.*
58+
ListenerArn: !Ref AlbHttpsListenerArn
59+
Priority: !Join ["", [!Ref AlbListenerRulePriorityPrefix, "01"]]
60+
61+
ExecutionRole:
62+
Type: AWS::IAM::Role
63+
Properties:
64+
AssumeRolePolicyDocument:
65+
Statement:
66+
- Action: sts:AssumeRole
67+
Effect: Allow
68+
Principal:
69+
Service: ecs-tasks.amazonaws.com
70+
Version: "2012-10-17"
71+
ManagedPolicyArns:
72+
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
73+
Policies:
74+
- PolicyDocument:
75+
Statement:
76+
- Action: ssm:GetParameters
77+
Effect: Allow
78+
Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/prx/${EnvironmentTypeAbbreviation}/Spire/Dovetail-Insights/*
79+
Sid: AllowAppParameterRead
80+
Version: "2012-10-17"
81+
PolicyName: ContainerSecrets
82+
Tags:
83+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
84+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
85+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
86+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
87+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
88+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
89+
- { Key: prx:dev:family, Value: Dovetail }
90+
- { Key: prx:dev:application, Value: Insights }
91+
TaskRole:
92+
Type: AWS::IAM::Role
93+
Properties:
94+
AssumeRolePolicyDocument:
95+
Statement:
96+
- Action: sts:AssumeRole
97+
Effect: Allow
98+
Principal:
99+
Service: ecs-tasks.amazonaws.com
100+
Version: "2012-10-17"
101+
Policies:
102+
- PolicyDocument:
103+
Statement:
104+
- Action: events:PutEvents
105+
Effect: Allow
106+
Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default
107+
Sid: AllowDefaultEventBusPut
108+
Version: "2012-10-17"
109+
PolicyName: DefaultEventBus
110+
Tags:
111+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
112+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
113+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
114+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
115+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
116+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
117+
- { Key: prx:dev:family, Value: Dovetail }
118+
- { Key: prx:dev:application, Value: Insights }
119+
120+
WebTargetGroup:
121+
Type: AWS::ElasticLoadBalancingV2::TargetGroup
122+
Properties:
123+
HealthCheckIntervalSeconds: 15
124+
HealthCheckPath: /api/v1
125+
HealthCheckTimeoutSeconds: 5
126+
HealthyThresholdCount: 3
127+
Port: 80
128+
Protocol: HTTP
129+
TargetGroupAttributes:
130+
- Key: deregistration_delay.timeout_seconds
131+
Value: "30"
132+
Tags:
133+
- { Key: Name, Value: !Sub "${RootStackName}_insights" }
134+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
135+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
136+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
137+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
138+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
139+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
140+
- { Key: prx:dev:family, Value: Dovetail }
141+
- { Key: prx:dev:application, Value: Insights }
142+
UnhealthyThresholdCount: 3
143+
VpcId: !Ref VpcId
144+
WebTargetGroupHttp5xxAlarm:
145+
Type: AWS::CloudWatch::Alarm
146+
Condition: IsProduction
147+
Properties:
148+
AlarmName: !Sub ERROR [Insights] Web server <${EnvironmentTypeAbbreviation}> RETURNING 5XX ERRORS (${RootStackName})
149+
AlarmDescription: !Sub >-
150+
${EnvironmentType} Insights' Rails server is returning 5XX errors from
151+
the ECS service to the load balancer.
152+
ComparisonOperator: GreaterThanThreshold
153+
Dimensions:
154+
- Name: LoadBalancer
155+
Value: !Ref AlbFullName
156+
- Name: TargetGroup
157+
Value: !GetAtt WebTargetGroup.TargetGroupFullName
158+
EvaluationPeriods: 1
159+
MetricName: HTTPCode_Target_5XX_Count
160+
Namespace: AWS/ApplicationELB
161+
Period: 60
162+
Statistic: Sum
163+
Tags:
164+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
165+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
166+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
167+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
168+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
169+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
170+
- { Key: prx:ops:cloudwatch-log-group-name, Value: !Ref WebTaskLogGroup }
171+
- { Key: prx:dev:family, Value: Dovetail }
172+
- { Key: prx:dev:application, Value: Insights }
173+
Threshold: 0
174+
TreatMissingData: notBreaching
175+
176+
WebEcsService:
177+
Type: AWS::ECS::Service
178+
# Condition: HasAuroraEndpoint # See README
179+
Properties:
180+
Cluster: !Ref EcsClusterArn
181+
DeploymentConfiguration:
182+
MaximumPercent: 200
183+
MinimumHealthyPercent: 50
184+
DesiredCount: !If [IsPrimaryRegion, !If [IsProduction, 0, 0], 0]
185+
EnableECSManagedTags: true
186+
LoadBalancers:
187+
- ContainerName: !Ref kWebContainerName
188+
ContainerPort: !Ref kWebApplicationPort
189+
TargetGroupArn: !Ref WebTargetGroup
190+
PlacementConstraints:
191+
- Type: memberOf
192+
Expression: attribute:ecs.cpu-architecture == ARM64
193+
PropagateTags: TASK_DEFINITION
194+
Tags:
195+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
196+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
197+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
198+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
199+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
200+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
201+
- { Key: prx:dev:family, Value: Dovetail }
202+
- { Key: prx:dev:application, Value: Insights }
203+
TaskDefinition: !Ref WebTaskDefinition
204+
WebTaskLogGroup:
205+
Type: AWS::Logs::LogGroup
206+
DeletionPolicy: Delete
207+
UpdateReplacePolicy: Delete
208+
Properties:
209+
RetentionInDays: 14
210+
Tags:
211+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
212+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
213+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
214+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
215+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
216+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
217+
- { Key: prx:dev:family, Value: Dovetail }
218+
- { Key: prx:dev:application, Value: Insights }
219+
WebTaskDefinition:
220+
Type: AWS::ECS::TaskDefinition
221+
Properties:
222+
ContainerDefinitions:
223+
- Command:
224+
- web
225+
Cpu: !If [IsProduction, 200, 128]
226+
Environment:
227+
- Name: ID_HOST
228+
Value: !Ref IdHostname
229+
- Name: NEW_RELIC_KEY
230+
Value: !Ref NewRelicApiKeyPrxLite
231+
- Name: NEW_RELIC_NAME
232+
Value: !If [IsProduction, Insights Production, Insights Staging]
233+
- Name: PORT
234+
Value: !Ref kWebApplicationPort
235+
- Name: RAILS_ENV
236+
Value: !Ref EnvironmentTypeLowercase
237+
Essential: true
238+
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrImageTag}
239+
LinuxParameters:
240+
InitProcessEnabled: true
241+
LogConfiguration:
242+
LogDriver: awslogs
243+
Options:
244+
awslogs-group: !Ref WebTaskLogGroup
245+
awslogs-region: !Ref AWS::Region
246+
awslogs-stream-prefix: ecs
247+
Memory: !If [IsProduction, 2000, 1000]
248+
MemoryReservation: !If [IsProduction, 1000, 500]
249+
Name: !Ref kWebContainerName
250+
PortMappings:
251+
- ContainerPort: !Ref kWebApplicationPort
252+
HostPort: 0
253+
# Secrets:
254+
# - Name: API_ADMIN_TOKENS
255+
# ValueFrom: !Sub /prx/${EnvironmentTypeAbbreviation}/Spire/Dovetail-Feeder/api-admin-tokens
256+
ExecutionRoleArn: !GetAtt ExecutionRole.Arn
257+
NetworkMode: bridge
258+
Tags:
259+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
260+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
261+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
262+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
263+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
264+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
265+
- { Key: prx:dev:family, Value: Dovetail }
266+
- { Key: prx:dev:application, Value: Insights }
267+
TaskRoleArn: !GetAtt TaskRole.Arn
268+
269+
Outputs:
270+
WebTargetGroupFullName:
271+
Value: !GetAtt WebTargetGroup.TargetGroupFullName

spire/templates/dashboards.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ Parameters:
6767

6868
IframelyTargetGroupFullName: { Type: String }
6969

70+
InsightsWebTargetGroupFullName: { Type: String }
71+
7072
MetricsTargetGroupFullName: { Type: String }
7173

7274
NetworksPublicWebTargetGroupFullName: { Type: String }
@@ -174,6 +176,7 @@ Resources:
174176
[ "AWS/ApiGateway", "Count", "ApiId", "${FeederAuthProxyApiId}", { "label": "Feeder Auth Proxy" } ],
175177
[ "AWS/ApplicationELB", "RequestCount", "TargetGroup", "${IdTargetGroupFullName}", "LoadBalancer", "${SharedAlbFullName}", { "label": "ID" } ],
176178
[ "AWS/ApplicationELB", "RequestCount", "TargetGroup", "${IframelyTargetGroupFullName}", "LoadBalancer", "${SharedAlbFullName}", { "label": "Iframely" } ],
179+
[ "AWS/ApplicationELB", "RequestCount", "TargetGroup", "${InsightsWebTargetGroupFullName}", "LoadBalancer", "${SharedAlbFullName}", { "label": "Dovetail Insights" } ],
177180
[ "AWS/ApplicationELB", "RequestCount", "TargetGroup", "${MetricsTargetGroupFullName}", "LoadBalancer", "${SharedAlbFullName}", { "label": "Metrics" } ],
178181
[ "AWS/ApplicationELB", "RequestCount", "TargetGroup", "${NetworksPublicWebTargetGroupFullName}", "LoadBalancer", "${SharedAlbFullName}", { "label": "Networks" } ],
179182
[ "AWS/ApplicationELB", "RequestCount", "TargetGroup", "${PlayWebTargetGroupFullName}", "LoadBalancer", "${SharedAlbFullName}", { "label": "Play::Web" } ],

spire/templates/root.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Mappings:
7171
Networks: { prefix: 28 }
7272
Remix: { prefix: 29 }
7373
Metrics: { prefix: 36 }
74+
Insights: { prefix: 37 }
7475
TheCount: { prefix: 42 }
7576
TheCastle: { prefix: 50 } # Legacy Castle
7677
Styleguide: { prefix: 65 }
@@ -825,6 +826,8 @@ Resources:
825826

826827
FeederSharedAlbListenerRulePriorityPrefix: !FindInMap [SharedAlbListenerRulePriorityMap, Feeder, prefix]
827828

829+
InsightsSharedAlbListenerRulePriorityPrefix: !FindInMap [SharedAlbListenerRulePriorityMap, Insights, prefix]
830+
828831
NetworksSharedAlbListenerRulePriorityPrefix: !FindInMap [SharedAlbListenerRulePriorityMap, Networks, prefix]
829832

830833
RemixSharedAlbListenerRulePriorityPrefix: !FindInMap [SharedAlbListenerRulePriorityMap, Remix, prefix]
@@ -1084,6 +1087,8 @@ Resources:
10841087

10851088
IframelyTargetGroupFullName: !GetAtt Apps100AStack.Outputs.IframelyTargetGroupFullName
10861089

1090+
InsightsWebTargetGroupFullName: !GetAtt Apps200AStack.Outputs.InsightsWebTargetGroupFullName
1091+
10871092
MetricsTargetGroupFullName: !GetAtt Apps300AStack.Outputs.MetricsTargetGroupFullName
10881093

10891094
NetworksPublicWebTargetGroupFullName: !GetAtt Apps200AStack.Outputs.NetworksPublicWebTargetGroupFullName

0 commit comments

Comments
 (0)