cfn_monitor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,428 @@
1
+ templates:
2
+ HttpCheck:
3
+ EndpointAvailable:
4
+ AlarmActions: crit
5
+ Namespace: HttpCheck
6
+ ComparisonOperator: LessThanThreshold
7
+ Dimensions: [ { Name: 'Endpoint', Value: { 'Fn::Sub': ['${endpoint}', {'env': { Ref: 'EnvironmentName' } } ] } } ]
8
+ Statistic: Maximum
9
+ Threshold: 1
10
+ Period: 60
11
+ EvaluationPeriods: 2
12
+ MetricName: Available
13
+ EndpointTimeTaken:
14
+ AlarmActions: crit
15
+ Namespace: HttpCheck
16
+ ComparisonOperator: GreaterThanThreshold
17
+ Dimensions: [ { Name: 'Endpoint', Value: { 'Fn::Sub': ['${endpoint}', {'env': { Ref: 'EnvironmentName' } } ] } } ]
18
+ Statistic: Minimum
19
+ Threshold: 1000
20
+ Period: 300
21
+ EvaluationPeriods: 1
22
+ MetricName: TimeTaken
23
+ EndpointStatusCodeMatch:
24
+ AlarmActions: crit
25
+ Namespace: HttpCheck
26
+ ComparisonOperator: LessThanThreshold
27
+ Dimensions: [ { Name: 'Endpoint', Value: { 'Fn::Sub': ['${endpoint}', {'env': { Ref: 'EnvironmentName' } } ] } } ]
28
+ Statistic: Maximum
29
+ Threshold: 1
30
+ Period: 60
31
+ EvaluationPeriods: 2
32
+ MetricName: StatusCodeMatch
33
+ HttpCheckBody:
34
+ EndpointResponseBodyRegexMatch:
35
+ AlarmActions: crit
36
+ Namespace: HttpCheck
37
+ ComparisonOperator: LessThanThreshold
38
+ Dimensions: [ { Name: 'Endpoint', Value: { 'Fn::Sub': ['${endpoint}', {'env': { Ref: 'EnvironmentName' } } ] } } ]
39
+ Statistic: Maximum
40
+ Threshold: 1
41
+ Period: 60
42
+ EvaluationPeriods: 2
43
+ MetricName: ResponseBodyRegexMatch
44
+ Services:
45
+ FailedService:
46
+ AlarmActions: warn
47
+ Namespace: ServiceChecks
48
+ ComparisonOperator: GreaterThanThreshold
49
+ Dimensions: [ { Name: 'Service', Value: '${resource}' }, { Name: 'Environment', Value: { Ref: 'EnvironmentName' } } ]
50
+ Statistic: Maximum
51
+ Threshold: 0
52
+ Period: 60
53
+ EvaluationPeriods: 2
54
+ MetricName: Failed_Service
55
+ AlarmDescription: { 'Fn::Join': [ ' ', [ Ref: 'MonitoredStack', { 'Fn::Sub': ['${resource}', {'env': { Ref: 'EnvironmentName' } } ] }, '${alarmName}' ] ] }
56
+ TreatMissingData: notBreaching
57
+ # FailedSSMAgent:
58
+ # AlarmActions: warn
59
+ # Namespace: ServiceChecks
60
+ # ComparisonOperator: GreaterThanThreshold
61
+ # Dimensions: [ { Name: 'Environment', Value: { Ref: 'EnvironmentName' } } ]
62
+ # Statistic: Maximum
63
+ # Threshold: 0
64
+ # Period: 60
65
+ # EvaluationPeriods: 2
66
+ # MetricName: Failed_SSM_Agent
67
+ # AlarmDescription: { 'Fn::Join': [ ' ', [ Ref: 'MonitoredStack', { 'Fn::Sub': ['${resource}', {'env': { Ref: 'EnvironmentName' } } ] }, '${alarmName}' ] ] }
68
+ # TreatMissingData: notBreaching
69
+ Nrpe:
70
+ Warn:
71
+ AlarmActions: warn
72
+ Namespace: NRPE
73
+ ComparisonOperator: GreaterThanThreshold
74
+ Dimensions: [ { Name: 'Host', Value: { 'Fn::Join': [ '-', [ { 'Fn::Sub': ['${env}', {'env': { Ref: 'EnvironmentName' } } ] }, '${resource}' ] ] } } ]
75
+ Statistic: Maximum
76
+ Threshold: 0
77
+ Period: 60
78
+ EvaluationPeriods: 2
79
+ MetricName: ${cmd}
80
+ TreatMissingData: breaching
81
+ AlarmDescription: { 'Fn::Join': [ ' ', [ Ref: 'MonitoredStack', { 'Fn::Sub': ['${resource}', {'env': { Ref: 'EnvironmentName' } } ] }, '${templateName}', '${cmd}', '${alarmName}' ] ] }
82
+ Crit:
83
+ AlarmActions: crit
84
+ Namespace: NRPE
85
+ ComparisonOperator: GreaterThanThreshold
86
+ Dimensions: [ { Name: 'Host', Value: { 'Fn::Join': [ '-', [ { 'Fn::Sub': ['${env}', {'env': { Ref: 'EnvironmentName' } } ] }, '${resource}' ] ] } } ]
87
+ Statistic: Maximum
88
+ Threshold: 1
89
+ Period: 60
90
+ EvaluationPeriods: 2
91
+ MetricName: ${cmd}
92
+ AlarmDescription: { 'Fn::Join': [ ' ', [ Ref: 'MonitoredStack', { 'Fn::Sub': ['${resource}', {'env': { Ref: 'EnvironmentName' } } ] }, '${templateName}', '${cmd}', '${alarmName}' ] ] }
93
+ LambdaMetrics: # Lambda Functions deployed with a Function Name
94
+ Errors:
95
+ AlarmActions: crit
96
+ Namespace: AWS/Lambda
97
+ ComparisonOperator: GreaterThanThreshold
98
+ Dimensions: [ { Name: 'FunctionName', Value: { 'Fn::Sub': ['${metric}', {'env': { Ref: 'EnvironmentName' } } ] } } ]
99
+ Statistic: Average
100
+ Threshold: 0.5
101
+ Period: 60
102
+ EvaluationPeriods: 5
103
+ MetricName: Errors
104
+ TreatMissingData: notBreaching
105
+ ElasticLoadBalancer: # AWS::ElasticLoadBalancing::LoadBalancer
106
+ HealthyHosts:
107
+ AlarmActions: crit
108
+ Namespace: AWS/ELB
109
+ MetricName: HealthyHostCount
110
+ ComparisonOperator: LessThanThreshold
111
+ DimensionsName: LoadBalancerName
112
+ Statistic: Minimum
113
+ Threshold: 2
114
+ Threshold.development: 1
115
+ EvaluationPeriods: 1
116
+ TreatMissingData: notBreaching
117
+ UnHealthyHosts:
118
+ AlarmActions: warn
119
+ Namespace: AWS/ELB
120
+ MetricName: UnHealthyHostCount
121
+ ComparisonOperator: GreaterThanThreshold
122
+ DimensionsName: LoadBalancerName
123
+ Statistic: Maximum
124
+ Threshold: 0
125
+ EvaluationPeriods: 10
126
+ TreatMissingData: notBreaching
127
+ ApplicationELBTargetGroup: # AWS::ElasticLoadBalancingV2::TargetGroup / AWS::ElasticLoadBalancingV2::LoadBalancer where type: application
128
+ HealthyHosts:
129
+ AlarmActions: crit
130
+ Namespace: AWS/ApplicationELB
131
+ MetricName: HealthyHostCount
132
+ ComparisonOperator: LessThanThreshold
133
+ DimensionsName: TargetGroup/LoadBalancer
134
+ Statistic: Minimum
135
+ Threshold: 2
136
+ Threshold.development: 1
137
+ EvaluationPeriods: 1
138
+ TreatMissingData: breaching
139
+ UnHealthyHosts:
140
+ AlarmActions: warn
141
+ Namespace: AWS/ApplicationELB
142
+ MetricName: UnHealthyHostCount
143
+ ComparisonOperator: GreaterThanThreshold
144
+ DimensionsName: TargetGroup/LoadBalancer
145
+ Statistic: Maximum
146
+ Threshold: 0
147
+ EvaluationPeriods: 10
148
+ TreatMissingData: notBreaching
149
+ TargetResponseTime:
150
+ AlarmActions: crit
151
+ Namespace: AWS/ApplicationELB
152
+ MetricName: TargetResponseTime
153
+ ComparisonOperator: GreaterThanThreshold
154
+ DimensionsName: TargetGroup/LoadBalancer
155
+ Statistic: Average
156
+ Threshold: 5
157
+ EvaluationPeriods: 5
158
+ TreatMissingData: notBreaching
159
+ NetworkELBTargetGroup: # AWS::ElasticLoadBalancingV2::TargetGroup / AWS::ElasticLoadBalancingV2::LoadBalancer where type: network
160
+ HealthyHosts:
161
+ AlarmActions: crit
162
+ Namespace: AWS/NetworkELB
163
+ MetricName: HealthyHostCount
164
+ ComparisonOperator: LessThanThreshold
165
+ DimensionsName: TargetGroup/LoadBalancer
166
+ Statistic: Minimum
167
+ Threshold: 2
168
+ Threshold.development: 1
169
+ EvaluationPeriods: 1
170
+ TreatMissingData: breaching
171
+ UnHealthyHosts:
172
+ AlarmActions: warn
173
+ Namespace: AWS/NetworkELB
174
+ MetricName: UnHealthyHostCount
175
+ ComparisonOperator: GreaterThanThreshold
176
+ DimensionsName: TargetGroup/LoadBalancer
177
+ Statistic: Maximum
178
+ Threshold: 0
179
+ EvaluationPeriods: 10
180
+ TreatMissingData: notBreaching
181
+ TargetResponseTime:
182
+ AlarmActions: crit
183
+ Namespace: AWS/NetworkELB
184
+ MetricName: TargetResponseTime
185
+ ComparisonOperator: GreaterThanThreshold
186
+ DimensionsName: TargetGroup/LoadBalancer
187
+ Statistic: Average
188
+ Threshold: 5
189
+ EvaluationPeriods: 5
190
+ TreatMissingData: notBreaching
191
+ AutoScalingGroup: # AWS::AutoScaling::AutoScalingGroup
192
+ CPUUtilizationHighBase:
193
+ AlarmActions: warn
194
+ Namespace: AWS/EC2
195
+ MetricName: CPUUtilization
196
+ ComparisonOperator: GreaterThanThreshold
197
+ DimensionsName: AutoScalingGroupName
198
+ Statistic: Minimum
199
+ Threshold: 75
200
+ EvaluationPeriods: 60
201
+ TreatMissingData: notBreaching
202
+ StatusCheckFailed:
203
+ AlarmActions: warn
204
+ Namespace: AWS/EC2
205
+ MetricName: StatusCheckFailed
206
+ ComparisonOperator: GreaterThanThreshold
207
+ DimensionsName: AutoScalingGroupName
208
+ Statistic: Maximum
209
+ Threshold: 0
210
+ EvaluationPeriods: 10
211
+ Ec2Instance: # AWS::EC2::Instance
212
+ CPUUtilizationHigh:
213
+ AlarmActions: crit
214
+ Namespace: AWS/EC2
215
+ MetricName: CPUUtilization
216
+ ComparisonOperator: GreaterThanThreshold
217
+ DimensionsName: InstanceId
218
+ Statistic: Minimum
219
+ Threshold: 90
220
+ EvaluationPeriods: 10
221
+ StatusCheckFailed:
222
+ AlarmActions: crit
223
+ Namespace: AWS/EC2
224
+ MetricName: StatusCheckFailed
225
+ ComparisonOperator: GreaterThanThreshold
226
+ DimensionsName: InstanceId
227
+ Statistic: Maximum
228
+ Threshold: 0
229
+ EvaluationPeriods: 10
230
+ RDSInstance: # AWS::RDS::DBInstance
231
+ FreeStorageSpaceCrit:
232
+ AlarmActions: crit
233
+ Namespace: AWS/RDS
234
+ MetricName: FreeStorageSpace
235
+ ComparisonOperator: LessThanThreshold
236
+ DimensionsName: DBInstanceIdentifier
237
+ Statistic: Minimum
238
+ Threshold: 50000000000
239
+ Threshold.development: 10000000000
240
+ EvaluationPeriods: 1
241
+ FreeStorageSpaceTask:
242
+ AlarmActions: task
243
+ Namespace: AWS/RDS
244
+ MetricName: FreeStorageSpace
245
+ ComparisonOperator: LessThanThreshold
246
+ DimensionsName: DBInstanceIdentifier
247
+ Statistic: Minimum
248
+ Threshold: 100000000000
249
+ Threshold.development: 20000000000
250
+ EvaluationPeriods: 1
251
+ CPUUtilizationHighSpike:
252
+ AlarmActions: crit
253
+ Namespace: AWS/RDS
254
+ MetricName: CPUUtilization
255
+ ComparisonOperator: GreaterThanThreshold
256
+ DimensionsName: DBInstanceIdentifier
257
+ Statistic: Minimum
258
+ Threshold: 95
259
+ EvaluationPeriods: 10
260
+ CPUUtilizationHighBase:
261
+ AlarmActions: warn
262
+ Namespace: AWS/RDS
263
+ MetricName: CPUUtilization
264
+ ComparisonOperator: GreaterThanThreshold
265
+ DimensionsName: DBInstanceIdentifier
266
+ Statistic: Minimum
267
+ Threshold: 75
268
+ EvaluationPeriods: 60
269
+ DBCluster: # AWS::RDS::DBCluster
270
+ CPUUtilizationHighSpike:
271
+ AlarmActions: crit
272
+ Namespace: AWS/RDS
273
+ MetricName: CPUUtilization
274
+ ComparisonOperator: GreaterThanThreshold
275
+ DimensionsName: DBClusterIdentifier
276
+ Statistic: Minimum
277
+ Threshold: 95
278
+ EvaluationPeriods: 10
279
+ CPUUtilizationHighBase:
280
+ AlarmActions: warn
281
+ Namespace: AWS/RDS
282
+ MetricName: CPUUtilization
283
+ ComparisonOperator: GreaterThanThreshold
284
+ DimensionsName: DBClusterIdentifier
285
+ Statistic: Minimum
286
+ Threshold: 75
287
+ EvaluationPeriods: 60
288
+ RedshiftCluster: # AWS::Redshift::Cluster
289
+ CPUUtilizationHighSpike:
290
+ AlarmActions: crit
291
+ Namespace: AWS/Redshift
292
+ MetricName: CPUUtilization
293
+ ComparisonOperator: GreaterThanThreshold
294
+ DimensionsName: ClusterIdentifier
295
+ Statistic: Minimum
296
+ Threshold: 95
297
+ EvaluationPeriods: 10
298
+ CPUUtilizationHighBase:
299
+ AlarmActions: warn
300
+ Namespace: AWS/Redshift
301
+ MetricName: CPUUtilization
302
+ ComparisonOperator: GreaterThanThreshold
303
+ DimensionsName: ClusterIdentifier
304
+ Statistic: Minimum
305
+ Threshold: 75
306
+ EvaluationPeriods: 60
307
+ UnHealthyCluster:
308
+ AlarmActions: crit
309
+ Namespace: AWS/Redshift
310
+ MetricName: HealthStatus
311
+ ComparisonOperator: GreaterThanThreshold
312
+ DimensionsName: ClusterIdentifier
313
+ Statistic: Maximum
314
+ Threshold: 0
315
+ EvaluationPeriods: 10
316
+ TreatMissingData: notBreaching
317
+ ECSCluster: # AWS::ECS::Cluster
318
+ MemoryUtilizationWarn:
319
+ AlarmActions: warn
320
+ Namespace: AWS/ECS
321
+ MetricName: MemoryUtilization
322
+ ComparisonOperator: GreaterThanThreshold
323
+ DimensionsName: ClusterName
324
+ Statistic: Maximum
325
+ Threshold: 75
326
+ EvaluationPeriods: 10
327
+ MemoryUtilizationCrit:
328
+ AlarmActions: crit
329
+ Namespace: AWS/ECS
330
+ MetricName: MemoryUtilization
331
+ ComparisonOperator: GreaterThanThreshold
332
+ DimensionsName: ClusterName
333
+ Statistic: Maximum
334
+ Threshold: 95
335
+ EvaluationPeriods: 10
336
+ CPUUtilizationHighBase:
337
+ AlarmActions: warn
338
+ Namespace: AWS/ECS
339
+ MetricName: CPUUtilization
340
+ ComparisonOperator: GreaterThanThreshold
341
+ DimensionsName: ClusterName
342
+ Statistic: Minimum
343
+ Threshold: 75
344
+ EvaluationPeriods: 10
345
+ ECSService: #AWS::ECS::Service
346
+ UnHealthyTask:
347
+ AlarmActions: crit
348
+ MetricName: MemoryUtilization
349
+ Namespace: AWS/ECS
350
+ Statistic: SampleCount
351
+ DimensionsName: ServiceName/ClusterName
352
+ Period: 60
353
+ EvaluationPeriods: 10
354
+ DatapointsToAlarm: 8
355
+ Threshold: 0.0
356
+ ComparisonOperator: LessThanOrEqualToThreshold
357
+ TreatMissingData: breaching
358
+ ECSTasks:
359
+ UnHealthyTaskWarn:
360
+ AlarmActions: warn
361
+ MetricName: MemoryUtilization
362
+ Namespace: AWS/ECS
363
+ Statistic: SampleCount
364
+ DimensionsName: ServiceName/ClusterName
365
+ Period: 60
366
+ EvaluationPeriods: 10
367
+ DatapointsToAlarm: 10
368
+ Threshold: 1.0
369
+ ComparisonOperator: LessThanOrEqualToThreshold
370
+ TreatMissingData: breaching
371
+ ElastiCacheReplicationGroup: # AWS::ElastiCache::ReplicationGroup
372
+ FreeableMemoryWarn:
373
+ AlarmActions: warn
374
+ Namespace: AWS/ElastiCache
375
+ MetricName: FreeableMemory
376
+ ComparisonOperator: LessThanThreshold
377
+ DimensionsName: CacheClusterId
378
+ Statistic: Maximum
379
+ Threshold: 100000000
380
+ EvaluationPeriods: 10
381
+ CPUUtilizationHighBase:
382
+ AlarmActions: warn
383
+ Namespace: AWS/ElastiCache
384
+ MetricName: CPUUtilization
385
+ ComparisonOperator: GreaterThanThreshold
386
+ DimensionsName: CacheClusterId
387
+ Statistic: Minimum
388
+ Threshold: 75
389
+ EvaluationPeriods: 10
390
+ ElasticFileSystem: # AWS::EFS::FileSystem
391
+ PercentIOLimitHigh:
392
+ AlarmActions: crit
393
+ Namespace: AWS/EFS
394
+ MetricName: PercentIOLimit
395
+ ComparisonOperator: GreaterThanThreshold
396
+ DimensionsName: FileSystemId
397
+ Statistic: Minimum
398
+ Threshold: 90
399
+ EvaluationPeriods: 5
400
+ ApiGateway: #AWS:ApiGateway
401
+ ApiEndpoint5xx:
402
+ AlarmActions: crit
403
+ Namespace: AWS/ApiGateway
404
+ MetricName: 5XXError
405
+ ComparisonOperator: GreaterThanThreshold
406
+ DimensionsName: ApiName
407
+ Statistic: Sum
408
+ Threshold: 5
409
+ EvaluationPdyneriods: 2
410
+ DynamoDBTable: #AWS::DynamoDB::Table
411
+ DynamoDBReadUsage:
412
+ AlarmActions: warn
413
+ Namespace: AWS/DynamoDB
414
+ MetricName: ConsumedReadCapacityUnits
415
+ ComparisonOperator: GreaterThanThreshold
416
+ DimensionsName: TableName
417
+ Statistic: Sum
418
+ Threshold: 80
419
+ EvaluationPeriods: 2
420
+ DynamoDBWriteUsage:
421
+ AlarmActions: warn
422
+ Namespace: AWS/DynamoDB
423
+ MetricName: ConsumedWriteCapacityUnits
424
+ ComparisonOperator: GreaterThanThreshold
425
+ DimensionsName: TableName
426
+ Statistic: Sum
427
+ Threshold: 80
428
+ EvaluationPeriods: 2
data/lib/ext/alarms.rb ADDED
@@ -0,0 +1,33 @@
1
+ def replace_vars(hash,find,replace)
2
+ if hash.is_a?(Hash)
3
+ hash.each do |k, v|
4
+ replace_vars(v,find,replace)
5
+ end
6
+ elsif hash.is_a?(Array)
7
+ hash.each do |e|
8
+ replace_vars(e,find,replace)
9
+ end
10
+ elsif hash.is_a?(String) && hash == find
11
+ hash.replace replace
12
+ end
13
+ hash
14
+ end
15
+
16
+ def create_param_mappings(params,template_envs,alarmHash)
17
+ mappings = {}
18
+ params.each do |key,value|
19
+ if !key.include? '.'
20
+ if [String, Integer, Float, Fixnum, TrueClass].member?(value.class)
21
+ mappings[key] = {}
22
+ template_envs.each do |env|
23
+ if !params["#{key}.#{env}"].nil? && [String, Integer, Float, Fixnum, TrueClass].member?(params["#{key}.#{env}"].class)
24
+ mappings[key][env] = params["#{key}.#{env}"]
25
+ else
26
+ mappings[key][env] = value
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ Mapping("#{alarmHash}", mappings)
33
+ end
@@ -0,0 +1,39 @@
1
+ import json
2
+ import cfnresponse
3
+ import boto3
4
+ from botocore.exceptions import ClientError
5
+ import time
6
+
7
+ def getEnvironmentName(client,stackName):
8
+ time.sleep(5)
9
+ max_retries = 5
10
+ sleep_time = 1
11
+ for i in range(max_retries):
12
+ try:
13
+ response = client.describe_stacks(StackName=stackName)
14
+ except ClientError as e:
15
+ print e
16
+ time.sleep(sleep_time)
17
+ sleep_time += sleep_time
18
+ continue
19
+ else:
20
+ break
21
+ else:
22
+ return stackName
23
+ if 'Parameters' in response['Stacks'][0]:
24
+ for r in response['Stacks'][0]['Parameters']:
25
+ if r['ParameterKey'] == 'EnvironmentName':
26
+ return r['ParameterValue']
27
+ return stackName
28
+ else:
29
+ return stackName
30
+
31
+
32
+ def handler(event, context):
33
+ stackName = event['ResourceProperties']['StackName']
34
+ region = event['ResourceProperties']['Region']
35
+ client = boto3.client('cloudformation',region_name=region)
36
+
37
+ responseData = {}
38
+ responseData['EnvironmentName'] = getEnvironmentName(client,stackName)
39
+ cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
@@ -0,0 +1,67 @@
1
+ import json
2
+ import cfnresponse
3
+ import boto3
4
+ from botocore.exceptions import ClientError
5
+ import time
6
+
7
+ def findNestedStack(client,resource):
8
+ if len(resource) == 2:
9
+ return resource
10
+ else:
11
+ max_retries = 20
12
+ sleep_time = 1
13
+ for i in range(max_retries):
14
+ try:
15
+ response = client.list_stack_resources(StackName=resource[0])
16
+ except ClientError as e:
17
+ print e
18
+ time.sleep(sleep_time)
19
+ sleep_time += 1
20
+ continue
21
+ else:
22
+ break
23
+ else:
24
+ return
25
+ for r in response['StackResourceSummaries']:
26
+ if r['ResourceType'] == 'AWS::CloudFormation::Stack':
27
+ if r['LogicalResourceId'] == resource[1]:
28
+ resource[1] = r['PhysicalResourceId']
29
+ del resource[0]
30
+ return findNestedStack(client,resource)
31
+
32
+ def findResource(client,resource):
33
+ time.sleep(5)
34
+ if resource:
35
+ max_retries = 20
36
+ sleep_time = 1
37
+ for i in range(max_retries):
38
+ try:
39
+ paginator = client.get_paginator('list_stack_resources')
40
+ page_iterator = paginator.paginate(StackName=resource[0])
41
+ response = []
42
+ for page in page_iterator:
43
+ response = response + page['StackResourceSummaries']
44
+ except ClientError as e:
45
+ print e
46
+ time.sleep(sleep_time)
47
+ sleep_time += 1
48
+ continue
49
+ else:
50
+ break
51
+ else:
52
+ return
53
+ for r in response:
54
+ if r['LogicalResourceId'] == resource[1]:
55
+ return r['PhysicalResourceId']
56
+ else:
57
+ return
58
+
59
+ def handler(event, context):
60
+ resource = event['ResourceProperties']['LogicalResourceId'].split(".")
61
+ region = event['ResourceProperties']['Region']
62
+ client = boto3.client('cloudformation',region_name=region)
63
+
64
+ responseData = {}
65
+ responseData['PhysicalResourceId'] = findResource(client,findNestedStack(client,resource))
66
+ cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
67
+