Skip to content

Commit 3f5f820

Browse files
authored
Merge pull request #873 from PRX/feat/stream_recorder
Setup stream recorder lambda
2 parents 46056c0 + 2a9a0e7 commit 3f5f820

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed

spire/templates/apps-100A.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,35 @@ Resources:
236236
TemplateURL: !Sub ${TemplateUrlPrefix}/dovetail-marketing-form-handler.yml
237237
TimeoutInMinutes: 10
238238

239+
DovetailStreamRecorderStack:
240+
Type: AWS::CloudFormation::Stack
241+
UpdateReplacePolicy: Delete
242+
DeletionPolicy: Delete
243+
Properties:
244+
Parameters:
245+
NestedChangeSetScrubbingResourcesState: !Ref NestedChangeSetScrubbingResourcesState
246+
EnvironmentType: !Ref EnvironmentType
247+
EnvironmentTypeAbbreviation: !Ref EnvironmentTypeAbbreviation
248+
AwsOrganizationId: !Ref AwsOrganizationId
249+
RegionMode: !Ref RegionMode
250+
RootStackName: !Ref RootStackName
251+
RootStackId: !Ref RootStackId
252+
CodeS3Bucket: !Ref DeploymentPackageBucketName
253+
CodeS3ObjectKey: !Sub /prx/${EnvironmentTypeAbbreviation}/Spire/Dovetail-Stream_Recorder/pkg/s3-object-key
254+
StreamRecorderConfigUrl: !Sub /prx/${EnvironmentTypeAbbreviation}/Spire/Dovetail-Stream_Recorder/config-url
255+
StreamRecorderOxbowSnsTopicArns: !Sub /prx/${EnvironmentTypeAbbreviation}/Spire/Dovetail-Stream_Recorder/${AWS::Region}/oxbow-sns-topic-arns
256+
Tags:
257+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
258+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
259+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
260+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
261+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
262+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
263+
- { Key: prx:dev:family, Value: Dovetail }
264+
- { Key: prx:dev:application, Value: Stream Recorder }
265+
TemplateURL: !Sub ${TemplateUrlPrefix}/dovetail-stream-recorder.yml
266+
TimeoutInMinutes: 5
267+
239268
DovetailTrafficStack:
240269
Type: AWS::CloudFormation::Stack
241270
Condition: IsStaging # Staging only
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# stacks/apps/dovetail-stream-recorder.yml
2+
# 100A
3+
AWSTemplateFormatVersion: "2010-09-09"
4+
Transform: AWS::Serverless-2016-10-31
5+
6+
Description: >-
7+
Creates a Lambda function that orchestrates audio stream recordings
8+
9+
Parameters:
10+
kMetricFilterNamespace:
11+
Type: String
12+
Default: PRX/Dovetail/StreamRecorder
13+
#######
14+
NestedChangeSetScrubbingResourcesState: { Type: String }
15+
EnvironmentType: { Type: String }
16+
EnvironmentTypeAbbreviation: { Type: String }
17+
AwsOrganizationId: { Type: String }
18+
RegionMode: { Type: String }
19+
RootStackName: { Type: String }
20+
RootStackId: { Type: String }
21+
CodeS3Bucket: { Type: String }
22+
CodeS3ObjectKey: { Type: AWS::SSM::Parameter::Value<String> }
23+
StreamRecorderConfigUrl: { Type: AWS::SSM::Parameter::Value<String> }
24+
StreamRecorderOxbowSnsTopicArns: { Type: AWS::SSM::Parameter::Value<String> }
25+
26+
Conditions:
27+
EnableNestedChangeSetScrubbingResources: !Equals [!Ref NestedChangeSetScrubbingResourcesState, Enabled]
28+
29+
Resources:
30+
NestedChangeSetScrubber: { Type: AWS::SNS::Topic, Condition: EnableNestedChangeSetScrubbingResources }
31+
32+
StreamRecorderBucket:
33+
Type: AWS::S3::Bucket
34+
DeletionPolicy: Retain
35+
UpdateReplacePolicy: Retain
36+
Properties:
37+
LifecycleConfiguration:
38+
Rules:
39+
- ExpirationInDays: 14
40+
Status: Enabled
41+
PublicAccessBlockConfiguration:
42+
BlockPublicAcls: true
43+
BlockPublicPolicy: true
44+
IgnorePublicAcls: true
45+
RestrictPublicBuckets: true
46+
Tags:
47+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
48+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
49+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
50+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
51+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
52+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
53+
- { Key: prx:dev:family, Value: Dovetail }
54+
- { Key: prx:dev:application, Value: Stream Recorder }
55+
StreamRecorderBucketPolicy:
56+
Type: AWS::S3::BucketPolicy
57+
DeletionPolicy: Retain
58+
UpdateReplacePolicy: Retain
59+
Properties:
60+
Bucket: !Ref StreamRecorderBucket
61+
PolicyDocument:
62+
Statement:
63+
- Action: s3:GetObject
64+
Condition:
65+
StringEquals:
66+
aws:PrincipalOrgID: !Ref AwsOrganizationId
67+
Effect: Allow
68+
Principal:
69+
AWS: "*"
70+
Resource: !Sub ${StreamRecorderBucket.Arn}/*
71+
Sid: AllowOrganizationObjectRead
72+
Version: "2012-10-17"
73+
74+
StreamRecorderFunction:
75+
Type: AWS::Serverless::Function
76+
Properties:
77+
CodeUri:
78+
Bucket: !Ref CodeS3Bucket
79+
Key: !Ref CodeS3ObjectKey
80+
Description: !Sub ${EnvironmentType} Stream Recorder
81+
Environment:
82+
Variables:
83+
BUFFER_START: "300"
84+
BUFFER_END: "300"
85+
CONFIG_URL: !Ref StreamRecorderConfigUrl
86+
OXBOW_SNS_TOPICS: !Ref StreamRecorderOxbowSnsTopicArns
87+
OXBOW_STARTUP_TIME: "120"
88+
OXBOW_WIP_TIME: "30"
89+
S3_BUCKET: !Ref StreamRecorderBucket
90+
Events:
91+
ScheduleTrigger:
92+
Properties:
93+
Schedule: !Sub rate(1 minute)
94+
# TODO: remove after testing redundant recording callbacks
95+
Enabled: !Equals [!Ref RegionMode, Primary]
96+
Type: Schedule
97+
Handler: index.handler
98+
MemorySize: 256
99+
Runtime: nodejs24.x
100+
Policies:
101+
- Statement:
102+
- Action: s3:ListBucket
103+
Effect: Allow
104+
Resource: !GetAtt StreamRecorderBucket.Arn
105+
- Action:
106+
- s3:GetObject
107+
- s3:GetObjectAcl
108+
- s3:GetObjectTagging
109+
- s3:PutObject
110+
- s3:PutObjectAcl
111+
- s3:PutObjectTagging
112+
Effect: Allow
113+
Resource: !Sub ${StreamRecorderBucket.Arn}/*
114+
Version: "2012-10-17"
115+
Tags:
116+
prx:meta:tagging-version: "2021-04-07"
117+
prx:cloudformation:stack-name: !Ref AWS::StackName
118+
prx:cloudformation:stack-id: !Ref AWS::StackId
119+
prx:cloudformation:root-stack-name: !Ref RootStackName
120+
prx:cloudformation:root-stack-id: !Ref RootStackId
121+
prx:ops:environment: !Ref EnvironmentType
122+
prx:dev:family: Dovetail
123+
prx:dev:application: Stream Recorder
124+
Timeout: 60
125+
StreamRecorderFunctionLogGroup:
126+
Type: AWS::Logs::LogGroup
127+
DeletionPolicy: Delete
128+
UpdateReplacePolicy: Delete
129+
Properties:
130+
LogGroupName: !Sub /aws/lambda/${StreamRecorderFunction}
131+
RetentionInDays: 14
132+
Tags:
133+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
134+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
135+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
136+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
137+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
138+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
139+
- { Key: prx:dev:family, Value: Dovetail }
140+
- { Key: prx:dev:application, Value: Stream Recorder }
141+
142+
StreamRecorderElevatedErrorAlarm:
143+
Type: AWS::CloudWatch::Alarm
144+
Properties:
145+
AlarmName: !Sub WARN [Stream-Recorder] Lambda function <${EnvironmentTypeAbbreviation}> INVOCATIONS ERRORS (${RootStackName})
146+
AlarmDescription: !Sub >-
147+
${EnvironmentType} Stream Recorder Lambda function is failing, so it
148+
may not be capturing audio streams!
149+
ComparisonOperator: GreaterThanThreshold
150+
Dimensions:
151+
- Name: FunctionName
152+
Value: !Ref StreamRecorderFunction
153+
EvaluationPeriods: 1
154+
MetricName: Errors
155+
Namespace: AWS/Lambda
156+
Period: 60
157+
Statistic: Sum
158+
Tags:
159+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
160+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
161+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
162+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
163+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
164+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
165+
- { Key: prx:dev:family, Value: Dovetail }
166+
- { Key: prx:dev:application, Value: Stream Recorder }
167+
Threshold: 0
168+
TreatMissingData: notBreaching
169+
170+
StreamRecorderFunctionWarnLevelLogMetricFilter:
171+
Type: AWS::Logs::MetricFilter
172+
Properties:
173+
FilterPattern: '{ $._logLevel = "warn" }'
174+
LogGroupName: !Ref StreamRecorderFunctionLogGroup
175+
MetricTransformations:
176+
- MetricName: !Sub warns_${StreamRecorderFunction}
177+
MetricNamespace: !Ref kMetricFilterNamespace
178+
MetricValue: "1"
179+
StreamRecorderFunctionLoggedWarnAlarm:
180+
Type: AWS::CloudWatch::Alarm
181+
Properties:
182+
AlarmName: !Sub WARN [Stream-Recorder] Lambda function <${EnvironmentTypeAbbreviation}> LOGGED WARNINGS (${RootStackName})
183+
AlarmDescription: !Sub >-
184+
${EnvironmentType} Stream Recorder Lambda function has logged some warnings.
185+
ComparisonOperator: GreaterThanThreshold
186+
EvaluationPeriods: 1
187+
MetricName: !Sub warns_${StreamRecorderFunction}
188+
Namespace: !Ref kMetricFilterNamespace
189+
Period: 60
190+
Statistic: Sum
191+
Tags:
192+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
193+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
194+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
195+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
196+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
197+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
198+
- { Key: prx:ops:cloudwatch-log-group-name, Value: !Ref StreamRecorderFunctionLogGroup }
199+
- { Key: prx:dev:family, Value: Dovetail }
200+
- { Key: prx:dev:application, Value: Stream Recorder }
201+
Threshold: 0
202+
TreatMissingData: notBreaching
203+
204+
StreamRecorderFunctionErrorLevelLogMetricFilter:
205+
Type: AWS::Logs::MetricFilter
206+
Properties:
207+
FilterPattern: '{ $._logLevel = "error" }'
208+
LogGroupName: !Ref StreamRecorderFunctionLogGroup
209+
MetricTransformations:
210+
- MetricName: !Sub errors_${StreamRecorderFunction}
211+
MetricNamespace: !Ref kMetricFilterNamespace
212+
MetricValue: "1"
213+
StreamRecorderFunctionLoggedErrorAlarm:
214+
Type: AWS::CloudWatch::Alarm
215+
Properties:
216+
AlarmName: !Sub ERROR [Stream-Recorder] Lambda function <${EnvironmentTypeAbbreviation}> LOGGED ERRORS (${RootStackName})
217+
AlarmDescription: !Sub >-
218+
${EnvironmentType} Stream Recorder Lambda function has logged some errors.
219+
ComparisonOperator: GreaterThanThreshold
220+
EvaluationPeriods: 1
221+
MetricName: !Sub errors_${StreamRecorderFunction}
222+
Namespace: !Ref kMetricFilterNamespace
223+
Period: 60
224+
Statistic: Sum
225+
Tags:
226+
- { Key: prx:meta:tagging-version, Value: "2021-04-07" }
227+
- { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
228+
- { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
229+
- { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
230+
- { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
231+
- { Key: prx:ops:environment, Value: !Ref EnvironmentType }
232+
- { Key: prx:ops:cloudwatch-log-group-name, Value: !Ref StreamRecorderFunctionLogGroup }
233+
- { Key: prx:dev:family, Value: Dovetail }
234+
- { Key: prx:dev:application, Value: Stream Recorder }
235+
Threshold: 0
236+
TreatMissingData: notBreaching
237+
238+
Outputs:
239+
StreamRecorderFunctionArn:
240+
Value: !GetAtt StreamRecorderFunction.Arn
241+
StreamRecorderBucketArn:
242+
Value: !GetAtt StreamRecorderBucket.Arn
243+
StreamRecorderBucketRegionalDomainName:
244+
Value: !GetAtt StreamRecorderBucket.RegionalDomainName

0 commit comments

Comments
 (0)