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:
1
.agents.json
Normal file
1
.agents.json
Normal file
File diff suppressed because one or more lines are too long
@@ -19,6 +19,8 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure ·
|
||||
|
||||
<!-- Append entries below this line -->
|
||||
|
||||
2026-07-04 | Howard-Home | gururmm/agents-move | POST /api/agents/:id/move appears to CREATE a duplicate agent record (same device_id, new id) in the target site instead of moving; old record goes stale. Also 500s under repeated/rapid calls (works once in isolation). Result: ~28 duplicate agent pairs created 2026-07-04 (24 Dataforth D2 machines now have a live D1 dup + stale D2 original, plus staging reassign dups). STOPPED all RMM writes. [ctx: endpoint=/api/agents/:id/move symptom=duplicate+500]
|
||||
|
||||
2026-07-04 | Howard-Home | wiki-compile/dataforth | [correction] flagged 192.168.1.1 as a VLAN2 gateway/IP collision WARNING from a stale wiki note; Howard confirmed onsite there is no VLAN2 conflict - should have checked/trusted the onsite verification instead of raising an alarm from an assumption
|
||||
|
||||
2026-07-04 | Howard-Home | bash/quoting | [friction] inline PS-in-bash heredoc with nested quotes mangled by CommandLineToArgvW on dispatch to RMM; fixed by file+EncodedCommand path [ctx: ref=feedback_windows_quote_stripping]
|
||||
|
||||
58
projects/gps-rmm-audit/dedup-plan.json
Normal file
58
projects/gps-rmm-audit/dedup-plan.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"delete_ids": [
|
||||
"cfa93bb6-0cdc-4d4e-a29e-1609cda6f047",
|
||||
"e9ea7c6a-1aa3-4f67-9138-5d49bf2dd069",
|
||||
"3bf75d80-0380-46b0-a8a9-88a7768a2597",
|
||||
"d6c4aee3-6426-480a-96f2-0ca5bec57568",
|
||||
"3f656f3e-4906-4409-9172-66aa11000148",
|
||||
"33733e69-9160-4030-9af5-e70976a42ce6",
|
||||
"f2465fac-4d6b-46f1-9cc7-141b3a6e57b6",
|
||||
"013d2316-acd2-4a2c-a92c-39889b1c9d02",
|
||||
"fc281be9-0f98-4ef4-831b-1c95c133f207",
|
||||
"4fea5b33-e803-4e73-ab80-50cca2256f2a",
|
||||
"2819d8f1-02a7-4dcf-97b7-4cc0d0488832",
|
||||
"9b927ceb-8883-4a4f-8627-033a8a48bc9d",
|
||||
"dde8fc7d-5fb8-4da6-9f60-821d987a3154",
|
||||
"c11570aa-fdfa-4329-bcd5-dacdded92c5f",
|
||||
"5c9bbb5b-f736-4aae-a75d-89c977a497f4",
|
||||
"3ec67fed-be27-4777-8283-6e96a037cc1f",
|
||||
"b6376872-3d7a-4210-9bcf-23af23a5eb26",
|
||||
"a7c6dadf-40b0-4f55-8d4f-a1d73d62563c",
|
||||
"b7a32d56-52b4-4f91-8fd4-308ee181eb55",
|
||||
"d7bbc182-d31e-4101-a562-b0b37daeb346",
|
||||
"776e85c3-7b9e-4da6-a2d0-b8f68a9558fb",
|
||||
"db17e069-2948-4cbc-97ea-1da721edcaf5",
|
||||
"95991b45-d843-4586-8275-9996d0d9ae17",
|
||||
"89f5e71e-0ea7-44fe-baf9-31218dbd40f7",
|
||||
"2148e7c1-5a4e-4d40-bce8-8bfced6c4623",
|
||||
"c212e3b9-7a49-4a8d-a13d-1edc71da4b79",
|
||||
"960f9258-d754-4998-9d52-6a96f55fdcab",
|
||||
"689f646f-066f-48c5-88bd-3eb82b8601d8",
|
||||
"d44e5a66-d391-4ffd-bc0f-308e23430357",
|
||||
"0bfcb3d1-6916-4c3f-99ed-63741a4c1c0b",
|
||||
"80bd5f3c-b20c-448d-8927-7f238f1176ce",
|
||||
"1c2167d0-d04b-4a4e-830a-4bc2cada5e4c",
|
||||
"0af00285-a810-48ff-b9ce-bc8dd1ead292",
|
||||
"0eab1141-c4b2-4b37-9ad9-34ed871f088b",
|
||||
"1e6c4735-a0dd-48aa-9ce2-bb28af25abd8",
|
||||
"15177ae0-0e2e-42f3-b563-4487e7755c0e",
|
||||
"04537ca4-b088-4899-a224-adf1f1537169",
|
||||
"6ca769f4-526c-4bcd-bbaf-8b037e43a522",
|
||||
"06b9a807-017d-4395-b3ed-20ab374126fd"
|
||||
],
|
||||
"review_hostnames": [
|
||||
"BridgettePSHomeComputer",
|
||||
"DESKTOP-BTR2AM3",
|
||||
"GURU-5070",
|
||||
"MSI",
|
||||
"Maras-HP-Laptop",
|
||||
"PST-SURFACE",
|
||||
"RECEPTIONIST-PC",
|
||||
"RMM-TEST-MACHINE",
|
||||
"SERVER",
|
||||
"Sif-Laptop554",
|
||||
"Sif-Laptop555",
|
||||
"bfcfbc739d23",
|
||||
"gururmm"
|
||||
]
|
||||
}
|
||||
41
projects/gps-rmm-audit/dedup-plan.md
Normal file
41
projects/gps-rmm-audit/dedup-plan.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# GuruRMM duplicate-agent dedup plan (2026-07-04)
|
||||
|
||||
## Root cause (FIXED in code)
|
||||
`server/src/ws/mod.rs` — both agent-connect enrollment paths deduped by **`(site_id, device_id)`**
|
||||
(`get_agent_by_site_and_device`). A machine already enrolled in one site that ran a *different*
|
||||
site's installer (a new site code, or the Staging installer) was not found in the target site, so
|
||||
the server **created a new `agents` row** → a cross-site duplicate sharing the same `device_id`.
|
||||
The `/api/agents/:id/move` endpoint itself is a clean `UPDATE` — it was NOT the culprit; the
|
||||
duplicates were minted at re-enrollment. (The 500s under load are a separate server-capacity issue.)
|
||||
|
||||
**Fix:** added `db::get_agent_by_device_id()` (global, device_id is hardware-unique) and changed
|
||||
both enroll paths to look up by **real device_id across all sites** and **re-home** the existing
|
||||
record (`move_agent_to_site`) instead of creating a duplicate. Path 2 (enrollment key) only uses the
|
||||
global match when a genuine `device_id` is present — it falls back to the site-scoped hostname match
|
||||
when there is none, so distinct same-named machines (e.g. the 4x `SERVER`) are never wrongly merged.
|
||||
A blanket `UNIQUE(device_id)` DB constraint is intentionally NOT added — it would collide on the
|
||||
legacy hostname-fallback rows. `cargo check` passes.
|
||||
|
||||
## Deploy sequence (order matters)
|
||||
1. **Deploy the fixed server** (build + restart). Until then, re-homing/re-enroll can still duplicate.
|
||||
2. **Delete the 39 stale orphans** (below) — `dedup-plan.json.delete_ids`.
|
||||
3. **Re-home the 37 wrong-site survivors** (below) — now safe (move UPDATEs, no dup). Many will
|
||||
also self-correct on next enrollment once the fixed server is live.
|
||||
|
||||
## 39 SAFE deletes (same device_id, stale orphan — keep the live record, delete the stale one)
|
||||
Machine-readable ids: `projects/gps-rmm-audit/dedup-plan.json` → `delete_ids`.
|
||||
- 24 Dataforth `D2-*` (stale D2 originals; live dup currently in D1 — see site-fix)
|
||||
- Staging/Bucket-C re-enroll orphans (CNX-LAB-00, CURTIS-002-W7, Mel-PC, TPS-SVR, etc.)
|
||||
|
||||
## 37 SITE-FIX (survivor is in the WRONG site after dedup — re-home once server is fixed)
|
||||
- 24 Dataforth machines: live record sits in **D1**, belongs in **D2** → move to D2.
|
||||
- ~13 Bucket-C machines: live record still in **Staging** → re-home to real client
|
||||
(Safesite/Bell, Mineralogical, IMC, Curtis, etc.) via `reassign-staging.py` (works once move is reliable).
|
||||
|
||||
## 13 MANUAL review (different device_id — NOT auto-deleted; likely reimage or genuinely distinct)
|
||||
BridgettePSHomeComputer, DESKTOP-BTR2AM3, GURU-5070, MSI, Maras-HP-Laptop, PST-SURFACE,
|
||||
RECEPTIONIST-PC, RMM-TEST-MACHINE, SERVER (4x), Sif-Laptop554, Sif-Laptop555, bfcfbc739d23, gururmm.
|
||||
These share a hostname but have different device_ids — inspect each before any delete.
|
||||
|
||||
## Note
|
||||
The current RMM enrollment count (~105) is INFLATED by these duplicates; true unique-device count is lower.
|
||||
@@ -3,63 +3,45 @@
|
||||
Online = ActiveConnections ProcessType==2 (guest agent connected). Recency = GuestInfoUpdateTime.
|
||||
Rebuilt 2026-07-04. Staging installer pushed to all ONLINE machines (land in Staging -> reassign-staging.py).
|
||||
|
||||
## ONLINE now (17)
|
||||
## ONLINE now (6)
|
||||
- CP-QB [Curtis Plumbing] (1563d)
|
||||
- CURTIS-002-W7 [Curtis Plumbing] (0d)
|
||||
- DESKTOP-EVA4H1A [Gary A Hartman LLC] (0d)
|
||||
- IMC-PRINTSERVER [Instrumental Music Center] (0d)
|
||||
- LAPTOP-UBTI0IE3 [Instrumental Music Center] (0d)
|
||||
- DESKTOP-ERBA22G [Mineralogical Record] (0d)
|
||||
- PUGET-CW [Mineralogical Record] (0d)
|
||||
- CNX-LAB-00 [Ridgetop Group] (0d)
|
||||
- RGI-DC [Ridgetop Group] (0d)
|
||||
- RTG-HOST01 [Ridgetop Group] (0d)
|
||||
- DESKTOP-PL2RCGL [Robyn Pittman] (0d)
|
||||
- DESKTOP-2KKLG2B [Safesite] (0d)
|
||||
- STAMBACK-NEW05 [Stamback Septic] (0d)
|
||||
- MEL-PC [The Prairie Schooner] (0d)
|
||||
- TPS-SVR [The Prairie Schooner] (0d)
|
||||
- SERVER-OLD [Zeus Nestora] (0d)
|
||||
- WHITE-PC [Zeus Nestora] (0d)
|
||||
- DESKTOP-CLJKB39 [Multicultural Counseling Center] (0d)
|
||||
- DESKTOP-BA45FRS [Safesite] (0d)
|
||||
- DESKTOP-EJM109L [Safesite] (0d)
|
||||
- DESKTOP-6HT5SJ9 [The Marc Group] (0d)
|
||||
|
||||
## active <=14d (31)
|
||||
- BRETTWAREHOUSE [Brett Interiors] (0d)
|
||||
- DESKTOP-6LL5T6B [Brett Interiors] (0d)
|
||||
## active <=14d (24)
|
||||
- KAT1 [Business Services of Tucson LLC] (0d)
|
||||
- HSM-CATHY [Horseshoe Management] (1d)
|
||||
- DESKTOP-3ST7GFD [Inside Track Productions] (0d)
|
||||
- HSM-CATHY [Horseshoe Management] (2d)
|
||||
- IMC-LUIS [Instrumental Music Center] (0d)
|
||||
- IMC-M-EDSERVICE [Instrumental Music Center] (2d)
|
||||
- LAPTOP-PNVA9G51 [Instrumental Music Center] (4d)
|
||||
- REPAIRADMIN [Instrumental Music Center] (1d)
|
||||
- DESKTOP-OC2PH4I [Marty Ryan] (0d)
|
||||
- CHRISTIPC2024 [Mineralogical Record] (0d)
|
||||
- DESKTOP-CLJKB39 [Multicultural Counseling Center] (6d)
|
||||
- PLS-SERVER [PUTT LAND SURVEYING, INC.] (8d)
|
||||
- DESKTOP-EKC9PRV [Pro-Tech Services] (0d)
|
||||
- LAPTOP-73UDDTTK [Pro-Tech Services] (1d)
|
||||
- RWD-CHRIS [Reliant Well Drilling and Pump Corporate] (1d)
|
||||
- WILLCOXDOTADMIN [Reliant Well Drilling and Pump Corporate] (1d)
|
||||
- WILLCOXDOTADMIN [Reliant Well Drilling and Pump Corporate] (2d)
|
||||
- DESKTOP-8KQIDKH [Safesite] (0d)
|
||||
- DESKTOP-ARNPE1U [Safesite] (1d)
|
||||
- DESKTOP-B3ELJF5 [Safesite] (1d)
|
||||
- DESKTOP-BA45FRS [Safesite] (0d)
|
||||
- DESKTOP-EJM109L [Safesite] (0d)
|
||||
- DESKTOP-ARNPE1U [Safesite] (2d)
|
||||
- DESKTOP-B3ELJF5 [Safesite] (2d)
|
||||
- DESKTOP-FUB3PAV [Safesite] (3d)
|
||||
- DESKTOP-V3H99FC [Safesite] (1d)
|
||||
- DESKTOP-V3H99FC [Safesite] (2d)
|
||||
- DESKTOP-V9F9L23 [Safesite] (9d)
|
||||
- LAPTOP-NFB98THE [Safesite] (2d)
|
||||
- JEREE [Stamback Septic] (1d)
|
||||
- DESKTOP-6HT5SJ9 [The Marc Group] (0d)
|
||||
- JEREE [Stamback Septic] (2d)
|
||||
- ZEUS-ACCOUNTING [Zeus Nestora] (0d)
|
||||
- ZEUS-SHERRI [Zeus Nestora] (0d)
|
||||
- ZEUS1 [Zeus Nestora] (0d)
|
||||
|
||||
## stale 15-45d (4)
|
||||
- GND-L-3 [Grabb & Durando Law Office] (20d)
|
||||
- DESKTOP-KRHQ5TS [Instrumental Music Center] (15d)
|
||||
- DESKTOP-KRHQ5TS [Instrumental Music Center] (16d)
|
||||
- RWD-ALLENDESKTO [Reliant Well Drilling and Pump Corporate] (18d)
|
||||
- DESKTOP-FMDIK0Q [Safesite] (42d)
|
||||
- DESKTOP-FMDIK0Q [Safesite] (43d)
|
||||
|
||||
## dead/no-session (58)
|
||||
- DESKTOP-SUFJR0J [Bill Tedards] (no SC)
|
||||
@@ -74,22 +56,22 @@ Rebuilt 2026-07-04. Staging installer pushed to all ONLINE machines (land in Sta
|
||||
- Sheilaâs MacBook Pro [Heieck, Sheila] (no SC)
|
||||
- HSM-RANDI [Horseshoe Management] (no SC)
|
||||
- HSM-SURFACE [Horseshoe Management] (no SC)
|
||||
- DESKTOP-JQ0D38J [Instrumental Music Center] (105d)
|
||||
- DESKTOP-URV3UGR [Instrumental Music Center] (79d)
|
||||
- DESKTOP-JQ0D38J [Instrumental Music Center] (106d)
|
||||
- DESKTOP-URV3UGR [Instrumental Music Center] (80d)
|
||||
- IMC-EVENTS [Instrumental Music Center] (110d)
|
||||
- IMC-L1-GRAPHICS [Instrumental Music Center] (no SC)
|
||||
- PHIL [Instrumental Music Center] (no SC)
|
||||
- PHIL2021LAPTOP [Instrumental Music Center] (141d)
|
||||
- PURCHASINGCOMP [Instrumental Music Center] (79d)
|
||||
- PURCHASINGCOMP [Instrumental Music Center] (80d)
|
||||
- LHLH [Little Hearts Little Hands] (no SC)
|
||||
- WIN-KNVO6MUMMEM [Little Hearts Little Hands] (no SC)
|
||||
- CPC-chris-UZR6E [MVAN Enterprises Inc] (no SC)
|
||||
- DESKTOP-I7504C5 [MVAN Enterprises Inc] (no SC)
|
||||
- Juneâs MacBook Pro [MVAN Enterprises Inc] (no SC)
|
||||
- MITCH-LAPTOP [MVAN Enterprises Inc] (138d)
|
||||
- MITCH-LAPTOP [MVAN Enterprises Inc] (139d)
|
||||
- DESKTOP-3VPT017 [Mineralogical Record] (no SC)
|
||||
- DESKTOP-9QHSCIT [Mineralogical Record] (no SC)
|
||||
- DESKTOP-S1HPLDF [Multicultural Counseling Center] (64d)
|
||||
- DESKTOP-S1HPLDF [Multicultural Counseling Center] (65d)
|
||||
- PLS-FOUR [PUTT LAND SURVEYING, INC.] (no SC)
|
||||
- PLS-FRONT [PUTT LAND SURVEYING, INC.] (no SC)
|
||||
- PLS-LAPTOP [PUTT LAND SURVEYING, INC.] (no SC)
|
||||
@@ -106,7 +88,7 @@ Rebuilt 2026-07-04. Staging installer pushed to all ONLINE machines (land in Sta
|
||||
- RELIANT-L01 [Reliant Well Drilling and Pump Corporate] (no SC)
|
||||
- RELIANT-L02 [Reliant Well Drilling and Pump Corporate] (no SC)
|
||||
- RELIANT-L03 [Reliant Well Drilling and Pump Corporate] (no SC)
|
||||
- RWD-ALANLAPTOP [Reliant Well Drilling and Pump Corporate] (126d)
|
||||
- RWD-ALANLAPTOP [Reliant Well Drilling and Pump Corporate] (127d)
|
||||
- WILCOXADMIN [Reliant Well Drilling and Pump Corporate] (no SC)
|
||||
- 1225-LENOVO-E16 [Safesite] (49d)
|
||||
- DESKTOP-QAR6D04 [Safesite] (142d)
|
||||
|
||||
@@ -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