I feel like I'm writing more bugs than features

This commit is contained in:
Daniel Dayley 2019-12-06 11:14:19 -07:00
parent 3530dc965c
commit d233a12a5e
3 changed files with 126 additions and 26 deletions

29
ifxtool
View File

@ -61,15 +61,22 @@ class IFXTool():
# Resolve subject names
for item in self.namespace.subjects :
try:
quicklookup = socket.gethostbyname(item)
if quicklookup != item:
quicklookup = ipaddress.ip_address(item)
subjecttuple = socket.gethostbyname_ex(item)
# Can't make an IP out of item
except ValueError :
try :
# Lookup with system
subjecttuple = socket.gethostbyname_ex(item)
else :
subjecttuple = socket.gethostbyaddr(item)
except (socket.gaierror,socket.herror) :
self.warninfo.append("Unable to resolve " + item)
self.namespace.subjects.remove(item)
continue
except socket.gaierror :
# Not a valid host or IP
self.warninfo.append("Unable to resolve " + item)
#self.namespace.subjects.remove(item)
#continue
subjecttuple = [item,[],['']]
# Can't make IPv4 out of it
except socket.gaierror :
subjecttuple = [ipaddress.ip_address(item).reverse_pointer,[],[str(item)]]
# Convert mutable types to immutable (to be used as dictionary keys)
immutablesubjecttuple = tuple([subjecttuple[0],tuple(subjecttuple[1]),tuple(subjecttuple[2])])
self._dnsmaps.update({immutablesubjecttuple:item})
@ -109,10 +116,6 @@ class IFXTool():
else :
return ''
def get_dc_from_ip(self,ip) :
"""Given an IP, return the datacenter the IP resides in."""
pass
def print_results(self,dataset) :
"""Returns the submitted dataset"""
finalresult = {}
@ -125,7 +128,6 @@ class IFXTool():
for subject in self._subjecttuples :
subjectname = self._dnsmaps[subject]
subjectdataset = {}
# for plugin in [x for x in dataset if x != 'status'] :
for plugin in [x for x in dataset if x != 'error' and x != 'warn'] :
subjectdataset.update({plugin:dataset[plugin][subject]})
finalresult.update({subjectname:subjectdataset})
@ -141,6 +143,7 @@ if __name__ == "__main__":
# Load Plugins
plugindir="plugins"
pluginfiles = [x for x in os.listdir(plugindir) if x != "servicebase.py" and x.endswith('.py')]
pluginfiles = sorted(pluginfiles)
importlib.import_module(plugindir)
delegates = []
for pluginfile in pluginfiles :

View File

@ -20,13 +20,20 @@ class ServiceDelegate(ServiceBase) :
self.current_auth_header = self.get_bc_auth_header(self.config['host'],self.config['username'],self.config['key'])
def perform_lookup(self,host_tuple) :
error = None
if self.return_payload and 'error' in self.return_payload :
error = self.return_payload['error']
self.return_payload = {}
if error :
self.return_payload.update({'error':error})
if self.current_auth_header :
object = self.search_bc_object(host_tuple)
self.return_payload.update({'object':object})
parent = self.search_bc_parent_object(host_tuple)
self.return_payload.update({'parent':parent})
return self.return_payload
else :
return self.return_payload
def shutdown(self) :
if self.host and self.current_auth_header :
@ -49,7 +56,7 @@ class ServiceDelegate(ServiceBase) :
def search_bc_parent_object(self,host_tuple) :
"""Search for and return information about the objects parent, if any"""
if 'object' in self.return_payload and 'id' in self.return_payload['object'] :
if 'object' in self.return_payload and type(self.return_payload['object']) is dict and 'id' in self.return_payload['object'] :
response = requests.get("https://" + self.host + "/Services/REST/v1/getParent?entityId=" + str(self.return_payload['object']['id']), headers=self.current_auth_header)
return self.clean_response(response)

View File

