diff --git a/session-logs/2026-06-01-session.md b/session-logs/2026-06-01-session.md index 4aaf674..4a56963 100644 --- a/session-logs/2026-06-01-session.md +++ b/session-logs/2026-06-01-session.md @@ -88,3 +88,89 @@ Closed (coord todos, status=done): `7eb7e60a`, `5ada8ff4`, `04497b97` (all dupes - Coord messages: GURU-KALI handoff `23b095d0`, KALI reply `d91406ce`, purge confirm `f2ee93b6`. - Plan doc: `wiki/systems/jupiter-docker-templating.md`. Bug tracker: `projects/msp-tools/guru-rmm/docs/FEATURE_ROADMAP.md` (BUG-NNN sections). - POP3 settings for Jon: server `mail.ezfastautoglass.com`, port 995, SSL, user `jon@ezfastautoglass.com`. + +--- + +## Update: 09:44 PT — MSP360 License Report & Feature Request + +## User +- **User:** Mike Swanson (mike) +- **Machine:** GURU-BEAST-ROG +- **Role:** admin + +## Session Summary + +Mike requested a license report for MSPBackups (MSP360 Managed Backup Service). The MSP360 API at `api.mspbackups.com` was queried using credentials from the vault. DNS resolution for the API hostname fails on BEAST's local DNS server (`fddf:7d20:a256:8::1`); this was worked around by resolving the hostname via Google DNS (8.8.8.8) using curl's `--resolve` flag with the returned IP `52.6.7.137`. An auth token was obtained via `POST /api/Provider/Login`, then three endpoints were queried in sequence: `/api/Licenses`, `/api/Companies`, and `/api/Users`. The Users endpoint provided the company association for each user ID, enabling a full cross-reference of which licenses (by type and computer name) are attached to which client company. + +The report covered 35 companies with active licenses. Most held standard Server licenses (one per monitored machine). Notable exceptions included Dataforth (7 licenses: 5x Server, 1x MS SQL Server, 1x VM Server), Glaztech Industries (3 licenses: 1x MS SQL Server, 1x VM Server, 1x expired trial Server), and Jimmy Company (1x active Server + 9x pool/undeployed Server licenses). Three trial licenses were flagged as expired (Brett Interiors, Glaztech SBS, Len's Auto LAB-SVR). All MS Exchange and unallocated licenses were confirmed unused. + +Mike then asked whether licensing could be modified via the API. All write-capable endpoints were probed: `POST /api/Licenses/Revoke` and `POST /api/Licenses/Release` were confirmed functional (both require `LicenseID` and `UserID`). Sub-routes including Assign, Transfer, Move, Pool, Count, and Update all responded to GET but returned null or 405 for POST — no assignment capability exists via API. Companies and Users endpoints support POST/PUT for create/update operations. + +Mike requested a GuruRMM feature request to automate MSP360 license release on agent decommission. The feature-request skill was invoked, which performed full codebase research, classified the feature via Ollama (qwen3.6), generated a comprehensive specification via Ollama (qwen3:14b), and created SPEC-023. The spec was committed and pushed to the GuruRMM repo, and the submodule pointer was updated in the ClaudeTools parent repo. Mike declined Syncro logging. + +## Key Decisions + +- Used `--resolve api.mspbackups.com:443:52.6.7.137` with curl as the DNS workaround rather than hardcoding the IP, so the TLS certificate still validates against the hostname. +- Cross-referenced all three MSP360 endpoints (Licenses + Companies + Users) to produce the company-level report — the Licenses endpoint alone only has UserID, not company name. +- SPEC-023 design: Release fires best-effort on agent delete (never blocks deletion); failures are audit-logged to a new DB table rather than surfaced as blocking errors. +- Confidence guard added: only agents with `manually_verified = true` or `mapping_confidence = 'high'` trigger auto-release, preventing false releases on ambiguous hostname matches. +- A dedicated `reqwest::Client` with `hickory-resolver` pointing to 8.8.8.8/8.8.4.4 was specified rather than patching the global HTTP client, since the DNS issue is specific to the MSP360 integration. + +## Problems Encountered + +- `api.mspbackups.com` would not resolve via BEAST's local DNS (`fddf:7d20:a256:8::1`). Python `socket.gethostbyname()` also failed. Resolved by using curl's `--resolve` flag after obtaining the IP via `nslookup api.mspbackups.com 8.8.8.8`. IP resolved to `52.6.7.137`. +- Initial login attempt with `curl -X POST` returned an empty body. Adding `--resolve` with the IP from `nslookup 8.8.8.8` produced a valid token response. Root cause: DNS failure silently returned no connection rather than an error. + +## Configuration Changes + +- Created: `projects/msp-tools/guru-rmm/docs/specs/SPEC-023-msp360-license-release-on-decommission.md` +- Modified: `projects/msp-tools/guru-rmm/docs/FEATURE_ROADMAP.md` (added SPEC-023 under Integrations > MSP360) + +## Credentials & Secrets + +- Vault path accessed: `msp-tools/msp360-api.sops.yaml` + - `credentials.login`: API username (API-specific, not portal login) + - `credentials.password`: API password + - Auth flow: POST `/api/Provider/Login` → Bearer token (14-day expiry) + +## Infrastructure & Servers + +- MSP360 API: `https://api.mspbackups.com` → resolved IP `52.6.7.137` (via 8.8.8.8) +- Auth token obtained: `uiEqi8Ln...` (issued 2026-06-01 16:24 UTC, expires 2026-06-15) +- BEAST local DNS: `fddf:7d20:a256:8::1` — does NOT resolve `api.mspbackups.com` + +## Commands & Outputs + +```bash +# DNS workaround — resolve via Google DNS, then use --resolve flag +IP=$(nslookup api.mspbackups.com 8.8.8.8 | grep -E '^Address:' | tail -1 | awk '{print $2}') +# IP = 52.6.7.137 + +# Login +curl -s --resolve "api.mspbackups.com:443:52.6.7.137" \ + -X POST "https://api.mspbackups.com/api/Provider/Login" \ + -H "Content-Type: application/json" \ + -d '{"UserName": "kY9PvDdWki", "Password": "..."}' +# Returns: {"access_token":"...","expires_in":1209599,...} + +# License write endpoints confirmed: +# POST /api/Licenses/Revoke — requires LicenseID, UserID +# POST /api/Licenses/Release — requires LicenseID, UserID +# All others (Assign, Transfer, Move, Pool, etc.) — GET only, return null +``` + +## Pending / Incomplete Tasks + +- SPEC-023 is in Proposed status — needs review and sprint planning assignment +- The DNS fix for BEAST (dedicated resolver in MSP360 HTTP client) is a prerequisite for SPEC-023 implementation and also fixes the existing silent failure in the backup sync job +- 3 expired trial licenses may warrant cleanup in MSP360 portal: Brett Interiors (Server, exp 2026-05-01), Glaztech SBS (Server, exp 2026-05-23), Len's Auto LAB-SVR (Server, exp 2026-05-01) +- Jimmy Company has 9 undeployed pool Server licenses — worth confirming whether intentional + +## Reference Information + +- SPEC-023: `projects/msp-tools/guru-rmm/docs/specs/SPEC-023-msp360-license-release-on-decommission.md` +- FEATURE_ROADMAP.md: `projects/msp-tools/guru-rmm/docs/FEATURE_ROADMAP.md` +- MSP360 API base: `https://api.mspbackups.com` +- MSP360 vault: `msp-tools/msp360-api.sops.yaml` +- MSP360 release endpoint: `POST /api/Licenses/Release` (params: `LicenseID`, `UserID`) +- MSP360 revoke endpoint: `POST /api/Licenses/Revoke` (params: `LicenseID`, `UserID`)