Skip to content

Instantly share code, notes, and snippets.

@Seraf
Last active August 29, 2015 14:15
Show Gist options
  • Save Seraf/3bc8e423ac28539ae177 to your computer and use it in GitHub Desktop.
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)
#!/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