Skip to content

Instantly share code, notes, and snippets.

@zircote
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zircote/7962d05091267f542727 to your computer and use it in GitHub Desktop.
Save zircote/7962d05091267f542727 to your computer and use it in GitHub Desktop.
Receive AWS/Notifications and fire an event into Salt Stack
from flask import Flask
from flask import request
import os
import logging
import json
log = logging.getLogger(__name__)
app = Flask(__name__)
AWS_CREDENTIALS = {
'access_key': None,
'secret_key': None,
}
try:
from boto import ec2
import salt.config
import salt.runner
import salt.utils.event
event = salt.utils.event.MasterEvent('/var/run/salt/master')
except ImportError as e:
log.trace('Failed to import a library: {0}'.format(e))
exit(2)
def _get_credentials():
if AWS_CREDENTIALS['access_key'] and AWS_CREDENTIALS['secret_key']:
return AWS_CREDENTIALS
access_key = os.environ.get('AWS_ACCESS_KEY') or os.environ.get('AWS_ACCESS_KEY_ID')
secret_key = os.environ.get('AWS_SECRET_KEY') or os.environ.get('AWS_SECRET_ACCESS_KEY')
if access_key and secret_key:
return {
'access_key': access_key,
'secret_key': secret_key, }
return AWS_CREDENTIALS
def _fallback():
"""
Fallback function for the depends decorator to replace a function with
"""
return '"boto" needs to be installed for this custom grain to exist'
def ec2_information(event_details):
credentials = _get_credentials()
try:
conn = ec2.connect_to_region(event_details['region'],
aws_access_key_id=credentials['access_key'],
aws_secret_access_key=credentials['secret_key'])
except:
if not (credentials['access_key'] and credentials['secret_key']):
log.error("%s: no AWS credentials found, see documentation for how to provide them.", __name__)
return None
else:
log.error("%s: invalid AWS credentials found, see documentation for how to provide them.", __name__)
return None
reservation = conn.get_all_reservations(instance_ids=[event_details['instance_id']])[0]
instance = reservation.instances.pop()
minion = instance.__dict__
if instance.private_dns_name is not None:
minion['minion_id'] = instance.private_dns_name.split('.')[0]
return minion
def recv_event(data):
data = json.loads(data)
data['Message'] = json.loads(data['Message'])
parts = data['Message']['AutoScalingGroupARN'].split(':')
event_details = {
'arn': ":".join([parts[0], parts[1], parts[2]]),
'region': parts[3],
'acct': parts[4],
'autoScalingGroup': parts[6],
'autoScalingGroupName': parts[7].split('/')[1],
'event': data['Message']['Event'],
'instance_id': data['Message']['EC2InstanceId'],
'raw_delivery': data
}
event_details['minion'] = ec2_information(event_details)
event.fire_event(event_details, 'AWS/' + data['Message']['Event'])
@app.route("/", methods=['POST'])
def event_listener():
if request.method == 'POST':
print(request.data)
return recv_event(request.data)
else:
return None
if __name__ == "__main__":
app.run()
Event fired at Mon Jun 9 14:25:52 2014
*************************
Tag: AWS/autoscaling:EC2_INSTANCE_LAUNCH
Data:
{'_stamp': '2014-06-09T14:25:52.872399',
'acct': 'REDACTED',
'arn': 'arn:aws:autoscaling',
'autoScalingGroup': 'REDACTED',
'autoScalingGroupName': 'REDACTED',
'event': 'autoscaling:EC2_INSTANCE_LAUNCH',
'instance_id': 'REDACTED',
'minion_id': 'REDACTED',
'raw_delivery': {'Message': {'AccountId': 'REDACTED',
'ActivityId': 'REDACTED',
'AutoScalingGroupARN': 'arn:aws:autoscaling:us-east-1:REDACTED:autoScalingGroup:REDACTED:autoScalingGroupName/REDACTED',
'AutoScalingGroupName': 'REDACTED',
'Cause': 'At 2014-06-09T12:39:29Z a monitor alarm awsec2-REDACTED-High-CPU-Utilization in state ALARM triggered policy Decrease Group Size changing the desired capacity from 6 to 3. At 2014-06-09T12:41:47Z a user request update of AutoScalingGroup constraints to min: 6, max: 9, desired: 6 changing the desired capacity from 3 to 6. At 2014-06-09T12:41:47Z a difference between desired and actual capacity changing the desired capacity, increasing the capacity from 3 to 6.',
'Description': 'Launching a new EC2 instance: REDACTED',
'Details': {'Availability Zone': 'us-east-1d',
'InvokingAlarms': [{'AWSAccountId': 'REDACTED',
'AlarmDescription': None,
'AlarmName': 'awsec2-REDACTED-High-CPU-Utilization',
'NewStateReason': 'Threshold Crossed: 1 datapoint (5.984999999999999) was less than or equal to the threshold (40.0).',
'NewStateValue': 'ALARM',
'OldStateValue': 'ALARM',
'Region': 'US - N. Virginia',
'StateChangeTime': 1402188328924L,
'Trigger': {'ComparisonOperator': 'LessThanOrEqualToThreshold',
'Dimensions': [{'name': 'AutoScalingGroupName',
'value': 'REDACTED'}],
'EvaluationPeriods': 1,
'MetricName': 'CPUUtilization',
'Namespace': 'AWS/EC2',
'Period': 900,
'Statistic': 'AVERAGE',
'Threshold': 40,
'Unit': None}}]},
'EC2InstanceId': 'REDACTED',
'EndTime': '2014-06-09T12:47:23.288Z',
'Event': 'autoscaling:EC2_INSTANCE_LAUNCH',
'Progress': 50,
'RequestId': 'REDACTED',
'Service': 'AWS Auto Scaling',
'StartTime': '2014-06-09T12:41:47.438Z',
'StatusCode': 'InProgress',
'StatusMessage': '',
'Time': '2014-06-09T12:47:23.288Z'},
'MessageId': 'REDACTED',
'Signature': 'TXSE2FvRwPPOXnELz0HvTGqu8Q+GArLXnzdsSx2XouPmU8YDjpljC02DZ7aNuY8/7JRC6zcNjfjQ4QRDdCCrnO3cpL5suk4Ve7zM47ySSC6EVBAjHuhy3f7y6SlQHemI1iORZnN2VHCQcKD/T65GxrStPKclqarueg0fjkfEylfGwF9Y+RUJ6DuwHyqud5DNX5s+qve7UQO1dw0i+32YvrIL+LugisfoFCMRQZHkwVXD9fB/pMPM2VVxQTWO9ghMf4ujVSVrITn3w41BJC3Lm6wDkRdO2DfMkOXtLHwCyDBcp25MSYY0uR/Zr8QREo6pELe/QkXt/CdQJPSG+hg6Xw==',
'SignatureVersion': '1',
'SigningCertURL': 'https://sns.us-east-1.amazonaws.com/SimpleNotificationService-REDACTED.pem',
'Subject': 'Auto Scaling: launch for group "REDACTED"',
'Timestamp': '2014-06-09T12:47:23.354Z',
'TopicArn': 'arn:aws:sns:us-east-1:REDACTED:rpcsys_monitored_events',
'Type': 'Notification',
'UnsubscribeURL': 'https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:REDACTED:rpcsys_monitored_events:REDACTED'},
'region': 'us-east-1'}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment