sync: auto-sync from HOWARD-HOME at 2026-07-04 15:30:44
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-04 15:30:44
This commit is contained in:
@@ -7,15 +7,23 @@
|
||||
# client automatically. Idempotent — run it on a schedule or on demand.
|
||||
#
|
||||
# Env: RMM, TOK (GuruRMM), SK (Syncro api key). --dry = report only.
|
||||
import json,urllib.request,ssl,os,sys
|
||||
import json,urllib.request,ssl,os,sys,time
|
||||
RMM=os.environ["RMM"]; TOK=os.environ["TOK"]; SK=os.environ["SK"]
|
||||
ctx=ssl.create_default_context(); DRY="--dry" in sys.argv
|
||||
STAGING_CLIENT="Staging - Auto Enroll"
|
||||
FIX_HOSTS=set(h.strip().lower() for h in os.environ.get("FIX_HOSTS","").split(",") if h.strip())
|
||||
def rget(path):
|
||||
return json.loads("".join(c for c in urllib.request.urlopen(urllib.request.Request(f"{RMM}{path}",headers={"Authorization":f"Bearer {TOK}"}),context=ctx,timeout=30).read().decode("utf-8","replace") if ord(c)>=32 or c in "\t\n\r"))
|
||||
def move(aid,site_id):
|
||||
req=urllib.request.Request(f"{RMM}/api/agents/{aid}/move",data=json.dumps({"site_id":site_id}).encode(),method="POST",headers={"Authorization":f"Bearer {TOK}","Content-Type":"application/json"})
|
||||
urllib.request.urlopen(req,context=ctx,timeout=20)
|
||||
# move endpoint is rate-limited: throttle + retry on 500
|
||||
last=None
|
||||
for attempt in range(4):
|
||||
try:
|
||||
req=urllib.request.Request(f"{RMM}/api/agents/{aid}/move",data=json.dumps({"site_id":site_id}).encode(),method="POST",headers={"Authorization":f"Bearer {TOK}","Content-Type":"application/json"})
|
||||
urllib.request.urlopen(req,context=ctx,timeout=20); return
|
||||
except Exception as e:
|
||||
last=e; time.sleep(2.0*(attempt+1))
|
||||
raise last
|
||||
def syncro_customer(hostname):
|
||||
raw=urllib.request.urlopen(urllib.request.Request(f"https://computerguru.syncromsp.com/api/v1/customer_assets?query={urllib.parse.quote(hostname)}&api_key={SK}"),context=ctx,timeout=25).read()
|
||||
raw="".join(chr(b) for b in raw if b>=32 or b in (9,10,13))
|
||||
@@ -31,8 +39,8 @@ def norm(s):
|
||||
s=re.sub(r'\b(llc|inc|incorporated|corp|corporation|company|co|ltd|the)\b',' ',s)
|
||||
return re.sub(r'\s+',' ',s).strip()
|
||||
agents=rget("/api/agents")
|
||||
staging=[a for a in agents if a.get("client_name")==STAGING_CLIENT]
|
||||
print(f"{len(staging)} agents in Staging")
|
||||
staging=[a for a in agents if a.get("client_name")==STAGING_CLIENT or (a.get("hostname") or "").lower() in FIX_HOSTS]
|
||||
print(f"{len(staging)} agents to reconcile (Staging + FIX_HOSTS)")
|
||||
# GuruRMM client -> a target site id (prefer 'Main'/'Main Office', else first); keyed by normalized name
|
||||
clients=rget("/api/clients")
|
||||
name2site={}
|
||||
@@ -47,7 +55,9 @@ for a in staging:
|
||||
cust=syncro_customer(a["hostname"])
|
||||
site=name2site.get(norm(cust))
|
||||
if cust and site:
|
||||
if not DRY: move(a["id"],site)
|
||||
if not DRY:
|
||||
try: move(a["id"],site); time.sleep(1.5)
|
||||
except Exception as e: unmatched.append(f"{a['hostname']} (move FAILED: {e})"); continue
|
||||
moved+=1; print(f" {a['hostname']} -> '{cust}'")
|
||||
else:
|
||||
unmatched.append(f"{a['hostname']} (syncro='{cust}')")
|
||||
|
||||
Reference in New Issue
Block a user