-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathtemplate.yaml
389 lines (358 loc) · 11.4 KB
/
template.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Serverless Specification template describing your function.
Parameters:
SourceEmail:
Type: String
Description: The sending email address for notification emails.
Default: [email protected]
DestEmail:
Type: String
Description: The receiving email address for notification emails.
Default: [email protected]
SendEmails:
Description: Set whether to send SES emails or not (default 'n').
Default: 'n'
Type: String
AllowedValues:
- 'y'
- 'n'
StorePublicS3:
Description: Store a JSON object of blogposts as a public S3 file (default 'n').
Default: 'n'
Type: String
AllowedValues:
- 'y'
- 'n'
CreateAppSync:
Description: Create a read only AppSync endpoint for the blogs stored in DynamoDB
Default: 'n'
Type: String
AllowedValues:
- 'y'
- 'n'
EnableAlgolia:
Description: Optional - enable Algolia search index support
Default: 'n'
Type: 'String'
AllowedValues:
- 'y'
- 'n'
AlgoliaApp:
Description: Optional - add the Algolia App ID
Default: ''
Type: String
AlgoliaApikey:
Description: Optional - add the Algolia API key
Default: ''
Type: String
AlgoliaIndex:
Description: Optional - add the Algolia Index name
Default: ''
Type: String
# appsync create condition
Conditions:
EnableAppSync: !Equals [ !Ref CreateAppSync, y ]
Resources:
# create per rss feed retrieval function
rssgetfeed:
Type: 'AWS::Serverless::Function'
Properties:
Handler: getfeed.handler
Runtime: python3.8
CodeUri: lambda-getfeed/
Description: 'Retrieve RSS feeds and store them in DynamoDB'
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'ses:SendEmail'
Resource: '*'
- ComprehendFullAccess
- arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy
- DynamoDBCrudPolicy:
TableName: !Ref rssfeed
- S3CrudPolicy:
BucketName: !Ref PublicJsonBucket
MemorySize: 512
Timeout: 30
Environment:
Variables:
dynamo_table: !Ref rssfeed
Tracing: Active
ReservedConcurrentExecutions: 50
Layers:
- !Ref lambdalayer
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:14"
# create rss feed crawl function
rsscrawl:
Type: 'AWS::Serverless::Function'
Properties:
Handler: crawl.handler
Runtime: python3.8
CodeUri: lambda-crawl/
Description: 'Retrieve RSS feeds and check files stored on S3'
Policies:
- arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy
- DynamoDBReadPolicy:
TableName: !Ref rssfeed
- S3ReadPolicy:
BucketName: !Ref PublicJsonBucket
MemorySize: 256
Timeout: 30
Environment:
Variables:
algolia_app: !Ref AlgoliaApp
algolia_apikey: !Ref AlgoliaApikey
algolia_index: !Ref AlgoliaIndex
dynamo_region: !Ref 'AWS::Region'
dynamo_table: !Ref rssfeed
from_email: !Ref SourceEmail
to_email: !Ref DestEmail
s3_bucket: !Ref PublicJsonBucket
storepublics3: !Ref StorePublicS3
send_mail: !Ref SendEmails
enable_algolia: !Ref EnableAlgolia
Tracing: Active
ReservedConcurrentExecutions: 1
Layers:
- !Ref lambdalayer
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:14"
# refresh pagecount stored in dynamodb using a manual lambda invoke
pagecount:
Type: 'AWS::Serverless::Function'
Properties:
Handler: pagecount.handler
Runtime: python3.8
CodeUri: lambda-pagecount/
Description: 'Retrieve the total article count for blogs stored in DynamoDB'
Policies:
- arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy
- DynamoDBCrudPolicy:
TableName: !Ref rssfeed
MemorySize: 256
Timeout: 30
Environment:
Variables:
dynamo_region: !Ref 'AWS::Region'
dynamo_table: !Ref rssfeed
POWERTOOLS_SERVICE_NAME: rssgetpagecount
POWERTOOLS_TRACE_DISABLED: "false"
Tracing: Active
ReservedConcurrentExecutions: 1
Layers:
- !Ref lambdalayer
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:14"
# create lambda layer with dependencies
lambdalayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: rsslayer
Description: python3 dependencies for XRay, BeautifulSoup4, feedparser and requests
ContentUri: lambda-layer/
CompatibleRuntimes:
- python3.8
LicenseInfo: 'MIT-0'
RetentionPolicy: Delete
Metadata:
BuildMethod: python3.8
# dynamodb table for blog articles
rssfeed:
Type: 'AWS::DynamoDB::Table'
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: guid
AttributeType: S
- AttributeName: timest
AttributeType: N
- AttributeName: visible
AttributeType: S
- AttributeName: blogsource
AttributeType: S
KeySchema:
- AttributeName: guid
KeyType: HASH
- AttributeName: timest
KeyType: RANGE
GlobalSecondaryIndexes:
- IndexName: visible
KeySchema:
- AttributeName: visible
KeyType: HASH
- AttributeName: timest
KeyType: RANGE
Projection:
ProjectionType: ALL
- IndexName: timest
KeySchema:
- AttributeName: blogsource
KeyType: HASH
- AttributeName: timest
KeyType: RANGE
Projection:
ProjectionType: ALL
# log group
rssblog:
Type: AWS::Logs::LogGroup
# public s3 bucket
PublicJsonBucket:
Type: AWS::S3::Bucket
# state machine to coordinate the workflow
blogstatemachine:
Type: AWS::Serverless::StateMachine
Properties:
Type: STANDARD
Tracing:
Enabled: true
DefinitionUri: statemachine/rssblog.asl.json
DefinitionSubstitutions:
rsscrawl: !GetAtt rsscrawl.Arn
rssgetfeed: !GetAtt rssgetfeed.Arn
Policies:
- LambdaInvokePolicy:
FunctionName: !Ref rsscrawl
- LambdaInvokePolicy:
FunctionName: !Ref rssgetfeed
- CloudWatchFullAccess
Logging:
IncludeExecutionData: true
Destinations:
- CloudWatchLogsLogGroup:
LogGroupArn: !GetAtt rssblog.Arn
Events:
ScheduledEventEvery15Min:
Type: Schedule
Properties:
Schedule: rate(15 minutes)
# graphql api role
GraphQLApiRole:
Condition: EnableAppSync
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: 'appsync.amazonaws.com'
Action: 'sts:AssumeRole'
Policies:
- PolicyName: CWLogs
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
- PolicyName: DDBRead
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:GetItem'
- 'dynamodb:Query'
- 'dynamodb:Scan'
Resource:
- !GetAtt rssfeed.Arn
- !Sub '${rssfeed.Arn}/*'
# create graphql api
GraphQLApi:
Condition: EnableAppSync
Type: 'AWS::AppSync::GraphQLApi'
Properties:
XrayEnabled: true
Name: !Ref 'AWS::StackName'
AuthenticationType: API_KEY
LogConfig:
CloudWatchLogsRoleArn: !GetAtt 'GraphQLApiRole.Arn'
FieldLogLevel: ALL
# define graphql schema
GraphQLSchema:
Condition: EnableAppSync
Type: 'AWS::AppSync::GraphQLSchema'
Properties:
DefinitionS3Location: './graphql/schema.graphql'
ApiId: !GetAtt 'GraphQLApi.ApiId'
# define dynamodb source
DDBDataSource:
Condition: EnableAppSync
Type: 'AWS::AppSync::DataSource'
Properties:
Type: AMAZON_DYNAMODB
ServiceRoleArn: !GetAtt 'GraphQLApiRole.Arn'
ApiId: !GetAtt 'GraphQLApi.ApiId'
Name: ddbsourcce
DynamoDBConfig:
TableName: !Ref rssfeed
AwsRegion: !Ref 'AWS::Region'
# create appsync api key
ApiKey:
Condition: EnableAppSync
Type: 'AWS::AppSync::ApiKey'
Properties:
ApiId: !GetAtt 'GraphQLApi.ApiId'
# create per blogsource resolver for appsync
BlogSourceResolver:
Condition: EnableAppSync
Type: 'AWS::AppSync::Resolver'
Properties:
TypeName: Query
DataSourceName: !GetAtt 'DDBDataSource.Name'
RequestMappingTemplateS3Location: './graphql/QueryDdbByBlogsourceAndTimest-request.vtl'
ResponseMappingTemplateS3Location: './graphql/QueryDdbByBlogsourceAndTimest-response.vtl'
ApiId: !GetAtt 'GraphQLApi.ApiId'
FieldName: QueryDdbByBlogsourceAndTimest
# create visible blogs resolver for appsync
VisibleResolver:
Condition: EnableAppSync
Type: 'AWS::AppSync::Resolver'
Properties:
TypeName: Query
DataSourceName: !GetAtt 'DDBDataSource.Name'
RequestMappingTemplateS3Location: './graphql/QueryDdbByVisibleAndTimest-request.vtl'
ResponseMappingTemplateS3Location: './graphql/QueryDdbByVisibleAndTimest-response.vtl'
ApiId: !GetAtt 'GraphQLApi.ApiId'
FieldName: QueryDdbByVisibleAndTimest
# create single article resolver for appsync
SingleBlogResolver:
Condition: EnableAppSync
Type: 'AWS::AppSync::Resolver'
Properties:
TypeName: Query
DataSourceName: !GetAtt 'DDBDataSource.Name'
RequestMappingTemplateS3Location: './graphql/QueryDdbGetDetailText-request.vtl'
ResponseMappingTemplateS3Location: './graphql/QueryDdbGetDetailText-response.vtl'
ApiId: !GetAtt 'GraphQLApi.ApiId'
FieldName: QueryDdbGetDetailText
# create page count resolver per blog for appsync
PerBlogPageCountResolver:
Condition: EnableAppSync
Type: 'AWS::AppSync::Resolver'
Properties:
TypeName: Query
DataSourceName: !GetAtt 'DDBDataSource.Name'
RequestMappingTemplateS3Location: './graphql/QueryDdbItemCountPerBlog-request.vtl'
ResponseMappingTemplateS3Location: './graphql/QueryDdbItemCountPerBlog-response.vtl'
ApiId: !GetAtt 'GraphQLApi.ApiId'
FieldName: QueryDdbItemCountPerBlog
# create page count resolver for all blogs appsync
AllBlogsPageCountResolver:
Condition: EnableAppSync
Type: 'AWS::AppSync::Resolver'
Properties:
TypeName: Query
DataSourceName: !GetAtt 'DDBDataSource.Name'
RequestMappingTemplateS3Location: './graphql/QueryDdbItemCountAll-request.vtl'
ResponseMappingTemplateS3Location: './graphql/QueryDdbItemCountAll-response.vtl'
ApiId: !GetAtt 'GraphQLApi.ApiId'
FieldName: QueryDdbItemCountAll
# print the url of the state machine and graphql details
Outputs:
StateMachineURL:
Value: !Sub 'https://${AWS::Region}.console.aws.amazon.com/states/home?region=${AWS::Region}#/statemachines/view/${blogstatemachine}'