@ -1,18 +1,108 @@
from servicebase import ServiceBase
import requests
import re
import json
class ServiceDelegate(ServiceBase) :
current_auth_header = None
return_payload = {}
hosts = None
def get_arguments(cls) :
"""Returns an array of information used to construct an argumentparser argument."""
# [ <short flag>,<unix flag>,<arg type>,<description> ]
# Example return: [ '-n', '--net', 'store_true', "Return network information about the subject" ]
return ['-cg', '--vip', 'store_true', "Return VIP information about the subject"]
def get_f5_auth_header(host,username,password,authprovider) :
"""Given authentication information, return the authenticated header for use in REST requests to an F5 device."""
pass
def get_f5_for_dc(dc) :
"""Given a datacenter, return the next F5 device for that datacenter."""
pass
def get_vip_cg(ip) :
"""Given an IP, return all VIPs that the IP is a member of."""
pass
def startup(self) :
for requirement in ['hosts','username','key'] :
if requirement not in self.config or (requirement in self.config and self.config[requirement] is ''):
self.return_payload.update({'error':'Missing required config option ' + requirement})
return
self.hosts = self.config['hosts']
#self.current_auth_header = self.get_bc_auth_header(self.config['host'],self.config['username'],self.config['key'])
def perform_lookup(self,host_tuple) :
error = None
if self.return_payload and 'error' in self.return_payload :
error = self.return_payload['error']
self.return_payload = {}
if error :
self.return_payload.update({'error':error})
self.return_payload.update({'lookupcandidates':self.choose_host(host_tuple)})
return self.return_payload
if self.current_auth_header :
object = self.search_bc_object(host_tuple)
self.return_payload.update({'object':object})
parent = self.search_bc_parent_object(host_tuple)
self.return_payload.update({'parent':parent})
return self.return_payload
def shutdown(self) :
return
if self.host and self.current_auth_header :
logout = requests.get("https://" + self.host + "/Services/REST/v1/logout",headers=self.current_auth_header)
if not logout.text.endswith("successfully logged out.\"") :
self.return_payload.update({'error':'Unable to log out of BlueCat API session'})
def get_bc_auth_header(self,host,username,password) :
auth_token = requests.get("https://" + host + "/Services/REST/v1/login?username=" + username + "&password=" + password).text[17:71]
if auth_token.startswith('BAMAuthToken') :
return { "Authorization" : auth_token }
else :
return None
def search_bc_object(self,host_tuple) :
"""Searches BC for the subject."""
response = requests.get("https://" + self.host + "/Services/REST/v1/searchByObjectTypes?keyword=" + host_tuple[2][0] + "&types=IP4Address,IP6Address&start=0&count=10",headers=self.current_auth_header)
return self.clean_response(response)
def search_bc_parent_object(self,host_tuple) :
"""Search for and return information about the objects parent, if any"""
if 'object' in self.return_payload and 'id' in self.return_payload['object'] :
response = requests.get("https://" + self.host + "/Services/REST/v1/getParent?entityId=" + str(self.return_payload['object']['id']), headers=self.current_auth_header)
return self.clean_response(response)
def choose_host(self,host_tuple) :
"""Given a host_tuple, return the host that we suspect is responsible for the VIP resides in."""
hosts = {}
# Guess based on hostname
dcmatch = re.search('^[a-zA-Z]*-([a-zA-Z0-9]*)(-.*)*$',host_tuple[0])
if dcmatch :
potentialdc = dcmatch.group(1)
else :
potentialdc = None
if potentialdc :
for host in self.hosts.keys() :
if potentialdc.lower() in host.lower() :
hosts.update({host:self.hosts[host]})
if hosts != {} :
return hosts
# No hostname match, maybe we have info from bluecat?
if 'bluecat' in self.data and host_tuple in self.data['bluecat'] and self.data['bluecat'][host_tuple]['object'] :
potentialdc = self.data['bluecat'][host_tuple]['object']['locationCode'].split(' ')[-1]
for host in self.hosts.keys() :
if potentialdc.lower() in host.lower() :
hosts.update({host:self.hosts[host]})
return hosts
return hosts
def clean_response(self,response) :
parsed = {}
try :
parsed = json.loads(response.text)
except Exception :
return parsed
if type(parsed) is list and len(parsed) > 0 :
parsed = parsed[0]
if type(parsed) is dict :
if 'properties' in parsed :
parsed["properties"] = parsed["properties"][:-1]
bad_delim_props = [x for x in parsed["properties"].split("|") if x.count('=') > 1]
if len(bad_delim_props) > 0 :
parsed.update({"unknown":bad_delim_props})
attributes = dict(x.split("=") for x in parsed["properties"].split("|") if x.count('=') == 1)
parsed.pop("properties", None)
parsed.update(attributes)
return parsed