-
Guilhem Saurel authoredGuilhem Saurel authored
machines.py 4.52 KiB
#!/usr/bin/env python3
"""Utils to manage Gepetto computers"""
from argparse import ArgumentParser
from datetime import date
import pandas as pd
from ldap3 import Connection
from tabulate import tabulate
CONN = Connection("ldap.laas.fr", auto_bind=True)
ATTRIBUTES = [
"cn",
"laas-date-install",
"laas-mach-datePeremption",
"laas-mach-inventaire",
"laas-mach-modele",
"laas-mach-os",
"laas-mach-responsable",
# "laas-mach-type",
"laas-mach-utilisateur",
"laas-mach-commentaire",
"roomNumber",
]
FILTERS = {
"laas-mach-group": ["gepetto"],
"laas-mach-type": ["PC"],
"laas-mach-origineAchat": ["LAAS", "autre"], # exclude perso
}
def short(attr: str) -> str:
"""Use shorter versions of LDAP attributes for CLI & display."""
return attr.replace("laas-", "").replace("mach-", "").replace("Number", "")
def parse(k, v):
"""Parse ldap value."""
if not v:
return ""
v = v[0]
if "date" in k:
d, m, y = (int(i) for i in v.split("/"))
v = date(y, m, d)
return v
def filter(**filters) -> str:
"""format some filters for LDAP query."""
def filter_key(k, vs):
return "(|" + "".join(f"({k}={v})" for v in vs) + ")"
return "(&" + "".join(filter_key(k, vs) for k, vs in filters.items()) + ")"
def machines_ldap(
utilisateur="", responsable="", room="", machine="", vlan=False, **kwargs
):
"""Get a dict of Gepettists machines from LDAP."""
filters = FILTERS
if machine:
filters["cn"] = [machine]
if utilisateur:
filters["laas-mach-utilisateur"] = [utilisateur]
if responsable:
filters["laas-mach-responsable"] = [responsable]
if room:
filters["roomNumber"] = [room]
CONN.search(
"ou=machines,dc=laas,dc=fr",
filter(**filters),
attributes=ATTRIBUTES,
)
ret = {
str(entry.cn): {
short(k): parse(k, v) for k, v in entry.entry_attributes_as_dict.items()
}
for entry in CONN.entries
}
if vlan:
filters = "".join(f"(cn={k})" for k in ret.keys())
attributes = ["cn", "laas-vlan", "laas-vlan-name"]
CONN.search("ou=hosts,dc=laas,dc=fr", f"(|{filters})", attributes=attributes)
for entry in CONN.entries:
cn, vlan, name = (str(entry[k]) for k in attributes)
ret[cn]["vlan"] = f"{vlan}: {name}"
return ret
def users_ldap():
"""Get a dict of Gepettists with their room and st"""
CONN.search(
"ou=users,dc=laas,dc=fr", "(o=gepetto)", attributes=["uid", "st", "roomNumber"]
)
return {
str(entry.uid): {
short(k): parse(k, v) for k, v in entry.entry_attributes_as_dict.items()
}
for entry in CONN.entries
}
def machines_display(data, sort_by="datePeremption"):
"""Pandas & Tabulate magic to display machines data."""
df = pd.DataFrame(data).T.sort_values(by=sort_by)
print(tabulate(df.drop("cn", axis=1), headers="keys"))
def get_parser() -> ArgumentParser:
"""Configure argparse."""
parser = ArgumentParser(description=__doc__)
parser.add_argument("-V", "--vlan", action="store_true")
# Filtering
parser.add_argument("-m", "--machine")
parser.add_argument("-R", "--responsable")
parser.add_argument("-u", "--utilisateur")
parser.add_argument("-r", "--room")
# Sorting
parser.add_argument(
"-s",
"--sort_by",
choices=[short(a) for a in ATTRIBUTES],
default="datePeremption",
)
return parser
if __name__ == "__main__":
args = get_parser().parse_args()
machines_data = machines_ldap(**vars(args))
if not machines_data:
print("nothing was found.")
else:
machines_display(machines_data, args.sort_by)
print()
users_data = users_ldap()
for k, v in machines_data.items():
if not v["utilisateur"] or v["utilisateur"] not in users_data:
print(f"{k}: wrong user {v['utilisateur']}")
continue
user = users_data[v["utilisateur"]]
if user["room"] != v["room"]:
print(f"{k}: wrong user's room {user['room']} != {v['room']}")
if user["st"] in ["JAMAIS", "NON-PERTINENT"]:
continue
d, m, y = (int(i) for i in user["st"].split("/"))
st = date(y, m, d)
if v["datePeremption"] > st:
print(
f"{k}: wrong peremption for {user['uid']}: "
f"{v['datePeremption']:%d/%m/%Y} > {st:%d/%m/%Y}"
)