Refonte sync iTop: import complet contacts/domaines/envs/zones/serveurs
- Tables referentielles videes (iTop = maitre) - Import: Person -> contacts, domaine_applicatif -> domains, environnement -> environments, zone -> zones - Import: domain_environments auto-crees depuis les combinaisons VM - Import: VirtualMachine + Server avec responsable_serveur, responsable_domaine, IP, OS, description - Export: status, description, creation VMs manquantes - Matching par hostname court (sans FQDN)
This commit is contained in:
parent
ba48e75b68
commit
3b5f0992b3
@ -1,4 +1,4 @@
|
||||
"""Service iTop REST API — synchronisation bidirectionnelle serveurs et contacts"""
|
||||
"""Service iTop REST API — synchronisation bidirectionnelle"""
|
||||
import logging
|
||||
import requests
|
||||
import json
|
||||
@ -24,261 +24,276 @@ class ITopClient:
|
||||
"auth_user": self.user,
|
||||
"auth_pwd": self.password},
|
||||
verify=False, timeout=30)
|
||||
result = r.json()
|
||||
if result.get("code", -1) != 0:
|
||||
log.error(f"iTop API error: {result.get('message')}")
|
||||
return result
|
||||
return r.json()
|
||||
except Exception as e:
|
||||
log.error(f"iTop connection error: {e}")
|
||||
log.error(f"iTop error: {e}")
|
||||
return {"code": -1, "message": str(e)}
|
||||
|
||||
def get_servers(self):
|
||||
"""Recupere tous les serveurs iTop (Server + VirtualMachine) avec contacts"""
|
||||
servers = []
|
||||
for cls in ["Server", "VirtualMachine"]:
|
||||
r = self._call("core/get", **{
|
||||
"class": cls,
|
||||
"key": f"SELECT {cls}",
|
||||
"output_fields": "name,description,status,managementip,osfamily_id_friendlyname,"
|
||||
"osversion_id_friendlyname,brand_name,model_name,serialnumber,"
|
||||
"organization_name,location_name,business_criticity,cpu,ram,"
|
||||
"contacts_list,responsable_serveur_name,responsable_domaine_name,environnement"
|
||||
})
|
||||
def get_all(self, cls, fields):
|
||||
r = self._call("core/get", **{"class": cls, "key": f"SELECT {cls}", "output_fields": fields})
|
||||
if r.get("code") == 0 and r.get("objects"):
|
||||
for key, obj in r["objects"].items():
|
||||
f = obj["fields"]
|
||||
# Extract contacts (responsable serveur)
|
||||
contacts = f.get("contacts_list", [])
|
||||
contact_names = []
|
||||
contact_emails = []
|
||||
for c in contacts:
|
||||
cname = c.get("contact_id_friendlyname", "")
|
||||
if cname:
|
||||
contact_names.append(cname)
|
||||
return [{"itop_id": o["key"], **o["fields"]} for o in r["objects"].values()]
|
||||
return []
|
||||
|
||||
servers.append({
|
||||
"itop_id": obj["key"],
|
||||
"itop_class": cls,
|
||||
"name": f.get("name", ""),
|
||||
"description": f.get("description", ""),
|
||||
"status": f.get("status", ""),
|
||||
"ip": f.get("managementip", ""),
|
||||
"os_family": f.get("osfamily_id_friendlyname", ""),
|
||||
"os_version": f.get("osversion_id_friendlyname", ""),
|
||||
"brand": f.get("brand_name", ""),
|
||||
"model": f.get("model_name", ""),
|
||||
"serial": f.get("serialnumber", ""),
|
||||
"org": f.get("organization_name", ""),
|
||||
"location": f.get("location_name", ""),
|
||||
"criticity": f.get("business_criticity", ""),
|
||||
"cpu": f.get("cpu", ""),
|
||||
"ram": f.get("ram", ""),
|
||||
"responsable_nom": f.get("responsable_serveur_name", "") or (contact_names[0] if contact_names else ""),
|
||||
"responsable_domaine": f.get("responsable_domaine_name", ""),
|
||||
"environnement": f.get("environnement", ""),
|
||||
})
|
||||
return servers
|
||||
def update(self, cls, key, fields):
|
||||
return self._call("core/update", **{"class": cls, "key": str(key), "fields": fields, "comment": "PatchCenter sync"})
|
||||
|
||||
def get_contacts(self):
|
||||
"""Recupere tous les contacts iTop"""
|
||||
r = self._call("core/get", **{
|
||||
"class": "Person",
|
||||
"key": "SELECT Person",
|
||||
"output_fields": "name,first_name,email,phone,org_name,function"
|
||||
})
|
||||
contacts = []
|
||||
if r.get("code") == 0 and r.get("objects"):
|
||||
for key, obj in r["objects"].items():
|
||||
f = obj["fields"]
|
||||
contacts.append({
|
||||
"itop_id": obj["key"],
|
||||
"name": f.get("name", ""),
|
||||
"first_name": f.get("first_name", ""),
|
||||
"email": f.get("email", ""),
|
||||
"phone": f.get("phone", ""),
|
||||
"org": f.get("org_name", ""),
|
||||
"function": f.get("function", ""),
|
||||
})
|
||||
return contacts
|
||||
|
||||
def get_server_contacts(self, server_class, server_id):
|
||||
"""Recupere les contacts associes a un serveur"""
|
||||
r = self._call("core/get", **{
|
||||
"class": server_class,
|
||||
"key": str(server_id),
|
||||
"output_fields": "contacts_list"
|
||||
})
|
||||
contacts = []
|
||||
if r.get("code") == 0 and r.get("objects"):
|
||||
for key, obj in r["objects"].items():
|
||||
for c in obj["fields"].get("contacts_list", []):
|
||||
contacts.append({
|
||||
"contact_id": c.get("contact_id"),
|
||||
"contact_name": c.get("contact_id_friendlyname", ""),
|
||||
})
|
||||
return contacts
|
||||
|
||||
def update_server(self, server_class, server_id, fields):
|
||||
"""Met a jour un serveur dans iTop"""
|
||||
return self._call("core/update", **{
|
||||
"class": server_class,
|
||||
"key": str(server_id),
|
||||
"fields": fields,
|
||||
"comment": "Sync from PatchCenter"
|
||||
})
|
||||
|
||||
def create_server(self, server_class, fields):
|
||||
"""Cree un serveur dans iTop"""
|
||||
return self._call("core/create", **{
|
||||
"class": server_class,
|
||||
"fields": fields,
|
||||
"comment": "Created by PatchCenter"
|
||||
})
|
||||
def create(self, cls, fields):
|
||||
return self._call("core/create", **{"class": cls, "fields": fields, "comment": "PatchCenter sync"})
|
||||
|
||||
|
||||
def sync_from_itop(db, itop_url, itop_user, itop_pass):
|
||||
"""Importe les serveurs et contacts depuis iTop vers PatchCenter"""
|
||||
"""Import complet depuis iTop: contacts, domaines, envs, zones, serveurs"""
|
||||
client = ITopClient(itop_url, itop_user, itop_pass)
|
||||
stats = {"servers_updated": 0, "servers_created": 0, "contacts_updated": 0, "contacts_created": 0, "errors": []}
|
||||
|
||||
# --- Sync contacts ---
|
||||
itop_contacts = client.get_contacts()
|
||||
for c in itop_contacts:
|
||||
fullname = f"{c['first_name']} {c['name']}".strip()
|
||||
existing = db.execute(text(
|
||||
"SELECT id FROM contacts WHERE LOWER(email) = LOWER(:email) OR LOWER(nom) = LOWER(:nom)"
|
||||
), {"email": c["email"], "nom": fullname}).fetchone()
|
||||
stats = {"contacts": 0, "domains": 0, "environments": 0, "zones": 0,
|
||||
"servers_created": 0, "servers_updated": 0, "errors": []}
|
||||
|
||||
# ─── 1. Contacts (Person) ───
|
||||
persons = client.get_all("Person", "name,first_name,email,phone,org_name,function")
|
||||
for p in persons:
|
||||
fullname = f"{p.get('first_name','')} {p.get('name','')}".strip()
|
||||
existing = db.execute(text("SELECT id FROM contacts WHERE LOWER(email) = LOWER(:e)"),
|
||||
{"e": p.get("email", "")}).fetchone()
|
||||
if existing:
|
||||
db.execute(text("""
|
||||
UPDATE contacts SET nom = :nom, email = :email, telephone = :tel, updated_at = NOW()
|
||||
WHERE id = :id
|
||||
"""), {"id": existing.id, "nom": fullname, "email": c["email"], "tel": c["phone"]})
|
||||
stats["contacts_updated"] += 1
|
||||
db.execute(text("UPDATE contacts SET nom=:n, telephone=:t, updated_at=NOW() WHERE id=:id"),
|
||||
{"id": existing.id, "n": fullname, "t": p.get("phone", "")})
|
||||
else:
|
||||
try:
|
||||
db.execute(text("""
|
||||
INSERT INTO contacts (nom, email, telephone) VALUES (:nom, :email, :tel)
|
||||
"""), {"nom": fullname, "email": c["email"], "tel": c["phone"]})
|
||||
stats["contacts_created"] += 1
|
||||
db.execute(text("INSERT INTO contacts (nom, email, telephone) VALUES (:n, :e, :t)"),
|
||||
{"n": fullname, "e": p.get("email", ""), "t": p.get("phone", "")})
|
||||
stats["contacts"] += 1
|
||||
except Exception as e:
|
||||
stats["errors"].append(f"Contact {fullname}: {e}")
|
||||
|
||||
# --- Sync servers ---
|
||||
itop_servers = client.get_servers()
|
||||
for s in itop_servers:
|
||||
hostname = s["name"].split(".")[0].lower()
|
||||
existing = db.execute(text(
|
||||
"SELECT id FROM servers WHERE LOWER(hostname) = LOWER(:h) OR LOWER(fqdn) = LOWER(:f)"
|
||||
), {"h": hostname, "f": s["name"]}).fetchone()
|
||||
# ─── 2. Domaines applicatifs (typology via VMs) ───
|
||||
vms = client.get_all("VirtualMachine",
|
||||
"name,description,status,managementip,osfamily_id_friendlyname,"
|
||||
"osversion_id_friendlyname,organization_name,cpu,ram,"
|
||||
"responsable_serveur_name,responsable_domaine_name,"
|
||||
"environnement,environnement_name,"
|
||||
"domaine_applicatif_name,zone_name,"
|
||||
"applicationsolution_list,contacts_list,"
|
||||
"virtualhost_name,business_criticity")
|
||||
|
||||
# Also get physical Servers
|
||||
phys = client.get_all("Server",
|
||||
"name,description,status,managementip,osfamily_id_friendlyname,"
|
||||
"osversion_id_friendlyname,organization_name,cpu,ram,"
|
||||
"contacts_list,location_name,brand_name,model_name")
|
||||
|
||||
# Collect unique domains, envs, zones from VMs
|
||||
domain_set = set()
|
||||
env_set = set()
|
||||
zone_set = set()
|
||||
for v in vms:
|
||||
if v.get("domaine_applicatif_name"): domain_set.add(v["domaine_applicatif_name"])
|
||||
if v.get("environnement_name"): env_set.add(v["environnement_name"])
|
||||
if v.get("zone_name"): zone_set.add(v["zone_name"])
|
||||
|
||||
# ─── 3. Insert domains ───
|
||||
domain_map = {} # name -> id
|
||||
for d in sorted(domain_set):
|
||||
existing = db.execute(text("SELECT id FROM domains WHERE LOWER(name)=LOWER(:n)"), {"n": d}).fetchone()
|
||||
if existing:
|
||||
domain_map[d] = existing.id
|
||||
else:
|
||||
db.execute(text("INSERT INTO domains (name, code) VALUES (:n, :c)"),
|
||||
{"n": d, "c": d[:10].upper().replace(" ", "")})
|
||||
db.commit()
|
||||
row = db.execute(text("SELECT id FROM domains WHERE name=:n"), {"n": d}).fetchone()
|
||||
domain_map[d] = row.id
|
||||
stats["domains"] += 1
|
||||
|
||||
# ─── 4. Insert environments ───
|
||||
env_map = {}
|
||||
for e in sorted(env_set):
|
||||
existing = db.execute(text("SELECT id FROM environments WHERE LOWER(name)=LOWER(:n)"), {"n": e}).fetchone()
|
||||
if existing:
|
||||
env_map[e] = existing.id
|
||||
else:
|
||||
db.execute(text("INSERT INTO environments (name, code) VALUES (:n, :c)"),
|
||||
{"n": e, "c": e[:10].upper().replace(" ", "")})
|
||||
db.commit()
|
||||
row = db.execute(text("SELECT id FROM environments WHERE name=:n"), {"n": e}).fetchone()
|
||||
env_map[e] = row.id
|
||||
stats["environments"] += 1
|
||||
|
||||
# ─── 5. Insert zones ───
|
||||
zone_map = {}
|
||||
for z in sorted(zone_set):
|
||||
existing = db.execute(text("SELECT id FROM zones WHERE LOWER(name)=LOWER(:n)"), {"n": z}).fetchone()
|
||||
if existing:
|
||||
zone_map[z] = existing.id
|
||||
else:
|
||||
db.execute(text("INSERT INTO zones (name, is_dmz) VALUES (:n, :d)"),
|
||||
{"n": z, "d": "dmz" in z.lower()})
|
||||
db.commit()
|
||||
row = db.execute(text("SELECT id FROM zones WHERE name=:n"), {"n": z}).fetchone()
|
||||
zone_map[z] = row.id
|
||||
stats["zones"] += 1
|
||||
|
||||
# ─── 6. Create domain_environments associations ───
|
||||
de_map = {} # (domain, env) -> id
|
||||
for v in vms:
|
||||
dom = v.get("domaine_applicatif_name", "")
|
||||
env = v.get("environnement_name", "")
|
||||
if dom and env and dom in domain_map and env in env_map:
|
||||
key = (dom, env)
|
||||
if key not in de_map:
|
||||
did, eid = domain_map[dom], env_map[env]
|
||||
existing = db.execute(text(
|
||||
"SELECT id FROM domain_environments WHERE domain_id=:d AND environment_id=:e"),
|
||||
{"d": did, "e": eid}).fetchone()
|
||||
if existing:
|
||||
de_map[key] = existing.id
|
||||
else:
|
||||
db.execute(text(
|
||||
"INSERT INTO domain_environments (domain_id, environment_id, responsable_nom, responsable_email) VALUES (:d, :e, :rn, :re)"),
|
||||
{"d": did, "e": eid,
|
||||
"rn": v.get("responsable_domaine_name", ""),
|
||||
"re": ""})
|
||||
db.commit()
|
||||
row = db.execute(text(
|
||||
"SELECT id FROM domain_environments WHERE domain_id=:d AND environment_id=:e"),
|
||||
{"d": did, "e": eid}).fetchone()
|
||||
de_map[key] = row.id
|
||||
|
||||
# ─── 7. Insert servers (VMs) ───
|
||||
itop_status_map = {"production": "en_production", "stock": "stock",
|
||||
"implementation": "en_cours", "obsolete": "decommissionne"}
|
||||
etat = itop_status_map.get(s["status"], "en_production")
|
||||
|
||||
for v in vms:
|
||||
hostname = v.get("name", "").split(".")[0].lower()
|
||||
if not hostname:
|
||||
continue
|
||||
|
||||
dom = v.get("domaine_applicatif_name", "")
|
||||
env = v.get("environnement_name", "")
|
||||
de_id = de_map.get((dom, env))
|
||||
zone_id = zone_map.get(v.get("zone_name", ""))
|
||||
|
||||
existing = db.execute(text("SELECT id FROM servers WHERE LOWER(hostname)=LOWER(:h)"),
|
||||
{"h": hostname}).fetchone()
|
||||
|
||||
vals = {
|
||||
"hostname": hostname,
|
||||
"fqdn": v.get("name", hostname),
|
||||
"os_family": "linux" if "linux" in v.get("osfamily_id_friendlyname", "").lower() else "windows",
|
||||
"os_version": v.get("osversion_id_friendlyname", ""),
|
||||
"machine_type": "vm",
|
||||
"etat": itop_status_map.get(v.get("status", ""), "en_production"),
|
||||
"de_id": de_id,
|
||||
"zone_id": zone_id,
|
||||
"resp_srv": v.get("responsable_serveur_name", ""),
|
||||
"resp_dom": v.get("responsable_domaine_name", ""),
|
||||
"desc": v.get("description", ""),
|
||||
"ip": v.get("managementip", ""),
|
||||
"criticity": v.get("business_criticity", ""),
|
||||
"cpu": v.get("cpu", ""),
|
||||
"ram": v.get("ram", ""),
|
||||
"hypervisor": v.get("virtualhost_name", ""),
|
||||
}
|
||||
|
||||
if existing:
|
||||
updates = {"sid": existing.id}
|
||||
sets = []
|
||||
if s["os_version"]:
|
||||
sets.append("os_version = :osv")
|
||||
updates["osv"] = s["os_version"]
|
||||
if s["ip"]:
|
||||
sets.append("fqdn = :fqdn")
|
||||
updates["fqdn"] = s["name"]
|
||||
if s["location"]:
|
||||
sets.append("site = :site")
|
||||
updates["site"] = s["location"]
|
||||
if s.get("responsable_nom"):
|
||||
sets.append("responsable_nom = :resp_nom")
|
||||
updates["resp_nom"] = s["responsable_nom"]
|
||||
if s.get("responsable_domaine"):
|
||||
sets.append("referent_nom = :ref_nom")
|
||||
updates["ref_nom"] = s["responsable_domaine"]
|
||||
if s.get("description"):
|
||||
sets.append("commentaire = :comm")
|
||||
updates["comm"] = s["description"]
|
||||
if s.get("ip"):
|
||||
sets.append("fqdn = :fqdn")
|
||||
updates["fqdn"] = s["name"]
|
||||
if sets:
|
||||
sets.append("updated_at = NOW()")
|
||||
db.execute(text(f"UPDATE servers SET {', '.join(sets)} WHERE id = :sid"), updates)
|
||||
db.execute(text("""
|
||||
UPDATE servers SET fqdn=:fqdn, os_family=:os_family, os_version=:os_version,
|
||||
etat=:etat, domain_env_id=:de_id, zone_id=:zone_id,
|
||||
responsable_nom=:resp_srv, referent_nom=:resp_dom,
|
||||
commentaire=:desc, updated_at=NOW()
|
||||
WHERE id=:sid
|
||||
"""), {**vals, "sid": existing.id})
|
||||
stats["servers_updated"] += 1
|
||||
else:
|
||||
try:
|
||||
db.execute(text("""
|
||||
INSERT INTO servers (hostname, fqdn, os_family, os_version, machine_type,
|
||||
tier, etat, ssh_port, ssh_user, ssh_method, site)
|
||||
VALUES (:h, :f, :osf, :osv, :mt, 'a_definir', :etat, 22, 'root', 'ssh_key', :site)
|
||||
etat, domain_env_id, zone_id, responsable_nom, referent_nom,
|
||||
commentaire, ssh_port, ssh_user, ssh_method, tier)
|
||||
VALUES (:hostname, :fqdn, :os_family, :os_version, :machine_type,
|
||||
:etat, :de_id, :zone_id, :resp_srv, :resp_dom,
|
||||
:desc, 22, 'root', 'ssh_key', 'a_definir')
|
||||
"""), vals)
|
||||
stats["servers_created"] += 1
|
||||
except Exception as e:
|
||||
stats["errors"].append(f"Server {hostname}: {e}")
|
||||
|
||||
# ─── 8. Insert physical servers ───
|
||||
for s in phys:
|
||||
hostname = s.get("name", "").split(".")[0].lower()
|
||||
if not hostname:
|
||||
continue
|
||||
existing = db.execute(text("SELECT id FROM servers WHERE LOWER(hostname)=LOWER(:h)"),
|
||||
{"h": hostname}).fetchone()
|
||||
if not existing:
|
||||
try:
|
||||
contacts = s.get("contacts_list", [])
|
||||
resp = contacts[0].get("contact_id_friendlyname", "") if contacts else ""
|
||||
db.execute(text("""
|
||||
INSERT INTO servers (hostname, fqdn, os_family, os_version, machine_type,
|
||||
etat, responsable_nom, commentaire, ssh_port, ssh_user, ssh_method, tier)
|
||||
VALUES (:h, :f, :osf, :osv, 'physical', 'en_production', :resp, :desc,
|
||||
22, 'root', 'ssh_key', 'tier0')
|
||||
"""), {
|
||||
"h": hostname, "f": s["name"],
|
||||
"osf": "linux" if "linux" in s["os_family"].lower() else "windows",
|
||||
"osv": s["os_version"], "etat": etat, "site": s["location"],
|
||||
"mt": "vm" if s["itop_class"] == "VirtualMachine" else "physical",
|
||||
"h": hostname, "f": s.get("name", hostname),
|
||||
"osf": "linux" if "linux" in s.get("osfamily_id_friendlyname", "").lower() else "windows",
|
||||
"osv": s.get("osversion_id_friendlyname", ""),
|
||||
"resp": resp, "desc": s.get("description", ""),
|
||||
})
|
||||
stats["servers_created"] += 1
|
||||
except Exception as e:
|
||||
stats["errors"].append(f"Server {s['name']}: {e}")
|
||||
stats["errors"].append(f"Physical {hostname}: {e}")
|
||||
|
||||
db.commit()
|
||||
log.info(f"iTop sync: {stats}")
|
||||
log.info(f"iTop full sync: {stats}")
|
||||
return stats
|
||||
|
||||
|
||||
def sync_to_itop(db, itop_url, itop_user, itop_pass):
|
||||
"""Exporte les serveurs PatchCenter vers iTop (mise a jour)"""
|
||||
"""Exporte les infos patching de PatchCenter vers iTop"""
|
||||
client = ITopClient(itop_url, itop_user, itop_pass)
|
||||
stats = {"updated": 0, "created": 0, "errors": []}
|
||||
|
||||
# Get current iTop servers for matching (by full name AND by hostname part)
|
||||
itop_servers_raw = client.get_servers()
|
||||
itop_servers = {}
|
||||
for s in itop_servers_raw:
|
||||
itop_servers[s["name"].lower()] = s
|
||||
short = s["name"].split(".")[0].lower()
|
||||
if short not in itop_servers:
|
||||
itop_servers[short] = s
|
||||
# Get iTop VMs indexed by short name
|
||||
itop_vms = {}
|
||||
for v in client.get_all("VirtualMachine", "name"):
|
||||
itop_vms[v["name"].split(".")[0].lower()] = v
|
||||
|
||||
# Get patchcenter servers
|
||||
rows = db.execute(text("SELECT hostname, fqdn, os_version, os_family, etat, site, responsable_nom, commentaire FROM servers")).fetchall()
|
||||
# Get PatchCenter servers
|
||||
rows = db.execute(text(
|
||||
"SELECT hostname, fqdn, os_version, etat, commentaire, tier FROM servers"
|
||||
)).fetchall()
|
||||
|
||||
status_map = {"en_production": "production", "decommissionne": "obsolete",
|
||||
"stock": "stock", "en_cours": "implementation"}
|
||||
|
||||
for srv in rows:
|
||||
fqdn = (srv.fqdn or "").lower()
|
||||
hostname = (srv.hostname or "").lower()
|
||||
itop_srv = itop_servers.get(fqdn) or itop_servers.get(hostname)
|
||||
itop_vm = itop_vms.get(hostname)
|
||||
|
||||
if itop_srv:
|
||||
if itop_vm:
|
||||
fields = {}
|
||||
if srv.commentaire:
|
||||
fields["description"] = srv.commentaire
|
||||
elif srv.os_version:
|
||||
fields["description"] = f"OS: {srv.os_version}"
|
||||
if srv.etat:
|
||||
fields["status"] = status_map.get(srv.etat, "production")
|
||||
|
||||
if srv.commentaire:
|
||||
fields["description"] = srv.commentaire
|
||||
if fields:
|
||||
r = client.update_server(itop_srv["itop_class"], itop_srv["itop_id"], fields)
|
||||
r = client.update("VirtualMachine", itop_vm["itop_id"], fields)
|
||||
if r.get("code") == 0:
|
||||
stats["updated"] += 1
|
||||
else:
|
||||
stats["errors"].append(f"{srv.hostname}: {r.get('message')}")
|
||||
|
||||
stats["errors"].append(f"{hostname}: {r.get('message', '')[:60]}")
|
||||
else:
|
||||
# Server not in iTop — create as VirtualMachine
|
||||
fields = {
|
||||
# Create VM in iTop
|
||||
r = client.create("VirtualMachine", {
|
||||
"name": srv.hostname,
|
||||
"org_id": "SELECT Organization WHERE name = 'MPCZ'",
|
||||
"status": status_map.get(srv.etat, "production"),
|
||||
"description": srv.commentaire or f"OS: {srv.os_version or 'N/A'}",
|
||||
}
|
||||
r = client.create_server("VirtualMachine", fields)
|
||||
})
|
||||
if r.get("code") == 0:
|
||||
stats["created"] += 1
|
||||
else:
|
||||
stats["errors"].append(f"Create {srv.hostname}: {r.get('message')}")
|
||||
stats["errors"].append(f"Create {hostname}: {r.get('message', '')[:60]}")
|
||||
|
||||
log.info(f"iTop export: {stats}")
|
||||
return stats
|
||||
|
||||
Loading…
Reference in New Issue
Block a user