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 -->
|
<!-- 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 | 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]
|
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.
|
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).
|
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)
|
- CP-QB [Curtis Plumbing] (1563d)
|
||||||
- CURTIS-002-W7 [Curtis Plumbing] (0d)
|
|
||||||
- DESKTOP-EVA4H1A [Gary A Hartman LLC] (0d)
|
|
||||||
- IMC-PRINTSERVER [Instrumental Music Center] (0d)
|
- IMC-PRINTSERVER [Instrumental Music Center] (0d)
|
||||||
- LAPTOP-UBTI0IE3 [Instrumental Music Center] (0d)
|
- DESKTOP-CLJKB39 [Multicultural Counseling Center] (0d)
|
||||||
- DESKTOP-ERBA22G [Mineralogical Record] (0d)
|
- DESKTOP-BA45FRS [Safesite] (0d)
|
||||||
- PUGET-CW [Mineralogical Record] (0d)
|
- DESKTOP-EJM109L [Safesite] (0d)
|
||||||
- CNX-LAB-00 [Ridgetop Group] (0d)
|
- DESKTOP-6HT5SJ9 [The Marc 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)
|
|
||||||
|
|
||||||
## active <=14d (31)
|
## active <=14d (24)
|
||||||
- BRETTWAREHOUSE [Brett Interiors] (0d)
|
|
||||||
- DESKTOP-6LL5T6B [Brett Interiors] (0d)
|
|
||||||
- KAT1 [Business Services of Tucson LLC] (0d)
|
- KAT1 [Business Services of Tucson LLC] (0d)
|
||||||
- HSM-CATHY [Horseshoe Management] (1d)
|
- HSM-CATHY [Horseshoe Management] (2d)
|
||||||
- DESKTOP-3ST7GFD [Inside Track Productions] (0d)
|
|
||||||
- IMC-LUIS [Instrumental Music Center] (0d)
|
- IMC-LUIS [Instrumental Music Center] (0d)
|
||||||
- IMC-M-EDSERVICE [Instrumental Music Center] (2d)
|
- IMC-M-EDSERVICE [Instrumental Music Center] (2d)
|
||||||
- LAPTOP-PNVA9G51 [Instrumental Music Center] (4d)
|
- LAPTOP-PNVA9G51 [Instrumental Music Center] (4d)
|
||||||
- REPAIRADMIN [Instrumental Music Center] (1d)
|
- REPAIRADMIN [Instrumental Music Center] (1d)
|
||||||
- DESKTOP-OC2PH4I [Marty Ryan] (0d)
|
- DESKTOP-OC2PH4I [Marty Ryan] (0d)
|
||||||
- CHRISTIPC2024 [Mineralogical Record] (0d)
|
- CHRISTIPC2024 [Mineralogical Record] (0d)
|
||||||
- DESKTOP-CLJKB39 [Multicultural Counseling Center] (6d)
|
|
||||||
- PLS-SERVER [PUTT LAND SURVEYING, INC.] (8d)
|
- PLS-SERVER [PUTT LAND SURVEYING, INC.] (8d)
|
||||||
- DESKTOP-EKC9PRV [Pro-Tech Services] (0d)
|
- DESKTOP-EKC9PRV [Pro-Tech Services] (0d)
|
||||||
- LAPTOP-73UDDTTK [Pro-Tech Services] (1d)
|
- LAPTOP-73UDDTTK [Pro-Tech Services] (1d)
|
||||||
- RWD-CHRIS [Reliant Well Drilling and Pump Corporate] (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-8KQIDKH [Safesite] (0d)
|
||||||
- DESKTOP-ARNPE1U [Safesite] (1d)
|
- DESKTOP-ARNPE1U [Safesite] (2d)
|
||||||
- DESKTOP-B3ELJF5 [Safesite] (1d)
|
- DESKTOP-B3ELJF5 [Safesite] (2d)
|
||||||
- DESKTOP-BA45FRS [Safesite] (0d)
|
|
||||||
- DESKTOP-EJM109L [Safesite] (0d)
|
|
||||||
- DESKTOP-FUB3PAV [Safesite] (3d)
|
- DESKTOP-FUB3PAV [Safesite] (3d)
|
||||||
- DESKTOP-V3H99FC [Safesite] (1d)
|
- DESKTOP-V3H99FC [Safesite] (2d)
|
||||||
- DESKTOP-V9F9L23 [Safesite] (9d)
|
- DESKTOP-V9F9L23 [Safesite] (9d)
|
||||||
- LAPTOP-NFB98THE [Safesite] (2d)
|
- LAPTOP-NFB98THE [Safesite] (2d)
|
||||||
- JEREE [Stamback Septic] (1d)
|
- JEREE [Stamback Septic] (2d)
|
||||||
- DESKTOP-6HT5SJ9 [The Marc Group] (0d)
|
|
||||||
- ZEUS-ACCOUNTING [Zeus Nestora] (0d)
|
- ZEUS-ACCOUNTING [Zeus Nestora] (0d)
|
||||||
- ZEUS-SHERRI [Zeus Nestora] (0d)
|
- ZEUS-SHERRI [Zeus Nestora] (0d)
|
||||||
- ZEUS1 [Zeus Nestora] (0d)
|
- ZEUS1 [Zeus Nestora] (0d)
|
||||||
|
|
||||||
## stale 15-45d (4)
|
## stale 15-45d (4)
|
||||||
- GND-L-3 [Grabb & Durando Law Office] (20d)
|
- 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)
|
- RWD-ALLENDESKTO [Reliant Well Drilling and Pump Corporate] (18d)
|
||||||
- DESKTOP-FMDIK0Q [Safesite] (42d)
|
- DESKTOP-FMDIK0Q [Safesite] (43d)
|
||||||
|
|
||||||
## dead/no-session (58)
|
## dead/no-session (58)
|
||||||
- DESKTOP-SUFJR0J [Bill Tedards] (no SC)
|
- 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)
|
- Sheilaâs MacBook Pro [Heieck, Sheila] (no SC)
|
||||||
- HSM-RANDI [Horseshoe Management] (no SC)
|
- HSM-RANDI [Horseshoe Management] (no SC)
|
||||||
- HSM-SURFACE [Horseshoe Management] (no SC)
|
- HSM-SURFACE [Horseshoe Management] (no SC)
|
||||||
- DESKTOP-JQ0D38J [Instrumental Music Center] (105d)
|
- DESKTOP-JQ0D38J [Instrumental Music Center] (106d)
|
||||||
- DESKTOP-URV3UGR [Instrumental Music Center] (79d)
|
- DESKTOP-URV3UGR [Instrumental Music Center] (80d)
|
||||||
- IMC-EVENTS [Instrumental Music Center] (110d)
|
- IMC-EVENTS [Instrumental Music Center] (110d)
|
||||||
- IMC-L1-GRAPHICS [Instrumental Music Center] (no SC)
|
- IMC-L1-GRAPHICS [Instrumental Music Center] (no SC)
|
||||||
- PHIL [Instrumental Music Center] (no SC)
|
- PHIL [Instrumental Music Center] (no SC)
|
||||||
- PHIL2021LAPTOP [Instrumental Music Center] (141d)
|
- PHIL2021LAPTOP [Instrumental Music Center] (141d)
|
||||||
- PURCHASINGCOMP [Instrumental Music Center] (79d)
|
- PURCHASINGCOMP [Instrumental Music Center] (80d)
|
||||||
- LHLH [Little Hearts Little Hands] (no SC)
|
- LHLH [Little Hearts Little Hands] (no SC)
|
||||||
- WIN-KNVO6MUMMEM [Little Hearts Little Hands] (no SC)
|
- WIN-KNVO6MUMMEM [Little Hearts Little Hands] (no SC)
|
||||||
- CPC-chris-UZR6E [MVAN Enterprises Inc] (no SC)
|
- CPC-chris-UZR6E [MVAN Enterprises Inc] (no SC)
|
||||||
- DESKTOP-I7504C5 [MVAN Enterprises Inc] (no SC)
|
- DESKTOP-I7504C5 [MVAN Enterprises Inc] (no SC)
|
||||||
- Juneâs MacBook Pro [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-3VPT017 [Mineralogical Record] (no SC)
|
||||||
- DESKTOP-9QHSCIT [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-FOUR [PUTT LAND SURVEYING, INC.] (no SC)
|
||||||
- PLS-FRONT [PUTT LAND SURVEYING, INC.] (no SC)
|
- PLS-FRONT [PUTT LAND SURVEYING, INC.] (no SC)
|
||||||
- PLS-LAPTOP [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-L01 [Reliant Well Drilling and Pump Corporate] (no SC)
|
||||||
- RELIANT-L02 [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)
|
- 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)
|
- WILCOXADMIN [Reliant Well Drilling and Pump Corporate] (no SC)
|
||||||
- 1225-LENOVO-E16 [Safesite] (49d)
|
- 1225-LENOVO-E16 [Safesite] (49d)
|
||||||
- DESKTOP-QAR6D04 [Safesite] (142d)
|
- DESKTOP-QAR6D04 [Safesite] (142d)
|
||||||
|
|||||||
@@ -7,15 +7,23 @@
|
|||||||
# client automatically. Idempotent — run it on a schedule or on demand.
|
# client automatically. Idempotent — run it on a schedule or on demand.
|
||||||
#
|
#
|
||||||
# Env: RMM, TOK (GuruRMM), SK (Syncro api key). --dry = report only.
|
# 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"]
|
RMM=os.environ["RMM"]; TOK=os.environ["TOK"]; SK=os.environ["SK"]
|
||||||
ctx=ssl.create_default_context(); DRY="--dry" in sys.argv
|
ctx=ssl.create_default_context(); DRY="--dry" in sys.argv
|
||||||
STAGING_CLIENT="Staging - Auto Enroll"
|
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):
|
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"))
|
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):
|
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"})
|
# move endpoint is rate-limited: throttle + retry on 500
|
||||||
urllib.request.urlopen(req,context=ctx,timeout=20)
|
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):
|
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=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))
|
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)
|
s=re.sub(r'\b(llc|inc|incorporated|corp|corporation|company|co|ltd|the)\b',' ',s)
|
||||||
return re.sub(r'\s+',' ',s).strip()
|
return re.sub(r'\s+',' ',s).strip()
|
||||||
agents=rget("/api/agents")
|
agents=rget("/api/agents")
|
||||||
staging=[a for a in agents if a.get("client_name")==STAGING_CLIENT]
|
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 in Staging")
|
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
|
# GuruRMM client -> a target site id (prefer 'Main'/'Main Office', else first); keyed by normalized name
|
||||||
clients=rget("/api/clients")
|
clients=rget("/api/clients")
|
||||||
name2site={}
|
name2site={}
|
||||||
@@ -47,7 +55,9 @@ for a in staging:
|
|||||||
cust=syncro_customer(a["hostname"])
|
cust=syncro_customer(a["hostname"])
|
||||||
site=name2site.get(norm(cust))
|
site=name2site.get(norm(cust))
|
||||||
if cust and site:
|
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}'")
|
moved+=1; print(f" {a['hostname']} -> '{cust}'")
|
||||||
else:
|
else:
|
||||||
unmatched.append(f"{a['hostname']} (syncro='{cust}')")
|
unmatched.append(f"{a['hostname']} (syncro='{cust}')")
|
||||||
|
|||||||
Reference in New Issue
Block a user