Si ca intéresse quelqu'un, j'ai repris le script python et l'ai un peu amélioré pour gérer les exceptions et collecter plus de metrics (dont le statut d'enregistrement sur l'arbre):
#!/usr/bin/env python3
import socket
import requests
import base64
import time
## Default
#ont_host = "192.168.100.1"
#ont_username = "root"
#ont_password = "adminHW"
## Orange custom
#ont_host = "192.168.4.254"
#ont_username = "root"
#ont_password = "admin"
req_timeout_s = 2
# User vars
ont_host = "192.168.4.254"
ont_username = "root"
ont_password = "admin"
graphite_host = "localhost"
graphite_port = 2003
graphite_prefix = "ont0"
# precompute the password
ont_password = base64.b64encode(ont_password.encode())
# Python method to test if a string is a float
def isfloat(value):
try:
float(value)
return True
except ValueError:
return False
# Build URL prefix
ont_urlprefix = "http://" + ont_host
carbon_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# Start http session
ont_session = requests.Session()
starttime = time.monotonic()
session_active = False
print("running")
while True:
graphite_data = []
time.sleep(10.0 - ((time.monotonic() - starttime) % 10.0))
starttime = time.monotonic()
if session_active != True:
# grab a session ID and authenticate to the ONT
try:
res = ont_session.post(ont_urlprefix + "/asp/GetRandCount.asp", timeout=req_timeout_s)
res.close()
if res.status_code != 200:
raise Exception("non-200 status code")
except Exception as e:
print("failed to get session id: {:s}".format(str(e)))
# try to login again on the next tick
continue
sid = res.text[-32:]
headers = {"Cookie": "Cookie=body:Language:english:id=-1"}
auth_data = {"UserName": ont_username, "PassWord": ont_password, "x.X_HW_Token": sid}
try:
res = ont_session.post(ont_urlprefix + "/login.cgi", headers=headers, data=auth_data, timeout=req_timeout_s)
res.close()
if res.status_code != 200:
raise Exception("non-200 status code")
except Exception as e:
print("failed to execute login request: {:s}".format(str(e)))
# try to login again on the next tick
continue
session_active = True
# get optical transceiver stats
try:
res = ont_session.get(ont_urlprefix + "/html/amp/opticinfo/opticinfo.asp", timeout=req_timeout_s)
res.close()
if res.status_code != 200:
raise Exception("non-200 status code")
else:
# mark the current time for metrics timestamping
current_date = int(time.time())
# parse the results
for line in res.text.split("\n"):
if line.startswith('var opticInfos = new Array'):
opticInfos_split = line.split("\",\"")
# ensure we have enough chunks to proceed
if len(opticInfos_split) < 6:
break
# tx power
result_TxPower = opticInfos_split[1]
if isfloat(result_TxPower):
graphite_data.append("{:s}.tx_power_dBm {:f} {:d}".format(graphite_prefix, float(result_TxPower), current_date))
# rx power
result_RxPower = opticInfos_split[2]
if isfloat(result_RxPower):
graphite_data.append("{:s}.rx_power_dBm {:f} {:d}".format(graphite_prefix, float(result_RxPower), current_date))
# voltage
result_Voltage = opticInfos_split[3]
if str(result_Voltage).isdigit():
graphite_data.append("{:s}.voltage_mV {:d} {:d}".format(graphite_prefix, int(result_Voltage), current_date))
# bias current
result_BiasCurrent = opticInfos_split[5]
if str(result_BiasCurrent).isdigit():
graphite_data.append("{:s}.bias_current_mA {:d} {:d}".format(graphite_prefix, int(result_BiasCurrent), current_date))
# temperature
result_Temperature = opticInfos_split[4]
if str(result_Temperature).isdigit():
graphite_data.append("{:s}.temperature_C {:d} {:d}".format(graphite_prefix, int(result_Temperature), current_date))
break
except Exception as e:
print("failed to poll transceiver stats: {:s}".format(str(e)))
# get device status
try:
res = ont_session.get(ont_urlprefix + "/html/ssmp/deviceinfo/deviceinfocut.asp", timeout=req_timeout_s)
res.close()
if res.status_code != 200:
raise Exception("non-200 status code")
else:
# mark the current time right after reading the response
current_date = int(time.time())
lines_found = 0
# parse results
for line in res.text.split("\n"):
if line.startswith('var ontInfos = new Array'):
lines_found += 1
ontInfos_split = line.split("\"")
# ensure we have enough chunks to proceed
if len(ontInfos_split) < 3:
continue
# ONT registration status
if len(ontInfos_split[5]) == 2 and ontInfos_split[5][0] == 'O' and ontInfos_split[5][1].isdigit():
graphite_data.append("{:s}.ont_registration_status {:d} {:d}".format(graphite_prefix, int(ontInfos_split[5][1]), current_date))
# ONT ID
if ontInfos_split[3].isdigit():
graphite_data.append("{:s}.ont_id {:d} {:d}".format(graphite_prefix, int(ontInfos_split[3]), current_date))
elif line.startswith('var cpuUsed = '):
lines_found += 1
ontInfos_split = line.split("\'")
if len(ontInfos_split) != 3:
continue
# CPU used
if len(ontInfos_split[1]) >= 2 and ontInfos_split[1][-1] == '%' and ontInfos_split[1][0:-1].isdigit():
graphite_data.append("{:s}.cpu_used_pc {:d} {:d}".format(graphite_prefix, int(ontInfos_split[1][0:-1]), current_date))
elif line.startswith('var memUsed = '):
lines_found += 1
ontInfos_split = line.split("\'")
if len(ontInfos_split) != 3:
continue
# memory used
if len(ontInfos_split[1]) >= 2 and ontInfos_split[1][-1] == '%' and ontInfos_split[1][0:-1].isdigit():
graphite_data.append("{:s}.memory_used_pc {:d} {:d}".format(graphite_prefix, int(ontInfos_split[1][0:-1]), current_date))
if lines_found == 3:
break
except Exception as e:
print("failed to poll ONT status: {:s}".format(str(e)))
# since the ONT replies with 200/OK to unauthenticated requests, treat the absence of
# metrics as a signal to re-authenticate
if len(graphite_data) == 0:
print("no metrics, re-authenticating")
session_active = False
# logout
try:
ont_session.post(ont_urlprefix + "/logout.cgi?RequestFile=html/logout.html", timeout=req_timeout_s)
res.close()
if res.status_code != 200:
raise Exception("non-200 status code")
except Exception as e:
print("failed to perform logout request: {:s}".format(str(e)))
continue
try:
carbon_socket.sendto(("\n".join(graphite_data)).encode(), (graphite_host, graphite_port))
except Exception as e:
print("failed to push graphite metrics: {:s}".format(str(e)))
exit(2)
qui émet quelque chose comme cela toutes les 10s:
ont0.tx_power_dBm 2.060000 1755187721
ont0.rx_power_dBm -20.660000 1755187721
ont0.voltage_mV 3253 1755187721
ont0.bias_current_mA 7 1755187721
ont0.temperature_C 46 1755187721
ont0.ont_registration_status 5 1755187722
ont0.ont_id 106 1755187722
ont0.cpu_used_pc 14 1755187722
ont0.memory_used_pc 70 1755187722
Notez que j'émets en UDP et non en TCP comme le script original, donc il faudra probablement adapter si votre collecteur graphite n'écoute pas en UDP.
Python n'est pas mon language de prédilection, tapez pas trop fort si un PEP a été blessé lors de la rédaction de ce script :-)