# cnmaestro CLI Cleanup offline devices and bulk-upgrade firmware on a cnMaestro Cloud instance (cloud.cambiumnetworks.com). ## Setup ### 1. Find your tenant's API base URL Each cnMaestro Cloud tenant lives on a regional subdomain. Log in to your tenant in a browser and copy the scheme + host portion of the URL — everything before the first `/#/`. Example: ``` https://us-e1-s1-cmjbcvncy6.cloud.cambiumnetworks.com/#/VERONA_NETWORKS/home-view/home ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is your CNMAESTRO_BASE_URL ``` ### 2. Create an API client 1. While logged in, go to the menu (top-right gear/avatar) → **Application** (or **Services**) → **API Clients**. 2. Click **Add New** (or **Add API Client**). 3. Give it a name (e.g. `cnmaestro-cli`). Grant a role that has at minimum: - Read access to devices and firmware. - Delete access to devices. - Permission to create firmware-update jobs. The built-in **Administrator** role covers all three. 4. Save and copy the **Client ID** and **Client Secret**. The secret is shown only once. ### 3. Install ```bash cd /Users/graham/dev/network/cnmaestro uv sync cp .env.example .env # edit .env with your client id + secret ``` ### 4. Smoke-test ```bash uv run cnmaestro cleanup --dry-run ``` This authenticates, lists devices, and prints what *would* be removed without actually removing anything. ## Usage ### Remove devices offline > 24h ```bash uv run cnmaestro cleanup # interactive, asks before deleting uv run cnmaestro cleanup --threshold-hours 48 # custom threshold uv run cnmaestro cleanup --yes # non-interactive (cron) uv run cnmaestro cleanup --dry-run # just print, never delete ``` ### Bulk-upgrade online devices to latest firmware per model ```bash uv run cnmaestro upgrade # interactive uv run cnmaestro upgrade --product ePMP,PMP # only these products uv run cnmaestro upgrade --yes # non-interactive uv run cnmaestro upgrade --dry-run # show planned jobs only ``` The upgrade command groups devices by `(product, target_version)` and submits one bulk firmware job per group (cnMaestro caps each job at 100 devices, so larger groups are chunked). ## Safety - Both commands default to interactive confirmation. - `cleanup` refuses to run if more than 50 % of the fleet would be removed; pass `--force` to override. - Every destructive call (delete, job-submit) is appended to `./cnmaestro.log` for audit. - The OAuth2 token is held in memory only. ## Tests ```bash uv run pytest ``` All HTTP is mocked with `respx`; tests never touch the live API.