-
Notifications
You must be signed in to change notification settings - Fork 0
/
Slackbot.py
139 lines (115 loc) · 5.54 KB
/
Slackbot.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
139
import os
from slackclient import SlackClient
import boto3
from flask import abort, Flask, jsonify, request
from zappa.async import task
import json
app = Flask(__name__)
# instantiate Slack client
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))
# Set up cloudwatch client to pull metrics
cw = boto3.client('cloudwatch',
aws_access_key_id=os.environ.get('EXTERNAL_ACCESS_KEY_ID'),
aws_secret_access_key=os.environ.get('EXTERNAL_SECRET_ACCESS_KEY'),
region_name="us-east-1")
# specific metrics to pull, may move into external file to call from
cpu_metric = '{"metrics":[["AWS/EC2","CPUUtilization","AutoScalingGroupName",' \
'"AUTOSCALE GROUP NAME"]],"view":"timeSeries","stacked":false,' \
'"period":300,"yAxis":{"left":{"min":0}},"title": "Autoscaling CPU Utilization", "start":"-PT1H",' \
'"end":"P0D", "timezone":"-0800"} '
instance_metric = '{"metrics":[["AWS/AutoScaling","GroupTotalInstances","AutoScalingGroupName",' \
'"AUTOSCALE GROUP NAME",{"period":60}]],"view":"timeSeries","stacked":false,' \
'"period":300,"yAxis":{"left":{"min":0}}, "title": "Total Instances", "start":"-PT1H","end":"P0D",' \
'"timezone":"-0800"} '
'-----------------------------------------------------------------------------------------------------'
# checks if the request came from our slack and has the correct token.
def is_request_valid(info):
is_token_valid = info.form['token'] == os.environ['SLACK_VERIFICATION_TOKEN']
is_team_id_valid = info.form['team_id'] == os.environ['SLACK_TEAM_ID']
return is_token_valid and is_team_id_valid
# Used to find the writer database in a reader/writer RDS combo, to pull info on the writer one
def find_rds():
db_metric_1 = '{"metrics":[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",' \
'"DATABASE 1 NAME"]],"view":"timeSeries","stacked":false,' \
'"period":300,"yAxis":{"left":{"min":0}},"title": "DB CPU Utilization", "start":"-PT1H","end":"P0D",' \
'"timezone":"-0800"} '
db_metric_2 = '{"metrics":[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",' \
'"DATABASE 2 NAME"]],"view":"timeSeries","stacked":false,' \
'"period":300,"yAxis":{"left":{"min":0}},"title": "DB CPU Utilization", "start":"-PT1H","end":"P0D",' \
'"timezone":"-0800"} '
rds = boto3.client('rds',aws_access_key_id=os.environ.get('EXTERNAL_ACCESS_KEY_ID'),
aws_secret_access_key=os.environ.get('EXTERNAL_SECRET_ACCESS_KEY'),
region_name="us-east-1")
for member in rds.describe_db_clusters()['DBClusters'][0]['DBClusterMembers']:
if member['IsClusterWriter']:
server = member['DBInstanceIdentifier']
if server == "SERVER NAME 1":
return db_metric_1
elif server == "SERVER NAME 2":
return db_metric_2
'--------------------------------------------------------------------------------------------------------------'
# zappa async task to pull metric images as same time as normal response
@task
def pull_metric(metric, channel, comment):
metrics = {
'server': [cpu_metric, "Autoscaling CPU Usage for past Hour"],
'db': [find_rds(), "Database CPU Usage for past Hour"],
'instances': [instance_metric, "Total Autoscaling Instances"]
}
slack_client.api_call(
"files.upload",
initial_comment=comment,
channels=channel,
file=cw.get_metric_widget_image(MetricWidget=metrics[metric][0])['MetricWidgetImage'],
title=metrics[metric][1]
)
return
# Default response if there is a command it doesn't understand
@task
def default_response(user, channel):
slack_client.api_call(
"chat.postEphemeral",
user=user,
channel=channel,
text='Not a valid command. Please call /info help for a list of commands'
)
return
# zappa task for /help to return values
@task
def info_help(user, channel):
message = json.dumps([{"text": "• `/info server` - Displays server CPU for past hour \n "
"• `/info db` - Displays database CPU for past hour \n "
"• `/info instances` - Shows total instances running\n ",
"color": "#3AA3E3", "mrkdwn_in": ['text']
}])
slack_client.api_call(
"chat.postEphemeral",
user=user,
channel=channel,
attachments=message,
mrkdwn=True
)
return
# parses arguments passed to bot
@task
def event_handler(info):
command = info['text']
comment = "Command: `/info {}` \nUser: <@{}>".format(command, info['user_id'])
commands = {
'server': lambda: pull_metric('server', info['channel_id'], comment),
'db': lambda: pull_metric('db', info['channel_id'], comment),
'instances': lambda: pull_metric('instances', info['channel_id'], comment),
'help': lambda: info_help(info['user_id'], info['channel_id'])
}
commands.get(command, lambda: default_response(info['user_id'], info['channel_id']))()
return
'---------------------------------------------------------------------------------------------------------------'
# main function, checks request and passes to event_handler, responds immediately
@app.route('/', methods=['POST'])
def main():
if not is_request_valid(request):
abort(400)
event_handler(request.form)
return jsonify(text='Got it! Please wait!')
if __name__ == '__main__':
app.run()