Skip to content

Instantly share code, notes, and snippets.

@jg75
Created April 14, 2016 18:44
Show Gist options
  • Save jg75/eda66e53192c2c6404fbead8d8e23d8b to your computer and use it in GitHub Desktop.
Save jg75/eda66e53192c2c6404fbead8d8e23d8b to your computer and use it in GitHub Desktop.
from __future__ import print_function
import boto3
import botocore
import json
import logging
import urllib2
from base64 import b64decode
from datetime import datetime
# TODO cloudwatch stuff
"""
Before creating the Lambda service, some setup is required.
1. Create an encrypted key in AWS IAM and get the ARN.
2. Create a slack webhook and get the webhook URL.
3. Encrypt the slack webook URL without the protocol:
aws kms encrypt --key-id alias/slack --plaintext hooks.slack.com/etc
4. Create a role with the following policy for this lambda service:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1443036478000",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:<region name>:<account id>:key/<key>"
]
}
]
}
5. Create a list of dictionaries containing the site information and
escalation procedures, including the encrypted slack webhook URL.
[
{
"Name": "My Site",
"Url": "https://www.example.com/",
"ConfirmationText": "Welcome to My Site",
"CiphertextBlob": "<encrypted webhook URL>"
"SlackChannel": "#mychannel"
}
]
"""
def key_exists(s3_client, bucket, key):
try:
s3_client.head_object(Bucket=bucket, Key=key)
except botocore.exceptions.ClientError as e:
http_status_code = e.response['ResponseMetadata']['HTTPStatusCode']
if http_status_code == 404:
return False
else:
raise e
return True
def download_site_config(s3_client, bucket, key):
site_config = []
if key_exists(s3_client, bucket, key):
response = s3_client.get_object(
Bucket=bucket,
Key=key
)
site_config = json.loads(response['Body'].read())
return site_config
def decrypted_data(session, cipher_text_blob):
kms_client = session.client('kms')
cipher_text = b64decode(cipher_text_blob)
data = kms_client.decrypt(CiphertextBlob=cipher_text)
return data['Plaintext']
def send_slack_message(session, site_config):
webhook_url = "https://" + decrypted_data(
session, site_config['CiphertextBlob']
)
slack_message = json.dumps({
'channel': site_config['SlackChannel'],
'text': "%s (%s): Uptime Check Failed" % (
site_config['Name'],
site_config['Url']
),
'username': 'Uptime',
'icon_emoji': ':sos:'
})
request = urllib2.Request(webhook_url, slack_message)
logging.info(webhook_url)
logging.info(slack_message)
return
try:
response = urllib2.urlopen(request)
response.read()
except urllib2.HTTPError as e:
logging.error("Request Failed: %d %s" % (e.code, e.reason))
except urllib2.URLError as e:
logging.error("Request Failed: %s" % (e.reason))
def escalation_handler(site_config):
pass
def lambda_handler(event, context):
session = boto3.session.Session(region_name='us-east-1')
s3_client = session.client('s3')
bucket = 'amber-devops'
key = 'configs/devops/production/sites.json'
site_configs = download_site_config(s3_client, bucket, key)
logging.info("Uptime Check Started: %s" % event['time'])
for site_config in site_configs:
try:
request = urllib2.urlopen(site_config['Url'])
body = request.read().decode('utf8')
if site_config['ConfirmationText'] not in body:
raise Exception()
except:
send_slack_message(session, site_config)
logging.info("Uptime Check Finished: %s" % datetime.utcnow().isoformat())
logging.basicConfig(level=logging.INFO)
if __name__ == '__main__':
lambda_handler({'time': str(datetime.utcnow().isoformat())}, None)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment