Skip to content

Instantly share code, notes, and snippets.

@gianrubio
Last active March 3, 2019 17:21
Show Gist options
  • Save gianrubio/691b9ff49c0d01bda4911a22adf2214f to your computer and use it in GitHub Desktop.
Save gianrubio/691b9ff49c0d01bda4911a22adf2214f to your computer and use it in GitHub Desktop.
import json
from botocore.exceptions import ClientError
import boto3
import sys
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
from zabbix.api import ZabbixAPI
## to install virtualenv
## pip install py-zabbix boto3 -t .
## to update this lambda use
## rm proj.zip ; zip -r proj.zip * && aws lambda update-function-code --function-name aws-deregister --zip-file fileb://proj.zip --region us-east-1 ; rm proj.zip
### Use for debug
#
#tes={u'event': [{u'Records': [{u'Sns': {u'Message': {u'EC2InstanceId': u'i-af391367', u'Service': u'AWS Auto Scaling', u'AutoScalingGroupName': u'exampleAutoScalingGroup', u'LifecycleActionToken': u'eaac0cdf-df85-4c8f-a9ed-f0a685066099', u'LifecycleHookName': u'do-some-work', u'RequestId': u'6648ba02-138b-4f56-a0c7-bc74f22c3b51', u'Time': u'2015-01-07T18:37:17.553Z', u'LifecycleTransition': u'autoscaling:EC2_INSTANCE_TERMINATING', u'AccountId': u'356438515751'}}}]}]}
#tes={u'Records': [{u'EventVersion': u'1.0', u'EventSubscriptionArn': u'arn:aws:sns:sa-east-1:444914307613:zabbix-terminate-sa-east-1:c29c67d2-d070-4353-9093-266e49338720', u'EventSource': u'aws:sns', u'Sns': {u'SignatureVersion': u'1', u'Timestamp': u'2016-04-04T03:32:25.787Z', u'Signature': u'TeAaHghsAkPUuxyE6gIAad7PzV2CH2n2YT4q7UEtypqjVF0TEmGPAwX0q80Dm2XLT5fHlHjnngR9zm+kaTu5T137eNwxt+6xJuU4/yOao8VrV3AJ/4o/oLhK5G8h+mLqOYuGpqWTGYuslKmNEmc5i9RNDau0tP03hXNRAm5b+33wTtLuQ8gOQ/mrf6fwsmhGJO05LUEBnLFI6+TVs6u+X4l3qr4nxuy1kS5DuXfrb9FYkKAXT9RELMOCYLbPhFinJfaGkwfa7evGuxUNAStCR2gbiBKEQ3Q12hrOsh5x3QfMufiJNIBuFQi6Za3hrWW5tYBrh0tObxm9Qa6nfgcWpA==', u'SigningCertUrl': u'https://sns.sa-east-1.amazonaws.com/SimpleNotificationService-bb750dd426d95ee9390147a5624348ee.pem', u'MessageId': u'e6edf556-18ff-58e6-b457-ba2dfa7615fc', u'Message': u'{"StatusCode":"InProgress","Service":"AWS Auto Scaling","AutoScalingGroupName":"ASG-nginx-images-prod-20160316","Description":"Terminating EC2 instance: i-cfb63f1e","ActivityId":"67a0a507-0e45-4c9d-9fc5-dba95087fb70","Event":"autoscaling:EC2_INSTANCE_TERMINATE","Details":{"InvokingAlarms":[{"Region":"SA-East-1","AWSAccountId":"444914307613","OldStateValue":"OK","AlarmName":"awsec2-ASG-nginx-images-prod-20160316-High-CPU-Utilization","AlarmDescription":null,"NewStateReason":"Threshold Crossed: 1 datapoint (49.994) was less than or equal to the threshold (50.0).","StateChangeTime":1459740644889,"NewStateValue":"ALARM","Trigger":{"Period":300,"Statistic":"AVERAGE","MetricName":"CPUUtilization","Threshold":50,"EvaluationPeriods":1,"Dimensions":[{"name":"AutoScalingGroupName","value":"ASG-nginx-images-prod-20160316"}],"Namespace":"AWS/EC2","ComparisonOperator":"LessThanOrEqualToThreshold","Unit":null}}],"Availability Zone":"sa-east-1c","Subnet ID":"subnet-efcd90a9"},"AutoScalingGroupARN":"arn:aws:autoscaling:sa-east-1:444914307613:autoScalingGroup:3d4a78e3-518f-4116-a408-c7f0f55ab9a9:autoScalingGroupName/ASG-nginx-images-prod-20160316","Progress":50,"Time":"2016-04-04T03:32:25.735Z","AccountId":"444914307613","RequestId":"67a0a507-0e45-4c9d-9fc5-dba95087fb70","StatusMessage":"","EndTime":"2016-04-04T03:32:25.735Z","EC2InstanceId":"i-cfb63f1e","StartTime":"2016-04-04T03:31:02.157Z","Cause":"At 2016-04-04T03:30:44Z a monitor alarm awsec2-ASG-nginx-images-prod-20160316-High-CPU-Utilization in state ALARM triggered policy Decrease Group Size changing the desired capacity from 5 to 4. At 2016-04-04T03:31:02Z an instance was taken out of service in response to a difference between desired and actual capacity, shrinking the capacity from 5 to 4. At 2016-04-04T03:31:02Z instance i-cfb63f1e was selected for termination."}', u'MessageAttributes': {}, u'Type': u'Notification', u'UnsubscribeUrl': u'https://sns.sa-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:sa-east-1:444914307613:zabbix-terminate-sa-east-1:c29c67d2-d070-4353-9093-266e49338720', u'TopicArn': u'arn:aws:sns:sa-east-1:444914307613:zabbix-terminate-sa-east-1', u'Subject': u'Auto Scaling: termination for group "ASG-nginx-images-prod-20160316"'}}]}
#lambda_handler(test, None)
##
class AwsEc2DeregisterZabbix():
INSTANCE_TERMINATING = 'autoscaling:EC2_INSTANCE_TERMINATING'
INSTANCE_TERMINATE = 'autoscaling:EC2_INSTANCE_TERMINATE'
def __init__(self, ec2_instance_id):
self.ec2_instance_id = ec2_instance_id
self.host = None
self.aws_hostname = None
self.regions = ['us-east-1', 'sa-east-1']
def zabbix_disable_host(self):
self.zabbix = ZabbixAPI(url='https://myzabbix.com',
user='myuser', password='mypassword')
ec2_internal_ip = self.ec2_get_ip()
# disable host from ec2 ip
if ec2_internal_ip:
hosts = self.zabbix.hostinterface.get(filter={'ip': ec2_internal_ip})
# or disable host from zabbix hostname
else:
hosts = self.zabbix.host.get(search={"name": ["*{}".format(self.ec2_instance_id.replace('i-',''))]},
searchWildcardsEnabled=True)
for host in hosts:
update_host = {'hostid': host['hostid'], 'status': 1}
self.zabbix.host.update(update_host)
logger.info('Disabling host {} ({}) Zabbix'.format(self.ec2_instance_id, ec2_internal_ip))
return True
else:
logger.info('Host {} ({}) not found in Zabbix'.format(self.ec2_instance_id, ec2_internal_ip))
return False
def ec2_get_ip(self):
for region in self.regions:
ec2 = boto3.client('ec2', region_name=region)
instance = ec2.describe_instances(Filters=[{'Name': 'instance-id', 'Values': [self.ec2_instance_id]}])
logger.info('Found instance {}) '.format(instance))
if instance['Reservations']:
response = instance['Reservations'][0]['Instances'][0]
# ip not found on aws
if 'PrivateIpAddress' in response:
return response['PrivateIpAddress']
return None
def autoscaling_abandon(self, asg_name, asg_lifecycle_action_token, asg_hook_name):
for region in self.regions:
try:
boto3.client('autoscaling', region_name=region).complete_lifecycle_action(
AutoScalingGroupName=asg_name,
LifecycleActionToken=asg_lifecycle_action_token,
LifecycleActionResult='ABANDON',
LifecycleHookName=asg_hook_name,
)
except ClientError as e:
if e.message.__contains__("No active Lifecycle Action"):
pass
else:
raise e
def lambda_handler(event, context):
logger.info("Proccessing message {message}.".format(message=event))
msg = json.loads(event['Records'][0]['Sns']['Message'])
if ('LifecycleTransition' in msg and \
msg['LifecycleTransition'] \
== AwsEc2DeregisterZabbix.INSTANCE_TERMINATING) \
or ('Event' in msg and
msg['Event'] == AwsEc2DeregisterZabbix.INSTANCE_TERMINATE
):
aws_zabbix = AwsEc2DeregisterZabbix(ec2_instance_id=msg['EC2InstanceId'])
try:
aws_zabbix.zabbix_disable_host()
except Exception as e:
logger.exception(e)
finally:
asg_name = msg['AutoScalingGroupName']
if 'LifecycleActionToken' in msg:
asg_lifecycle_action_token = msg['LifecycleActionToken']
asg_hook_name = msg['LifecycleHookName']
aws_zabbix.autoscaling_abandon(asg_name, asg_lifecycle_action_token, asg_hook_name)
@marciogsm
Copy link

Great job! I was thinking on doing something similar to yours, however, through aws cli.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment