Created
August 10, 2020 09:38
-
-
Save steschuser/617afba17127d325eb303617f3bd2f0a to your computer and use it in GitHub Desktop.
Ansible dynamic inventory with Idoit
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 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
Hi. Thanks for sharing the script.
Do you have a newer version, because the HTTPClient in jsonrpcclieent is obsolete...