Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save josephsindel/cf156e1a084f049ce4b6a8bd8652b33d to your computer and use it in GitHub Desktop.
Save josephsindel/cf156e1a084f049ce4b6a8bd8652b33d to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# pylint: disable=invalid-name
# pylint: disable=bare-except
# pylint: disable=missing-docstring
# pylint: disable=line-too-long
# pylint: disable=redefined-outer-name
# pylint: disable=protected-access
import logging
import gzip
import urllib2
import json
import base64
import ssl
import os
import re
import boto3
from winrm.protocol import Protocol
from ldap3 import Server, Connection, ALL, NTLM
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def get_env_var(env_var, value=None):
ssm = boto3.client('ssm')
response = None
envvar = os.getenv(env_var, None)
if envvar is None:
envvar = value
if envvar != value:
if re.match("SSM~.*", envvar) is not None:
with_decryption = False
envvar = envvar.split("SSM~")[1]
if re.match(".*~true", envvar) is not None:
with_decryption = True
envvar = envvar.split("~true")[0]
try:
response = ssm.get_parameters(Names=[envvar], WithDecryption=with_decryption)
except:
logger.error("could not lookup %s", envvar)
if response is not None:
return response['Parameters'][0]['Value']
return envvar
DOMAINS = get_env_var("DOMAINS")
SERVERS = get_env_var("SERVERS")
LDAP_DOMAINS = get_env_var("LDAP_DOMAINS")
DNS_USERNAME = get_env_var("DNS_USERNAME")
DNS_PASSWORD = get_env_var("DNS_PASSWORD")
LDAP_USERNAME = get_env_var("LDAP_USERNAME")
LDAP_PASSWORD = get_env_var("LDAP_PASSWORD")
JIRA_USERNAME = get_env_var("JIRA_USERNAME")
JIRA_PASSWORD = get_env_var("JIRA_PASSWORD")
JIRA_API_ADDRESS = get_env_var("JIRA_API_ADDRESS")
OOM_API_KEY = get_env_var("OOM_API_KEY")
OOM_API_ADDRESS = get_env_var("OOM_API_ADDRESS")
WINRM_PROTOCOL = get_env_var("WINRM_PROTOCOL")
WINRM_PORT = get_env_var("WINRM_PORT")
def handle(event, context):
s3 = boto3.client('s3')
logger.debug("event is %s, context is %s", event, context)
trailevents = list()
for record in event['Records']:
key = record['s3']['object']['key']
bucket = record['s3']['bucket']['name']
s3.download_file(bucket, key, "/tmp/event.json.gz")
with gzip.open("/tmp/event.json.gz", 'rb') as f:
filecontent = f.read()
trailevents.append(json.loads(filecontent))
logger.info("retrieved file s3://%s/%s", bucket, key)
instanceIds = list()
for trailevent in trailevents:
for var in trailevent['Records']:
if var['eventName'] == "TerminateInstances":
instanceIds.append({var['awsRegion'], var['responseElements']['instancesSet']['items'][0]['instanceId']})
if instanceIds != []:
for k, v in instanceIds:
instanceId = v
region = k
aws_details = gather_instance_details(instanceId, region)
logger.debug("got instance details %s", json.dumps(aws_details))
delete_oom_record(instanceId)
delete_ldap_record(aws_details["hostname"])
delete_dns_record(aws_details["hostname"])
create_jira_ticket(aws_details)
else:
logger.info("no terminate-instance events found")
def which_server(hname):
domains = DOMAINS.split(",")
servers = SERVERS.split(",")
ldap_domains = LDAP_DOMAINS.split()
domain = ".".join(hname.split('.')[1:]).lower()
if domain in domains:
logger.info("matched domain %s", domain)
return servers[domains.index(domain)], domain, ldap_domains[domains.index(domain)]
logger.error("failed to match domain %s", domain)
return None, domain, None
def delete_dns_record(hostname):
server, domain, ldap_domain = which_server(hostname)
if server is not None:
p = Protocol(endpoint=WINRM_PROTOCOL + "://" + server + ":" + WINRM_PORT + "/wsman",
transport='credssp', username=DNS_USERNAME,
password=DNS_PASSWORD, server_cert_validation='ignore')
shell_id = p.open_shell()
command_id = p.run_command(shell_id, 'dnscmd', ['localhost', "/RecordDelete", domain, str(hostname.split(".")[0]), 'A', '/f'])
std_out, std_err, status_code = p.get_command_output(shell_id, command_id)
p.cleanup_command(shell_id, command_id)
p.close_shell(shell_id)
if std_err is not None:
logger.info("Successfully delete DNS A/PTR record for %s in domain %s", hostname, ldap_domain)
logger.debug(std_out)
else:
logger.error("failed to delete DNS records for %s", hostname)
logger.debug(std_err)
else:
logger.error("ldap server not found")
def delete_ldap_record(hostname):
server, domain, ldap_domain = which_server(hostname)
if server is not None:
ldap = Server(server, get_info=ALL)
conn = Connection(ldap, user=LDAP_USERNAME, password=LDAP_PASSWORD, authentication=NTLM)
conn.bind()
host = hostname.split('.')[0]
conn.search(ldap_domain, '(&(objectclass=computer)(cn=' + host + '))')
if len(conn.entries) == 1:
dn = str(conn.entries[0])
conn.delete(dn.split()[1])
logger.info("deleted ldap record %s in domain %s", dn.split()[1], domain)
elif len(conn.entries) > 1:
logger.error("more then one ldap result")
else:
logger.error("ldapsearch returned no results")
def gather_instance_details(instanceId, region):
ec2 = boto3.client("ec2", region_name=region)
instance_info = ec2.describe_instances(InstanceIds=[instanceId])
OomHeaders = {'Content-type':"application/json", 'Authorization2':OOM_API_KEY}
request = urllib2.Request(OOM_API_ADDRESS + "?filter=barcode%20eq%20\'" + instanceId + "\'", headers=OomHeaders)
try:
response = urllib2.urlopen(request)
content = json.loads(response.read())
except:
content = None
try:
oom_hostname = content[0]["name"]
except:
oom_hostname = None
logger.info("%s not found in ec2 instance_info", instanceId)
for tag in instance_info["Reservations"][0]["Instances"][0]["Tags"]:
if tag["Key"] == "Name":
ec2_hostname = tag["Value"]
ami = instance_info["Reservations"][0]["Instances"][0]["ImageId"]
az = instance_info["Reservations"][0]["Instances"][0]["Placement"]["AvailabilityZone"]
instance_type = instance_info["Reservations"][0]["Instances"][0]["InstanceType"]
if oom_hostname == ec2_hostname:
logger.info("oom hostname and ec2 hostname match - %s", ec2_hostname)
hostname = ec2_hostname
elif oom_hostname is not None and ec2_hostname is None:
logger.info("obtained hostname from oom - %s", oom_hostname)
hostname = oom_hostname
elif ec2_hostname is not None:
logger.info("obtained hostname from ec2 - %s", ec2_hostname)
hostname = ec2_hostname
else:
logger.info("unable to determine hostname")
hostname = instanceId
return {"hostname": hostname,
"amiId": ami,
"az": az,
"instanceId": instanceId,
"instanceType": instance_type}
def delete_oom_record(instanceId):
OomHeaders = {'Content-type':"application/json", 'Authorization2':OOM_API_KEY}
request = urllib2.Request(OOM_API_ADDRESS + "?filter=barcode%20eq%20\'" + instanceId + "\'", headers=OomHeaders)
try:
response = urllib2.urlopen(request)
content = json.loads(response.read())
except:
content = None
try:
equipment_id = content[0]["equipment_id"]
except:
equipment_id = None
logger.error("%s not found in oom", instanceId)
if equipment_id is not None:
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request(OOM_API_ADDRESS + "/" + equipment_id, headers=OomHeaders)
request.get_method = lambda: 'DELETE'
opener.open(request)
logger.info("Deleted OOM record for %s", instanceId)
def create_jira_ticket(aws_details, host_details=None):
JiraDescription = "||FieldName||Value||\n"
JiraDescription += "|AMI Id|" + aws_details['amiId'] + "|\n"
JiraDescription += "|Availability Zone|"+ aws_details['az'] + "|\n"
JiraDescription += "|Instance-Id|"+ aws_details['instanceId'] + "|\n"
JiraDescription += "|Instance-type|"+ aws_details['instanceType'] + "|\n"
JiraDescription += "|HostName|" + aws_details['hostname'] + "|\n"
if host_details is not None:
logger.debug("for later")
JiraTicketCreateBody = {'fields':{'project':{'id': '11107'},
'summary': "AWS Server Decommission " + aws_details['hostname'],
'description': JiraDescription,
'labels': [aws_details['instanceId'], aws_details['hostname']],
'issuetype': {
'id': '10815'}}}
JiraCredentials = JIRA_USERNAME + ':' + JIRA_PASSWORD
JiraHeaders = {'Content-type':'application/json', "Authorization": "Basic " + base64.b64encode(JiraCredentials)}
request = urllib2.Request(JIRA_API_ADDRESS, headers=JiraHeaders, data=json.dumps(JiraTicketCreateBody))
response = urllib2.urlopen(request, context=ssl._create_unverified_context())
response = response.read()
TicketId = json.loads(response)['key']
JiraTransitionBody = {'transition':{'id':11}}
request = urllib2.Request(JIRA_API_ADDRESS + '/' + TicketId + '/transitions?expand=transitions.fields', headers=JiraHeaders, data=json.dumps(JiraTransitionBody))
response = urllib2.urlopen(request, context=ssl._create_unverified_context())
response.read()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment