Last active
August 29, 2015 14:15
-
-
Save Seraf/3bc8e423ac28539ae177 to your computer and use it in GitHub Desktop.
This script remove an ec2 instance from route53 providing an instance pattern if this instance does not exist in sensu (so this instance still no longer exist)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
# encoding: utf-8 | |
# | |
# Authors: | |
# Julien Syx <[email protected]> | |
# | |
# Dependencies: | |
# - python boto | |
# | |
# On Debian: aptitude install python-boto | |
# With pip: pip install boto | |
import argparse | |
import sys | |
import urllib2 | |
import boto | |
import logging | |
import re | |
import json | |
from boto.route53.zone import Zone | |
from boto.route53 import exception | |
__version__ = 'v0.1' | |
LVL = {'INFO': logging.INFO, | |
'DEBUG': logging.DEBUG, | |
'ERROR': logging.ERROR, | |
'CRITICAL': logging.CRITICAL} | |
def setup_log(name=__name__, level='INFO', log=None, | |
console=True, form='%(asctime)s [%(levelname)s] %(message)s'): | |
""" | |
Setup logger object for displaying information into console/file | |
:param name: Name of the logger object to create | |
:type name: str | |
:param level: Level INFO/DEBUG/ERROR etc | |
:type level: str | |
:param log: File to which log information | |
:type log: str | |
:param console: If log information sent to console as well | |
:type console: Boolean | |
:param form: The format in which the log will be displayed | |
:type form: str | |
:returns: The object logger | |
:rtype: logger object | |
""" | |
level = level.upper() | |
if level not in LVL: | |
logging.warning("Option of log level %s incorrect, using INFO." % level) | |
level = 'INFO' | |
level = LVL[level] | |
formatter = logging.Formatter(form) | |
logger = logging.getLogger(name) | |
logger.setLevel(level) | |
if log is not None: | |
filehdl = logging.FileHandler(log) | |
filehdl.setFormatter(formatter) | |
logger.addHandler(filehdl) | |
if console is True: | |
consolehdl = logging.StreamHandler() | |
consolehdl.setFormatter(formatter) | |
logger.addHandler(consolehdl) | |
return logger | |
class RemoveR53Entries(): | |
def __init__(self, pattern, sensu_url, sensu_port, dry_run): | |
self.logger = logging.getLogger(__name__) | |
self.pattern = pattern | |
self.dry_run = dry_run | |
if dry_run: | |
self.logger.info("== Running in dry mode, no changes will be done ==") | |
# Get the list of the clients available on Sensu only one time | |
try: | |
sensu_conn = urllib2.urlopen(''.join(['http://', sensu_url, ':', sensu_port, '/clients/'])) | |
except urllib2.HTTPError, e: | |
self.logger.error('HTTPError = ' + str(e.code)) | |
except urllib2.URLError, e: | |
self.logger.error('URLError = ' + str(e.reason)) | |
except Exception: | |
self.logger.error('Problem joining sensu api') | |
finally: | |
self.sensu_clients = json.load(sensu_conn) | |
self.check_route53() | |
def check_route53(self): | |
conn = boto.connect_route53() | |
try: | |
zones = conn.get_all_hosted_zones() | |
except exception.DNSServerError: | |
self.logger.error('Problem getting all hosted zones') | |
sys.exit(1) | |
for zone in zones['ListHostedZonesResponse']['HostedZones']: | |
vpc_zone = Zone(conn, zone) | |
self.logger.debug("================ ZONE : %s ================" % zone['Name']) | |
for record in vpc_zone.get_records(): | |
recordname = record.name[:-1] | |
if re.search(self.pattern, recordname): | |
if self.in_sensu(name=recordname): | |
self.logger.info("ZONE : %s - Pattern %s matching and in Sensu" % (zone['Name'], recordname)) | |
else: | |
self.logger.warn("ZONE : %s - Pattern %s matching but not in Sensu" % (zone['Name'], | |
recordname)) | |
if not self.dry_run: | |
vpc_zone.delete_record(record) | |
self.logger.warn("ZONE : %s - /!\ Pattern %s has been deleted /!\ " % (zone['Name'], | |
recordname)) | |
else: | |
self.logger.debug("ZONE : %s - Pattern %s not matching" % (zone['Name'], recordname)) | |
def in_sensu(self, name=""): | |
""" | |
Check if a hostname (fqdn) is in sensu client's list | |
:param name: Instance hostname | |
:type name: str | |
:rtype: bool | |
""" | |
for client in self.sensu_clients: | |
if name.lower() == client['name'].lower(): | |
return 1 | |
return 0 | |
def main(): | |
""" | |
Main - manage args | |
""" | |
# Main informations | |
parser = argparse.ArgumentParser( | |
description='Delete entries from route53 by checking if they exist in Sensu or not', | |
formatter_class=argparse.ArgumentDefaultsHelpFormatter) | |
# Command args | |
parser.add_argument('-p', '--pattern', action='store', type=str, | |
default='.*-i-.*', metavar='PATTERN', nargs=1, | |
help='This is the pattern of your instances') | |
parser.add_argument('-s', '--sensu', action='store', type=str, | |
default='localhost', metavar='HOST', nargs=1, | |
help='Sensu http address') | |
parser.add_argument('-P', '--port', action='store', type=str, | |
default='4567', metavar='PORT', nargs=1, | |
help='Port of the Sensu API') | |
parser.add_argument('-d', '--dry_run', action='store_true', default=False, | |
help='Define if it should delete entries or just dry run') | |
parser.add_argument('-f', '--file_output', metavar='FILE', | |
default='/var/log/route53.log', action='store', type=str, | |
help='Set an output file') | |
parser.add_argument('-F', '--form', metavar='PATTERN', | |
default='%(asctime)s %(levelname)s %(message)s', action='store', type=str, | |
help='Set the logging format') | |
parser.add_argument('-S', '--stdout', action='store_true', default=True, | |
help='Log output to console (stdout)') | |
parser.add_argument('-V', '--verbosity', metavar='LEVEL', default='INFO', | |
type=str, action='store', | |
help='Verbosity level: DEBUG/INFO/ERROR/CRITICAL') | |
parser.add_argument('-v', '--version', | |
action='version', | |
version=' '.join([__version__, 'Licence GPLv2+']), | |
help='Print version number') | |
arg = parser.parse_args() | |
# Setup logger | |
setup_log(console=arg.stdout, log=arg.file_output, level=arg.verbosity, form=arg.form) | |
RemoveR53Entries(pattern=arg.pattern, sensu_url=arg.sensu, sensu_port=arg.port, dry_run=arg.dry_run) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment