From 896dced5eba019d3b68efcf2ca5948a1f29e87d2 Mon Sep 17 00:00:00 2001 From: rasmus Date: Wed, 23 Dec 2020 04:37:15 +0200 Subject: [PATCH] prom: part1/2: new files --- prom.py | 29 +++++++++++++ prom_servers.py | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 prom.py create mode 100644 prom_servers.py diff --git a/prom.py b/prom.py new file mode 100644 index 0000000..5886843 --- /dev/null +++ b/prom.py @@ -0,0 +1,29 @@ +""" +ENV VARIABLES AVAILABLE: + - SSH_HOSTNAME + - SSH_KEYPATH +""" +""" +export FLASK_ENV=development +export FLASK_APP=prom.py +flask run +""" +from flask import Flask, request # General flask, and the handle requests on the fly thing. +import os # for ENV arguments + +import scraperMain, prom_servers + +PREFIX = 'bladetest_' +enc = 'k-space-blade-02' # for now ~~hard~~softcoded in, we'd need to add parsing in hostnames, and add a similar enc env var. + +hostname = str(os.environ['SSH_HOSTNAME']) +sshkeypath = os.getenv('SSH_KEYPATH') + +### FLASK ### +app = Flask(__name__) +@app.route('/', methods=['GET']) +def parse_request(): # If somebody accesses us + data = scraperMain.scraperMain(hostname, enc, sshkeypath) # Gather up, we're going to wait a few minutes on the data. + response_list = prom_servers.prom_servers(PREFIX, data[0], data[1]) # Convert our python lists to prometheus format whatever. + response = '\n'.join(response_list) # Oh you still don't want a list? Fine, newlines! + return response # The pizza is already cold. \ No newline at end of file diff --git a/prom_servers.py b/prom_servers.py new file mode 100644 index 0000000..2360609 --- /dev/null +++ b/prom_servers.py @@ -0,0 +1,107 @@ +from datetime import datetime +from warnings import warn + +def prom_header(desc, item, promtype): + # Input validation + if not type(desc) is str: + raise TypeError("promify_item: desc must be a string, '" + str(desc) + "' is not.") + if not type(item) is list: + raise TypeError("promify_item: item must be a list, '" + str(item) + "' is not.") + if not type(promtype) is str: + raise TypeError("promify_item: promtype must be a string, '" + str(promtype) + "' is not.") + + name = item[0].split('{')[0] # something like bladetest_blade_bladeonly_dc, could be given as an argument, but human changing this code might forget to change the argument inputs + item.insert(0, '# HELP ' + name + ' ' + desc) # insert 2 header lines (in the same order as seen here) for the item + if promtype == "gauge": + item.insert(1, '# TYPE ' + name + ' gauge') + elif promtype == "counter": + item.insert(1, '# TYPE ' + name + ' counter') + else: + raise ValueError("promify_item: " + promtype + " promtype is either not implemented as a type, or invalid.") + + return(item) + +def prom_servers(PREFIX, baysInUseCount, servers): + # Input validation + if not type(baysInUseCount) is int: + raise TypeError("parseServers: baysInUseCount must be an integer, '" + str(baysInUseCount) + "' is not.") + if not type(servers) is list: + raise TypeError("parseServers: servers must be a list, '" + str(servers) + "' is not.") + + promRelAC = [] # Init all, is there a way to condense this to single line, and not repeat the '= []'? + promBldDC = [] + promHealth = [] + promUID = [] + promPower = [] + errors = 0 + timestampPart = ' [' + str(int(float(datetime.now().timestamp()) * 1000)) + ']' # https://github.com/prometheus/client_python/issues/185#issuecomment-671801202 + + for n in range(baysInUseCount): + if servers[n][2] == '': # If no serial + warn("no serial on blade '" + servers[n][1] + "' in enc " + servers[n][8] + " bay " + str(servers[n][0]) + ".") + errors += 1 + + labelsPart = '{' + 'enc="' + servers[n][8] + '",' + 'bay="' + str(servers[n][0]) + '",' 'name="' + servers[n][1] + '",' + 'blade_serial="' + servers[n][2] + '"' + '} ' + + + promRelAC.append( PREFIX + 'blade_relative_ac' + labelsPart + str(servers[n][7]) + timestampPart ) + + + promBldDC.append( PREFIX + 'blade_bladeonly_dc' + labelsPart + str(servers[n][6]) + timestampPart ) + + + if servers[n][3] == 'OK': + health = 1 + elif servers[n][3] == 'Failed': + health = 0 + else: + health = 'NaN' + warn("unknown health on blade '" + servers[n][1] + "' in enc " + servers[n][8] + " bay " + str(servers[n][0]) + "." ) + errors += 1 + + promHealth.append( PREFIX + 'blade_health' + labelsPart + str(health) + timestampPart ) + + + if servers[n][5] == 'On': + uid = 1 + elif servers[n][5] == 'Off': + uid = 0 + else: + uid = 'NaN' + warn("unknown UID status for blade '" + servers[n][1] + "' in enc " + servers[n][8] + " bay " + str(servers[n][0]) + "." ) + errors += 1 + + promUID.append( PREFIX + 'blade_uid' + labelsPart + str(uid) + timestampPart ) + + if servers[n][4] == 'On': + power = 1 + elif servers[n][4] == 'Off': + power = 0 + else: + power = 'NaN' + warn("unknown power state for blade '" + servers[n][1] + "' in enc " + servers[n][8] + " bay " + str(servers[n][0]) + "." ) + errors += 1 + promPower.append( PREFIX + 'blade_power' + labelsPart + str(power) + timestampPart ) + + #breakpoint() + # Add differnet types of things together. + prom_disp_servers = [] + prom_disp_servers = prom_disp_servers + prom_header('Relative usage of whole enc AC the blade is consuming in watts', promRelAC, 'gauge') + prom_disp_servers = prom_disp_servers + prom_header('Actual DC in watts what the blade uses directly', promBldDC, 'gauge') + prom_disp_servers = prom_disp_servers + prom_header('Blade health 1 for ok 0 for nok NaN for err', promHealth, 'gauge') + prom_disp_servers = prom_disp_servers + prom_header('Blade UID blinkyboy 1 for blinky blinky 0 for no blinky blinky NaN for err', promUID, 'gauge') + prom_disp_servers = prom_disp_servers + prom_header('Blade power 1 for on and everything in between 0 for off NaN for err', promPower, 'gauge') + prom_disp_servers = prom_disp_servers + prom_header('Number of errors or warnings encountered during the gathering of data see logs of promServers in blade-ssh-scraper', [PREFIX + 'errors ' + str(errors)], 'counter') + + #prom_disp_servers = '\n'.join(prom_disp_servers) + breakpoint() + return(prom_disp_servers) + +# Test data +#PREFIX = 'bladetest_' +#baysInUseCount = 11 +# 0~ 1~ 2~ 3~ 4~ 5~ 6~ 7~ 8~ +# [BayNumber "Server Name", "Serial Number", "Status", "Power", "UID Partner", presentPowerDirectDC, relativeUsageAC, "enc"] +#servers = [[1, 'tty-lab-1', '', 'OK', 'On', 'Off', 142, 222, "k-space-blade-02"], [2, 'tty-lab-2', 'CZ320263P9', 'OK', 'On', 'Off', 87, 136, "k-space-blade-02"], [3, 'tty-lab-3', 'CZJ14410KP', 'Failed', 'On', 'Off', 127, 198, "k-space-blade-02"], [4, 'kspve1', 'CZJ14410KK', 'OK', 'On', 'Off', 86, 134, "k-space-blade-02"], [5, 'kspve2-2', '', 'OK', 'On', 'Off', 71, 111, "k-space-blade-02"], [6, 'kspve3', '', 'OK', 'On', 'Off', 80, 125, "k-space-blade-02"], [7, 'plaes-blade', '', 'OK', 'On', 'Off', 81, 127, "k-space-blade-02"], [8, 'Ringly-01', 'CZ3402Y48C', 'OK', 'On', 'Off', 126, 197, "k-space-blade-02"], [9, 'toomas-lepik', 'CZ3217FNYE', 'OK', 'On', 'Off', 129, 202, "k-space-blade-02"], [10, 'toomas-lepik2', 'CZ3217FFSS', 'OK', 'On', 'Off', 97, 152, "k-space-blade-02"], [12, 'erki-naumanis', '', 'OK', 'On', 'Off', 86, 134, "k-space-blade-02"]] + +#print(prom_servers(PREFIX, baysInUseCount, servers))