Skip to content

Instantly share code, notes, and snippets.

@steschuser
Created August 10, 2020 09:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save steschuser/617afba17127d325eb303617f3bd2f0a to your computer and use it in GitHub Desktop.
Save steschuser/617afba17127d325eb303617f3bd2f0a to your computer and use it in GitHub Desktop.
Ansible dynamic inventory with Idoit
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
from bs4 import BeautifulSoup
from flask import Flask, request
from waitress import serve
from paste.translogger import TransLogger
from markupsafe import escape
from jsonrpcclient.clients.http_client import HTTPClient
from jsonrpcclient.requests import Request
from datetime import datetime
from requests import sessions
from parse_it import ParseIt
from pprint import pprint
from loguru import logger
from cachetools import cached, TTLCache
import requests
import attr
import json
import sys
import os
CACHE_TIME=300
IPMI_REPORT = 10 # Report number in idoit
URL = "https://MY_INSTANCE/src/jsonrpc.php"
apikey = "MY_KEY"
app = Flask(__name__)
class AnsibleGroups():
def __init__(self):
self.domains = {}
def sort(self):
self.domains = collections.OrderedDict(sorted(self.domains.items()))
def add(self, domain, host):
if domain is None or host is None:
return False
domain = domain.replace("-", "_")
if domain not in self.domains:
self.domains[domain] = {"hosts": [host]}
return True
if domain in self.domains:
tmp = self.domains[domain]["hosts"]
tmp.append(host)
self.domains[domain]["hosts"] = tmp
return True
@attr.s
class Idoit:
title = attr.ib()
ipmi = attr.ib(default=None)
access= attr.ib(default=None)
@property
def dnsname(self):
if self.title.count('.') == 2:
return self.title.rsplit(".",1)[0]
else:
return self.title
@property
def json(self):
return {"title": self.title, "ipmi": self.ipmi}
@property
def text(self):
return "{}, {}".format(self.title, self.ipmi)
@cached(cache=TTLCache(maxsize=1024, ttl=CACHE_TIME))
def remove_protocol(text):
return text.lstrip("html://").lstrip("https://").rstrip("/")
@cached(cache=TTLCache(maxsize=1024, ttl=CACHE_TIME))
def remove_ssh(text):
return text.lstrip("ssh://")
@cached(cache=TTLCache(maxsize=1024, ttl=CACHE_TIME))
def strip_html(text):
return BeautifulSoup(text, "html.parser").text
@cached(cache=TTLCache(maxsize=1024, ttl=CACHE_TIME))
def get_report(r_id):
client = HTTPClient(URL)
resp = client.send(Request("cmdb.reports.read", apikey=apikey, id=r_id))
resp = resp.data.result
result = []
key_map = {"Title": "title", 'Host[:Port]/URL': "ipmi", 'Primary access URL': "access" }
filter_funcs = {'Host[:Port]/URL': remove_protocol, 'Primary access URL': remove_ssh }
# For every line in report
for s in resp:
# create empty dictonay
c_dic = {}
for key, value in key_map.items():
if key in s:
# if the line contains element that is in key_map
if "<" in s[key]: # Filter html
c_dic[value] = strip_html(s[key])
else:
c_dic[value] = s[key]
# add to empty dictory
c_dic[value] = c_dic[value].split(" ")[0].lower()
if key in filter_funcs: # Use Filter function if key needs it
c_dic[value] = filter_funcs[key](c_dic[value])
tmp_idoit = Idoit(**c_dic)
result.append(tmp_idoit)
return result
@app.route('/')
def ping():
#logger.info("I live")
return json.dumps("I live")
########################################
# Ansible #
########################################
@cached(cache=TTLCache(maxsize=1024, ttl=CACHE_TIME))
def get_ansible_report(r_id):
report = get_report(r_id)
hostvars = {}
groups = AnsibleGroups()
for s in report:
if s.access.count(":") == 1:
ip, port = s.access.split(":")
hostvars[s.title] = {"ansible_ssh_host": ip, "ansible_ssh_port": port}
else:
hostvars[s.title] = {"ansible_ssh_host": s.access}
domain = s.title.split(".")
if len(domain) > 1:
groups.add(domain[1],s.title)
retvar = {"_meta": {"hostvars": hostvars }}
retvar["all"]= {"children": list(groups.domains.keys())}
for k,v in groups.domains.items():
retvar[k] = v
return retvar
@app.route('/ansible/')
@app.route('/ansible')
def ansible_all():
retvar = get_ansible_report(11)
# retvar = {"_meta":
# {"hostvars":
# {"ansible02.foo.de": {"ansible_ssh_host": "192.168.42.53"}
# }
# },
# "all":
# { "children":
# [ "foo"]
# },
# "foo":
# {"hosts":
# ["ansible02.foo.de"]
# }}
return json.dumps(retvar)
def main():
#serve(app, host='127.0.0.1', port=8011)
serve(TransLogger(app), host='127.0.0.1', port=8011)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment