-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandler.py
138 lines (111 loc) · 4.74 KB
/
handler.py
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
import os
import json
import boto3
import decimal
import datetime
check_last_result = {}
check_refresh_seconds = 300 # 5 minutes
check_last_update = datetime.datetime.now()
def handler_name(event, context):
return get_ec2_recovery_stats()
def get_ec2_recovery_stats():
global check_last_result
global check_refresh_seconds
global check_last_update
if os.environ.get('CHECK_REFRESH_SECONDS'):
check_refresh_seconds = float(os.environ.get('CHECK_REFRESH_SECONDS'))
elapsed_seconds = (datetime.datetime.now() - check_last_update).total_seconds()
if len(check_last_result) == 0 or elapsed_seconds > check_refresh_seconds:
check_last_update = datetime.datetime.now()
check_last_result = refresh_ec2_recovery_stats(check_last_update)
return check_last_result
def refresh_ec2_recovery_stats(check_last_update):
check_account_id = boto3.client('sts').get_caller_identity()['Account']
check_region_code = boto3.session.Session().region_name
running_instances = list_running_instances()
auto_scaling_instances = list_auto_scaling_instances()
alarm_instances = list_alarm_instances(auto_scaling_instances)
instance_counts = {
'running_instance_count': len(running_instances),
'auto_scaling_group_instance_count': len(auto_scaling_instances),
'cloud_watch_alarm_instance_count': len(alarm_instances)
}
try:
decimal.getcontext().prec = 3
overall_recovery_ratio = decimal.Decimal(len(alarm_instances) + len(auto_scaling_instances)) / decimal.Decimal(len(running_instances))
auto_scaling_ratio = decimal.Decimal(len(auto_scaling_instances)) / decimal.Decimal(len(running_instances))
alarm_recovery_ratio = decimal.Decimal(len(alarm_instances)) / decimal.Decimal(len(running_instances))
except:
overall_recovery_ratio = 0.0
auto_scaling_ratio = 0.0
alarm_recovery_ratio = 0.0
recovery_ratios = {
'overall_recovery_ratio': overall_recovery_ratio,
'auto_scaling_group_recovery_ratio': auto_scaling_ratio,
'cloud_watch_alarm_recovery_ratio': alarm_recovery_ratio
}
body = {
'check_status_code': 200,
'check_account_id': check_account_id,
'check_region_code': check_region_code,
'check_last_update': check_last_update,
'ec2_instance_counts': instance_counts,
'ec2_recovery_ratios': recovery_ratios
}
return json.dumps(body, indent=3, sort_keys=True, default=default_formatter)
def list_running_instances():
client = boto3.client('ec2')
result = client.describe_instances(
Filters=[{
'Name': 'instance-state-name',
'Values': ['running']}],
MaxResults=1000
)
while 'NextToken' in result:
next_result = client.describe_instances(
Filters=[{
'Name': 'instance-state-name',
'Values': ['running']}],
MaxResults=1000,
NextToken=result['NextToken']
)
next_result['Reservations'].extend(result['Reservations'])
result = next_result
instance_list = []
for reservation in (result['Reservations']):
for instance in reservation['Instances']:
instance_list.append(instance['InstanceId'])
return instance_list
def list_auto_scaling_instances():
client = boto3.client('autoscaling')
result = client.describe_auto_scaling_groups()
while 'NextToken' in result:
next_result = client.describe_auto_scaling_groups(NextToken=result['NextToken'])
next_result['AutoScalingGroups'].extend(result['AutoScalingGroups'])
result = next_result
instance_list = []
for group in (result['AutoScalingGroups']):
for instance in group['Instances']:
if instance['InstanceId'] not in instance_list:
instance_list.append(instance['InstanceId'])
return instance_list
def list_alarm_instances(ignore_list):
client = boto3.client('cloudwatch')
result = client.describe_alarms()
while 'NextToken' in result:
next_result = client.describe_alarms(NextToken=result['NextToken'])
next_result['MetricAlarms'].extend(result['MetricAlarms'])
result = next_result
instance_list = []
for alarm in (result['MetricAlarms']):
if 'StatusCheckFailed' in alarm['MetricName']:
for dimension in alarm['Dimensions']:
if dimension['Value'] not in instance_list and dimension['Value'] not in ignore_list:
instance_list.append(dimension['Value'])
return instance_list
def default_formatter(obj):
if isinstance(obj, decimal.Decimal):
return float(obj)
elif isinstance(obj, datetime.datetime):
return obj.isoformat()
raise TypeError