From 0f425cec66ec4d9302ef5c0ad18db7725d05868a Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:27:12 +0100 Subject: [PATCH 01/10] New Datto plugin - Alerts+Devices --- .../v1/dataStreams/dattoAllDevices.json | 59 +++++++++++++ .../v1/dataStreams/dattoScopeOpenAlerts.json | 30 +++++++ .../DattoRMM/v1/dataStreams/importSites.json | 82 ++++++++++++++++++ plugins/DattoRMM/v1/icon.png | Bin 0 -> 2437 bytes plugins/DattoRMM/v1/metadata.json | 50 +++++++++++ plugins/DattoRMM/v1/ui.json | 34 ++++++++ 6 files changed, 255 insertions(+) create mode 100644 plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json create mode 100644 plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json create mode 100644 plugins/DattoRMM/v1/dataStreams/importSites.json create mode 100644 plugins/DattoRMM/v1/icon.png create mode 100644 plugins/DattoRMM/v1/metadata.json create mode 100644 plugins/DattoRMM/v1/ui.json diff --git a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json new file mode 100644 index 0000000..219920e --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -0,0 +1,59 @@ +{ + "name": "dattoAllDevices", + "displayName": "Datto all devices", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "paging": { + "mode": "nextUrl", + "pageSize": { + "realm": { + "value": "none", + "label": "none" + } + }, + "in": { + "realm": { + "value": "payload", + "label": "payload" + }, + "path": "pageDetails.nextPageUrl" + } + }, + "expandInnerObjects": true, + "endpointPath": "account/devices", + "pathToData": "devices", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "thisQuarter", + "thisYear", + "lastMonth", + "lastQuarter", + "lastYear", + "none" + ], + "defaultShaping": { + "group": { + "by": [ + [ + "siteName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + } + } +} \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json new file mode 100644 index 0000000..222e702 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json @@ -0,0 +1,30 @@ +{ + "name": "dattoScopeOpenAlerts", + "displayName": "Datto scope open alerts", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "endpointPath": "/site/e3e9537b-168c-4ebc-b1ea-f02c7848da21/alerts/open\n", + "pathToData": "alerts", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "thisQuarter", + "thisYear", + "lastMonth", + "lastQuarter", + "lastYear" + ] +} \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json new file mode 100644 index 0000000..79ccca4 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -0,0 +1,82 @@ +{ + "name": "importSites", + "displayName": "Import Sites", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "paging": { + "mode": "nextUrl", + "pageSize": { + "realm": { + "value": "none", + "label": "none" + } + }, + "in": { + "realm": { + "value": "payload", + "label": "payload" + }, + "path": "nextPageUrl" + } + }, + "expandInnerObjects": true, + "endpointPath": "account/sites", + "pathToData": "sites", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": [ + "number", + { + "decimalPlaces": 0 + } + ], + "name": "devicesStatus.numberOfDevices" + }, + { + "shape": [ + "number", + { + "decimalPlaces": 0 + } + ], + "name": "devicesStatus.numberOfOfflineDevices" + }, + { + "shape": [ + "number", + { + "decimalPlaces": 0 + } + ], + "name": "devicesStatus.numberOfOnlineDevices" + }, + { + "shape": "string", + "name": "id" + }, + { + "pattern": ".*" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "thisQuarter", + "thisYear", + "lastMonth", + "lastQuarter", + "lastYear", + "none" + ], + "visibility": { + "type": "hidden" + } +} \ No newline at end of file diff --git a/plugins/DattoRMM/v1/icon.png b/plugins/DattoRMM/v1/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..da4522235a9831e5fa52e5025c8dc6d303da5165 GIT binary patch literal 2437 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 API.", + "validation": { + "required": true, + "pattern": { + "value": "^https?://[^\\s]+$", + "message": "Please enter a valid URL starting with https://" + } + } + }, + { + "type": "text", + "name": "apiKey", + "label": "Client ID", + "placeholder": "Enter your Datto RMM API Client ID", + "validation": { + "required": true + } + }, + { + "type": "password", + "name": "apiSecret", + "label": "Client Secret", + "placeholder": "Enter your Datto RMM API Client Secret", + "validation": { + "required": true + } + } +] From 69e0aebd566df5015f8ba91168733ae1f687eda0 Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Thu, 2 Apr 2026 20:44:02 +0100 Subject: [PATCH 02/10] Update metadata --- plugins/DattoRMM/v1/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/DattoRMM/v1/metadata.json b/plugins/DattoRMM/v1/metadata.json index ecc18b2..9158ebe 100644 --- a/plugins/DattoRMM/v1/metadata.json +++ b/plugins/DattoRMM/v1/metadata.json @@ -7,8 +7,8 @@ "type": "community" }, "description": "Datto RMM - Index and search your devices, sites and alerts", - "category": "User Defined", - "type": "hybrid", + "category": "SquaredUp Internal", + "type": "cloud", "schemaVersion": "2.0", "base": { "plugin": "WebAPI", From bbb2265d930129e741e2985574953a1e1bbdea2b Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:29:14 +0100 Subject: [PATCH 03/10] Import sites + devices --- plugins/DattoRMM/v1/custom_types.json | 16 ++++++ .../v1/dataStreams/dattoAllDevices.json | 55 +++++++++++++++++++ .../DattoRMM/v1/dataStreams/importSites.json | 27 +++++++-- .../DattoRMM/v1/indexDefinitions/default.json | 43 +++++++++++++++ 4 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 plugins/DattoRMM/v1/custom_types.json create mode 100644 plugins/DattoRMM/v1/indexDefinitions/default.json diff --git a/plugins/DattoRMM/v1/custom_types.json b/plugins/DattoRMM/v1/custom_types.json new file mode 100644 index 0000000..3629a3c --- /dev/null +++ b/plugins/DattoRMM/v1/custom_types.json @@ -0,0 +1,16 @@ +[ + { + "icon": "building", + "name": "Datto Site", + "plural": "Sites", + "singular": "Site", + "sourceType": "Datto Site" + }, + { + "icon": "desktop", + "name": "Datto Device", + "plural": "Devices", + "singular": "Device", + "sourceType": "Datto Device" + } +] diff --git a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json index 219920e..d6965d4 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -26,6 +26,61 @@ "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "displayName": "Hostname", + "shape": "string", + "name": "hostname" + }, + { + "displayName": "Site", + "shape": "string", + "name": "siteName" + }, + { + "displayName": "Device Class", + "shape": "string", + "name": "deviceClass" + }, + { + "displayName": "Operating System", + "shape": "string", + "name": "operatingSystem" + }, + { + "displayName": "Online Status", + "shape": "string", + "name": "onlineStatus" + }, + { + "displayName": "Last Seen", + "shape": "date", + "name": "lastSeen" + }, + { + "displayName": "Internal IP", + "shape": "string", + "name": "intIpAddress" + }, + { + "displayName": "External IP", + "shape": "string", + "name": "extIpAddress" + }, + { + "shape": "string", + "name": "siteUid", + "visible": false + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, "timeframes": [ "last1hour", diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json index 79ccca4..41f2440 100644 --- a/plugins/DattoRMM/v1/dataStreams/importSites.json +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -28,6 +28,27 @@ }, "metadata": [ { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "displayName": "Name", + "shape": "string", + "name": "name" + }, + { + "displayName": "Description", + "shape": "string", + "name": "description" + }, + { + "displayName": "Notes", + "shape": "string", + "name": "notes" + }, + { + "displayName": "Total Devices", "shape": [ "number", { @@ -37,6 +58,7 @@ "name": "devicesStatus.numberOfDevices" }, { + "displayName": "Offline Devices", "shape": [ "number", { @@ -46,6 +68,7 @@ "name": "devicesStatus.numberOfOfflineDevices" }, { + "displayName": "Online Devices", "shape": [ "number", { @@ -54,10 +77,6 @@ ], "name": "devicesStatus.numberOfOnlineDevices" }, - { - "shape": "string", - "name": "id" - }, { "pattern": ".*" } diff --git a/plugins/DattoRMM/v1/indexDefinitions/default.json b/plugins/DattoRMM/v1/indexDefinitions/default.json new file mode 100644 index 0000000..ffc3b43 --- /dev/null +++ b/plugins/DattoRMM/v1/indexDefinitions/default.json @@ -0,0 +1,43 @@ +{ + "steps": [ + { + "name": "sites", + "dataStream": { "name": "importSites" }, + "timeframe": "none", + "objectMapping": { + "id": "uid", + "name": "name", + "type": { "value": "Datto Site" }, + "properties": [ + "description", + "notes", + { "siteUid": "uid" }, + { "numberOfDevices": "devicesStatus.numberOfDevices" }, + { "numberOfOfflineDevices": "devicesStatus.numberOfOfflineDevices" }, + { "numberOfOnlineDevices": "devicesStatus.numberOfOnlineDevices" } + ] + } + }, + { + "name": "devices", + "dataStream": { "name": "dattoAllDevices" }, + "timeframe": "none", + "objectMapping": { + "id": "uid", + "name": "hostname", + "type": { "value": "Datto Device" }, + "properties": [ + "deviceClass", + "siteName", + { "deviceUid": "uid" }, + { "siteUid": "siteUid" }, + { "operatingSystem": "operatingSystem" }, + { "onlineStatus": "onlineStatus" }, + { "lastSeen": "lastSeen" }, + { "intIpAddress": "intIpAddress" }, + { "extIpAddress": "extIpAddress" } + ] + } + } + ] +} From 0c79064b6a291a99b0138afa9bb8c62e1be5a3e4 Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Thu, 9 Apr 2026 21:31:30 +0100 Subject: [PATCH 04/10] Add readme and cspell --- .github/CODEOWNERS | 1 + cspell.json | 1 + plugins/DattoRMM/v1/cspell.json | 7 +++++ .../v1/dataStreams/dattoAllDevices.json | 2 ++ .../v1/dataStreams/dattoScopeOpenAlerts.json | 4 ++- .../DattoRMM/v1/dataStreams/importSites.json | 2 ++ plugins/DattoRMM/v1/docs/README.md | 26 +++++++++++++++++++ plugins/DattoRMM/v1/metadata.json | 19 +++++++++++--- 8 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 plugins/DattoRMM/v1/cspell.json create mode 100644 plugins/DattoRMM/v1/docs/README.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 498bd01..9948a76 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,7 @@ /.github/* @squaredup/community-moderators # Request review from original author +plugins/DattoRMM/* @TimWheeler-SQUP plugins/DigiCert/* @shaswot77 plugins/FantasyPremierLeague/* @TimWheeler-SQUP plugins/GoogleSheets/* @kieranlangton diff --git a/cspell.json b/cspell.json index d1b7aa6..d563d67 100644 --- a/cspell.json +++ b/cspell.json @@ -1,5 +1,6 @@ { "words": [ + "Datto", "Phare", "rdap", "whois", diff --git a/plugins/DattoRMM/v1/cspell.json b/plugins/DattoRMM/v1/cspell.json new file mode 100644 index 0000000..de5e43a --- /dev/null +++ b/plugins/DattoRMM/v1/cspell.json @@ -0,0 +1,7 @@ +{ + "words": [ + "Datto", + "RMM", + "centrastage" + ] +} diff --git a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json index d6965d4..cb47b31 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -1,6 +1,8 @@ { "name": "dattoAllDevices", "displayName": "Datto all devices", + "description": "All devices across all sites", + "tags": ["Devices"], "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "get", diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json index 222e702..2edb311 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json @@ -1,6 +1,8 @@ { "name": "dattoScopeOpenAlerts", "displayName": "Datto scope open alerts", + "description": "Open alerts for a specific site", + "tags": ["Alerts"], "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "get", @@ -8,7 +10,7 @@ "mode": "none" }, "expandInnerObjects": true, - "endpointPath": "/site/e3e9537b-168c-4ebc-b1ea-f02c7848da21/alerts/open\n", + "endpointPath": "site/{{sourceId}}/alerts/open", "pathToData": "alerts", "getArgs": [], "headers": [] diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json index 41f2440..67e88f0 100644 --- a/plugins/DattoRMM/v1/dataStreams/importSites.json +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -1,6 +1,8 @@ { "name": "importSites", "displayName": "Import Sites", + "description": "All sites in the account", + "tags": ["Sites"], "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "get", diff --git a/plugins/DattoRMM/v1/docs/README.md b/plugins/DattoRMM/v1/docs/README.md new file mode 100644 index 0000000..a5225b1 --- /dev/null +++ b/plugins/DattoRMM/v1/docs/README.md @@ -0,0 +1,26 @@ +# Before you start + +[Datto RMM](https://www.datto.com/rmm) is a cloud-based Remote Monitoring and Management (RMM) platform used by Managed Service Providers (MSPs) to monitor, manage and support client devices. This plugin lets you import your Datto RMM sites and devices into SquaredUp, and monitor open alerts scoped to individual sites. + +## What is imported + +The following objects are imported and kept in sync: + +- **Sites** — each managed client site, including device counts (total, online, offline) +- **Devices** — all endpoints across all sites, including hostname, operating system, online status, last seen time, and internal/external IP addresses + +## Data streams + +| Data stream | Description | +|-------------|-------------| +| **All Devices** | Returns all devices across every site. Use this to build fleet-wide views or group by site. | +| **Open Alerts** | Returns open alerts scoped to an imported site object. Use this on site dashboards to surface active issues. | + +## Setup + +You will need the **Base URL**, **API Key** and **API Secret** for your Datto RMM account. + +1. Log in to Datto RMM and navigate to **Setup** > **API** +2. Copy the **API URL** — this is your Base URL (e.g. `https://merlot-api.centrastage.net`) +3. Under **API Users**, create a new API user or select an existing one +4. Copy the **API Key** and **API Secret** for that user diff --git a/plugins/DattoRMM/v1/metadata.json b/plugins/DattoRMM/v1/metadata.json index 9158ebe..0ca1b2a 100644 --- a/plugins/DattoRMM/v1/metadata.json +++ b/plugins/DattoRMM/v1/metadata.json @@ -6,8 +6,9 @@ "name": "@TimWheeler-SQUP", "type": "community" }, - "description": "Datto RMM - Index and search your devices, sites and alerts", - "category": "SquaredUp Internal", + "description": "Monitor and search your Datto RMM devices, sites and alerts.", + "category": "Monitoring", + "importNotSupported": false, "type": "cloud", "schemaVersion": "2.0", "base": { @@ -46,5 +47,17 @@ "oauth2AuthExtraArgs": [], "oauth2Scope": "" } - } + }, + "links": [ + { + "category": "documentation", + "url": "https://github.com/squaredup/plugins/blob/main/plugins/DattoRMM/v1/docs/README.md", + "label": "Help adding this plugin" + }, + { + "category": "source", + "url": "https://github.com/squaredup/plugins/tree/main/plugins/DattoRMM/v1", + "label": "Repository" + } + ] } \ No newline at end of file From aad3849545cc8ffb9ab41af8cbc225e0e70cf74d Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:34:27 +0100 Subject: [PATCH 05/10] move keys to header from post body --- plugins/DattoRMM/v1/metadata.json | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/plugins/DattoRMM/v1/metadata.json b/plugins/DattoRMM/v1/metadata.json index 0ca1b2a..69d494a 100644 --- a/plugins/DattoRMM/v1/metadata.json +++ b/plugins/DattoRMM/v1/metadata.json @@ -6,7 +6,7 @@ "name": "@TimWheeler-SQUP", "type": "community" }, - "description": "Monitor and search your Datto RMM devices, sites and alerts.", + "description": "Find and monitor your Datto RMM devices, sites and alerts.", "category": "Monitoring", "importNotSupported": false, "type": "cloud", @@ -22,7 +22,13 @@ } ], "queryArgs": [], - "oauth2TokenExtraArgs": [ + "oauth2TokenExtraArgs": [], + "oauth2ClientSecret": "public", + "oauth2ClientSecretLocationDuringAuth": "header", + "authMode": "oauth2", + "oauth2GrantType": "clientCredentials", + "baseUrl": "{{baseUrl}}/api/v2/", + "oauth2TokenExtraHeaders": [ { "value": "password", "key": "grant_type" @@ -36,15 +42,8 @@ "key": "password" } ], - "oauth2ClientSecret": "public", - "oauth2ClientSecretLocationDuringAuth": "header", - "authMode": "oauth2", - "oauth2GrantType": "clientCredentials", - "baseUrl": "{{baseUrl}}/api/v2/", - "oauth2TokenExtraHeaders": [], "oauth2ClientId": "public-client", "oauth2TokenUrl": "{{baseUrl}}/auth/oauth/token", - "oauth2AuthExtraArgs": [], "oauth2Scope": "" } }, From a2d6706e29340aa24b001140b788696818248baa Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:44:13 +0100 Subject: [PATCH 06/10] Reverse commit --- plugins/DattoRMM/v1/metadata.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/DattoRMM/v1/metadata.json b/plugins/DattoRMM/v1/metadata.json index 69d494a..8b0b0ee 100644 --- a/plugins/DattoRMM/v1/metadata.json +++ b/plugins/DattoRMM/v1/metadata.json @@ -22,13 +22,7 @@ } ], "queryArgs": [], - "oauth2TokenExtraArgs": [], - "oauth2ClientSecret": "public", - "oauth2ClientSecretLocationDuringAuth": "header", - "authMode": "oauth2", - "oauth2GrantType": "clientCredentials", - "baseUrl": "{{baseUrl}}/api/v2/", - "oauth2TokenExtraHeaders": [ + "oauth2TokenExtraArgs": [ { "value": "password", "key": "grant_type" @@ -42,6 +36,12 @@ "key": "password" } ], + "oauth2ClientSecret": "public", + "oauth2ClientSecretLocationDuringAuth": "header", + "authMode": "oauth2", + "oauth2GrantType": "clientCredentials", + "baseUrl": "{{baseUrl}}/api/v2/", + "oauth2TokenExtraHeaders": [], "oauth2ClientId": "public-client", "oauth2TokenUrl": "{{baseUrl}}/auth/oauth/token", "oauth2Scope": "" From 192e24c388c5a409616ca12142a906e18567ec91 Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:08:38 +0100 Subject: [PATCH 07/10] fix paging --- plugins/DattoRMM/v1/dataStreams/importSites.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json index 67e88f0..a34f285 100644 --- a/plugins/DattoRMM/v1/dataStreams/importSites.json +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -19,7 +19,7 @@ "value": "payload", "label": "payload" }, - "path": "nextPageUrl" + "path": "pageDetails.nextPageUrl" } }, "expandInnerObjects": true, From 29fb265589f11d1434ee6fbdd886836f32267a23 Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Sun, 12 Apr 2026 18:37:40 +0100 Subject: [PATCH 08/10] Add closed alerts data stream --- .gitignore | 7 ++ .../v1/dataStreams/dattoAllDevices.json | 81 +++++++++++++------ .../dataStreams/dattoScopeClosedAlerts.json | 81 +++++++++++++++++++ .../v1/dataStreams/dattoScopeOpenAlerts.json | 77 ++++++++++++++---- .../DattoRMM/v1/dataStreams/importSites.json | 9 +-- plugins/DattoRMM/v1/metadata.json | 2 +- plugins/DattoRMM/v1/ui.json | 10 ++- 7 files changed, 214 insertions(+), 53 deletions(-) create mode 100644 plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json diff --git a/.gitignore b/.gitignore index 43ec304..dd3bb92 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,13 @@ logs/ *.local.json +############################################ +# Claude Code (local only, never commit) +############################################ + +*.local.md + + ############################################ # Optional: generated assets ############################################ diff --git a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json index cb47b31..63ed896 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -1,6 +1,6 @@ { "name": "dattoAllDevices", - "displayName": "Datto all devices", + "displayName": "Devices", "description": "All devices across all sites", "tags": ["Devices"], "baseDataSourceName": "httpRequestUnscoped", @@ -23,7 +23,7 @@ } }, "expandInnerObjects": true, - "endpointPath": "account/devices", + "endpointPath": "api/v2/account/devices", "pathToData": "devices", "getArgs": [], "headers": [] @@ -34,6 +34,21 @@ "name": "uid", "visible": false }, + { + "shape": "string", + "name": "id", + "visible": false + }, + { + "shape": "string", + "name": "siteUid", + "visible": false + }, + { + "shape": "string", + "name": "siteId", + "visible": false + }, { "displayName": "Hostname", "shape": "string", @@ -65,18 +80,47 @@ "name": "lastSeen" }, { - "displayName": "Internal IP", - "shape": "string", - "name": "intIpAddress" + "displayName": "Creation Date", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "creationDate" }, { - "displayName": "External IP", - "shape": "string", - "name": "extIpAddress" + "displayName": "Last Audit Date", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "lastAuditDate" }, { - "shape": "string", - "name": "siteUid", + "displayName": "Patches Approved Pending", + "shape": ["number", { "decimalPlaces": 0 }], + "name": "patchManagement.patchesApprovedPending" + }, + { + "displayName": "Patches Installed", + "shape": ["number", { "decimalPlaces": 0 }], + "name": "patchManagement.patchesInstalled" + }, + { + "displayName": "Patches Not Approved", + "shape": ["number", { "decimalPlaces": 0 }], + "name": "patchManagement.patchesNotApproved" + }, + { + "displayName": "Compliance State", + "name": "softwareComplianceState", + "computed": true, + "valueExpression": "{{ $['softwareStatus'] }}", + "shape": ["state", { + "map": { + "success": ["Compliant"], + "error": ["Not Compliant"], + "warning": [], + "unknown": [], + "unmonitored": [] + } + }] + }, + { + "pattern": "udf.*", "visible": false }, { @@ -97,20 +141,5 @@ "lastQuarter", "lastYear", "none" - ], - "defaultShaping": { - "group": { - "by": [ - [ - "siteName", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "count" - } - ] - } - } + ] } \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json new file mode 100644 index 0000000..90bdce6 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json @@ -0,0 +1,81 @@ +{ + "name": "dattoScopeClosedAlerts", + "displayName": "Closed Alerts", + "description": "Resolved alerts for a specific site", + "tags": ["Alerts"], + "baseDataSourceName": "httpRequestScopedSingle", + "matches": { + "sourceType": { + "type": "equals", + "value": "Datto Site" + } + }, + "config": { + "httpMethod": "get", + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "endpointPath": "api/v2/site/{{objects[0].siteUid}}/alerts/resolved", + "pathToData": "alerts", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "name": "sourceId", + "displayName": "Object ID", + "shape": "string", + "visible": false + }, + { + "displayName": "Alert Message", + "shape": "string", + "name": "alertSourceInfo.alertMessage" + }, + { + "displayName": "Alert Type", + "shape": "string", + "name": "alertSourceInfo.alertTypeDescription" + }, + { + "displayName": "Device", + "shape": "string", + "name": "alertSourceInfo.alertContext.hostname" + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.deviceUid", + "visible": false + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.siteUid", + "visible": false + }, + { + "displayName": "Priority", + "shape": "string", + "name": "priority" + }, + { + "displayName": "Raised", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "timestamp" + }, + { + "displayName": "Resolved", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "resolvedAt" + }, + { + "pattern": ".*" + } + ], + "timeframes": false +} diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json index 2edb311..48829f0 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json @@ -1,32 +1,77 @@ { "name": "dattoScopeOpenAlerts", - "displayName": "Datto scope open alerts", + "displayName": "Open Alerts", "description": "Open alerts for a specific site", "tags": ["Alerts"], - "baseDataSourceName": "httpRequestUnscoped", + "baseDataSourceName": "httpRequestScopedSingle", + "matches": { + "sourceType": { + "type": "equals", + "value": "Datto Site" + } + }, "config": { "httpMethod": "get", "paging": { "mode": "none" }, "expandInnerObjects": true, - "endpointPath": "site/{{sourceId}}/alerts/open", + "endpointPath": "api/v2/site/{{objects[0].siteUid}}/alerts/open", "pathToData": "alerts", "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "name": "sourceId", + "displayName": "Object ID", + "shape": "string", + "visible": false + }, + { + "displayName": "Alert Message", + "shape": "string", + "name": "alertSourceInfo.alertMessage" + }, + { + "displayName": "Alert Type", + "shape": "string", + "name": "alertSourceInfo.alertTypeDescription" + }, + { + "displayName": "Device", + "shape": "string", + "name": "alertSourceInfo.alertContext.hostname" + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.deviceUid", + "visible": false + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.siteUid", + "visible": false + }, + { + "displayName": "Priority", + "shape": "string", + "name": "priority" + }, + { + "displayName": "Timestamp", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "timestamp" + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, - "timeframes": [ - "last1hour", - "last12hours", - "last24hours", - "last7days", - "last30days", - "thisMonth", - "thisQuarter", - "thisYear", - "lastMonth", - "lastQuarter", - "lastYear" - ] + "timeframes": false } \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json index a34f285..15accd5 100644 --- a/plugins/DattoRMM/v1/dataStreams/importSites.json +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -1,6 +1,6 @@ { "name": "importSites", - "displayName": "Import Sites", + "displayName": "Sites", "description": "All sites in the account", "tags": ["Sites"], "baseDataSourceName": "httpRequestUnscoped", @@ -23,7 +23,7 @@ } }, "expandInnerObjects": true, - "endpointPath": "account/sites", + "endpointPath": "api/v2/account/sites", "pathToData": "sites", "getArgs": [], "headers": [] @@ -96,8 +96,5 @@ "lastQuarter", "lastYear", "none" - ], - "visibility": { - "type": "hidden" - } + ] } \ No newline at end of file diff --git a/plugins/DattoRMM/v1/metadata.json b/plugins/DattoRMM/v1/metadata.json index 8b0b0ee..bed35bf 100644 --- a/plugins/DattoRMM/v1/metadata.json +++ b/plugins/DattoRMM/v1/metadata.json @@ -40,7 +40,7 @@ "oauth2ClientSecretLocationDuringAuth": "header", "authMode": "oauth2", "oauth2GrantType": "clientCredentials", - "baseUrl": "{{baseUrl}}/api/v2/", + "baseUrl": "{{baseUrl}}", "oauth2TokenExtraHeaders": [], "oauth2ClientId": "public-client", "oauth2TokenUrl": "{{baseUrl}}/auth/oauth/token", diff --git a/plugins/DattoRMM/v1/ui.json b/plugins/DattoRMM/v1/ui.json index 5e2dba5..c84554a 100644 --- a/plugins/DattoRMM/v1/ui.json +++ b/plugins/DattoRMM/v1/ui.json @@ -16,8 +16,9 @@ { "type": "text", "name": "apiKey", - "label": "Client ID", - "placeholder": "Enter your Datto RMM API Client ID", + "label": "API Key", + "placeholder": "Enter your Datto RMM API Key", + "help": "Enter the API Key from the Datto RMM Access Control screen https://rmm.datto.com/help/en/Content/2SETUP/APIv2.htm", "validation": { "required": true } @@ -25,8 +26,9 @@ { "type": "password", "name": "apiSecret", - "label": "Client Secret", - "placeholder": "Enter your Datto RMM API Client Secret", + "label": "API Secret", + "placeholder": "Enter your Datto RMM API Secret Key", + "help": "Enter the API Secret Key from the Datto RMM Access Control screen", "validation": { "required": true } From f39cbfbb72f7783d41c940152e0364db57aa76c7 Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:27:12 +0100 Subject: [PATCH 09/10] New Datto plugin - Import, 4 datastreams and Oauth2 setup --- .github/CODEOWNERS | 1 + .gitignore | 7 + cspell.json | 1 + plugins/DattoRMM/v1/cspell.json | 7 + plugins/DattoRMM/v1/custom_types.json | 16 ++ .../v1/dataStreams/dattoAllDevices.json | 145 ++++++++++++++++++ .../dataStreams/dattoScopeClosedAlerts.json | 81 ++++++++++ .../v1/dataStreams/dattoScopeOpenAlerts.json | 77 ++++++++++ .../DattoRMM/v1/dataStreams/importSites.json | 100 ++++++++++++ plugins/DattoRMM/v1/docs/README.md | 26 ++++ plugins/DattoRMM/v1/icon.png | Bin 0 -> 2437 bytes .../DattoRMM/v1/indexDefinitions/default.json | 43 ++++++ plugins/DattoRMM/v1/metadata.json | 62 ++++++++ plugins/DattoRMM/v1/ui.json | 36 +++++ 14 files changed, 602 insertions(+) create mode 100644 plugins/DattoRMM/v1/cspell.json create mode 100644 plugins/DattoRMM/v1/custom_types.json create mode 100644 plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json create mode 100644 plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json create mode 100644 plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json create mode 100644 plugins/DattoRMM/v1/dataStreams/importSites.json create mode 100644 plugins/DattoRMM/v1/docs/README.md create mode 100644 plugins/DattoRMM/v1/icon.png create mode 100644 plugins/DattoRMM/v1/indexDefinitions/default.json create mode 100644 plugins/DattoRMM/v1/metadata.json create mode 100644 plugins/DattoRMM/v1/ui.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 498bd01..9948a76 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,7 @@ /.github/* @squaredup/community-moderators # Request review from original author +plugins/DattoRMM/* @TimWheeler-SQUP plugins/DigiCert/* @shaswot77 plugins/FantasyPremierLeague/* @TimWheeler-SQUP plugins/GoogleSheets/* @kieranlangton diff --git a/.gitignore b/.gitignore index 43ec304..dd3bb92 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,13 @@ logs/ *.local.json +############################################ +# Claude Code (local only, never commit) +############################################ + +*.local.md + + ############################################ # Optional: generated assets ############################################ diff --git a/cspell.json b/cspell.json index d1b7aa6..d563d67 100644 --- a/cspell.json +++ b/cspell.json @@ -1,5 +1,6 @@ { "words": [ + "Datto", "Phare", "rdap", "whois", diff --git a/plugins/DattoRMM/v1/cspell.json b/plugins/DattoRMM/v1/cspell.json new file mode 100644 index 0000000..de5e43a --- /dev/null +++ b/plugins/DattoRMM/v1/cspell.json @@ -0,0 +1,7 @@ +{ + "words": [ + "Datto", + "RMM", + "centrastage" + ] +} diff --git a/plugins/DattoRMM/v1/custom_types.json b/plugins/DattoRMM/v1/custom_types.json new file mode 100644 index 0000000..3629a3c --- /dev/null +++ b/plugins/DattoRMM/v1/custom_types.json @@ -0,0 +1,16 @@ +[ + { + "icon": "building", + "name": "Datto Site", + "plural": "Sites", + "singular": "Site", + "sourceType": "Datto Site" + }, + { + "icon": "desktop", + "name": "Datto Device", + "plural": "Devices", + "singular": "Device", + "sourceType": "Datto Device" + } +] diff --git a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json new file mode 100644 index 0000000..63ed896 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -0,0 +1,145 @@ +{ + "name": "dattoAllDevices", + "displayName": "Devices", + "description": "All devices across all sites", + "tags": ["Devices"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "paging": { + "mode": "nextUrl", + "pageSize": { + "realm": { + "value": "none", + "label": "none" + } + }, + "in": { + "realm": { + "value": "payload", + "label": "payload" + }, + "path": "pageDetails.nextPageUrl" + } + }, + "expandInnerObjects": true, + "endpointPath": "api/v2/account/devices", + "pathToData": "devices", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "shape": "string", + "name": "id", + "visible": false + }, + { + "shape": "string", + "name": "siteUid", + "visible": false + }, + { + "shape": "string", + "name": "siteId", + "visible": false + }, + { + "displayName": "Hostname", + "shape": "string", + "name": "hostname" + }, + { + "displayName": "Site", + "shape": "string", + "name": "siteName" + }, + { + "displayName": "Device Class", + "shape": "string", + "name": "deviceClass" + }, + { + "displayName": "Operating System", + "shape": "string", + "name": "operatingSystem" + }, + { + "displayName": "Online Status", + "shape": "string", + "name": "onlineStatus" + }, + { + "displayName": "Last Seen", + "shape": "date", + "name": "lastSeen" + }, + { + "displayName": "Creation Date", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "creationDate" + }, + { + "displayName": "Last Audit Date", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "lastAuditDate" + }, + { + "displayName": "Patches Approved Pending", + "shape": ["number", { "decimalPlaces": 0 }], + "name": "patchManagement.patchesApprovedPending" + }, + { + "displayName": "Patches Installed", + "shape": ["number", { "decimalPlaces": 0 }], + "name": "patchManagement.patchesInstalled" + }, + { + "displayName": "Patches Not Approved", + "shape": ["number", { "decimalPlaces": 0 }], + "name": "patchManagement.patchesNotApproved" + }, + { + "displayName": "Compliance State", + "name": "softwareComplianceState", + "computed": true, + "valueExpression": "{{ $['softwareStatus'] }}", + "shape": ["state", { + "map": { + "success": ["Compliant"], + "error": ["Not Compliant"], + "warning": [], + "unknown": [], + "unmonitored": [] + } + }] + }, + { + "pattern": "udf.*", + "visible": false + }, + { + "pattern": ".*" + } + ], + "providesPluginDiagnostics": true, + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "thisQuarter", + "thisYear", + "lastMonth", + "lastQuarter", + "lastYear", + "none" + ] +} \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json new file mode 100644 index 0000000..90bdce6 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json @@ -0,0 +1,81 @@ +{ + "name": "dattoScopeClosedAlerts", + "displayName": "Closed Alerts", + "description": "Resolved alerts for a specific site", + "tags": ["Alerts"], + "baseDataSourceName": "httpRequestScopedSingle", + "matches": { + "sourceType": { + "type": "equals", + "value": "Datto Site" + } + }, + "config": { + "httpMethod": "get", + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "endpointPath": "api/v2/site/{{objects[0].siteUid}}/alerts/resolved", + "pathToData": "alerts", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "name": "sourceId", + "displayName": "Object ID", + "shape": "string", + "visible": false + }, + { + "displayName": "Alert Message", + "shape": "string", + "name": "alertSourceInfo.alertMessage" + }, + { + "displayName": "Alert Type", + "shape": "string", + "name": "alertSourceInfo.alertTypeDescription" + }, + { + "displayName": "Device", + "shape": "string", + "name": "alertSourceInfo.alertContext.hostname" + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.deviceUid", + "visible": false + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.siteUid", + "visible": false + }, + { + "displayName": "Priority", + "shape": "string", + "name": "priority" + }, + { + "displayName": "Raised", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "timestamp" + }, + { + "displayName": "Resolved", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "resolvedAt" + }, + { + "pattern": ".*" + } + ], + "timeframes": false +} diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json new file mode 100644 index 0000000..48829f0 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json @@ -0,0 +1,77 @@ +{ + "name": "dattoScopeOpenAlerts", + "displayName": "Open Alerts", + "description": "Open alerts for a specific site", + "tags": ["Alerts"], + "baseDataSourceName": "httpRequestScopedSingle", + "matches": { + "sourceType": { + "type": "equals", + "value": "Datto Site" + } + }, + "config": { + "httpMethod": "get", + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "endpointPath": "api/v2/site/{{objects[0].siteUid}}/alerts/open", + "pathToData": "alerts", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "name": "sourceId", + "displayName": "Object ID", + "shape": "string", + "visible": false + }, + { + "displayName": "Alert Message", + "shape": "string", + "name": "alertSourceInfo.alertMessage" + }, + { + "displayName": "Alert Type", + "shape": "string", + "name": "alertSourceInfo.alertTypeDescription" + }, + { + "displayName": "Device", + "shape": "string", + "name": "alertSourceInfo.alertContext.hostname" + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.deviceUid", + "visible": false + }, + { + "shape": "string", + "name": "alertSourceInfo.alertContext.siteUid", + "visible": false + }, + { + "displayName": "Priority", + "shape": "string", + "name": "priority" + }, + { + "displayName": "Timestamp", + "shape": ["date", { "timeZone": "Etc/UTC" }], + "name": "timestamp" + }, + { + "pattern": ".*" + } + ], + "providesPluginDiagnostics": true, + "timeframes": false +} \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json new file mode 100644 index 0000000..15accd5 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -0,0 +1,100 @@ +{ + "name": "importSites", + "displayName": "Sites", + "description": "All sites in the account", + "tags": ["Sites"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "paging": { + "mode": "nextUrl", + "pageSize": { + "realm": { + "value": "none", + "label": "none" + } + }, + "in": { + "realm": { + "value": "payload", + "label": "payload" + }, + "path": "pageDetails.nextPageUrl" + } + }, + "expandInnerObjects": true, + "endpointPath": "api/v2/account/sites", + "pathToData": "sites", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": "string", + "name": "uid", + "visible": false + }, + { + "displayName": "Name", + "shape": "string", + "name": "name" + }, + { + "displayName": "Description", + "shape": "string", + "name": "description" + }, + { + "displayName": "Notes", + "shape": "string", + "name": "notes" + }, + { + "displayName": "Total Devices", + "shape": [ + "number", + { + "decimalPlaces": 0 + } + ], + "name": "devicesStatus.numberOfDevices" + }, + { + "displayName": "Offline Devices", + "shape": [ + "number", + { + "decimalPlaces": 0 + } + ], + "name": "devicesStatus.numberOfOfflineDevices" + }, + { + "displayName": "Online Devices", + "shape": [ + "number", + { + "decimalPlaces": 0 + } + ], + "name": "devicesStatus.numberOfOnlineDevices" + }, + { + "pattern": ".*" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "thisQuarter", + "thisYear", + "lastMonth", + "lastQuarter", + "lastYear", + "none" + ] +} \ No newline at end of file diff --git a/plugins/DattoRMM/v1/docs/README.md b/plugins/DattoRMM/v1/docs/README.md new file mode 100644 index 0000000..a5225b1 --- /dev/null +++ b/plugins/DattoRMM/v1/docs/README.md @@ -0,0 +1,26 @@ +# Before you start + +[Datto RMM](https://www.datto.com/rmm) is a cloud-based Remote Monitoring and Management (RMM) platform used by Managed Service Providers (MSPs) to monitor, manage and support client devices. This plugin lets you import your Datto RMM sites and devices into SquaredUp, and monitor open alerts scoped to individual sites. + +## What is imported + +The following objects are imported and kept in sync: + +- **Sites** — each managed client site, including device counts (total, online, offline) +- **Devices** — all endpoints across all sites, including hostname, operating system, online status, last seen time, and internal/external IP addresses + +## Data streams + +| Data stream | Description | +|-------------|-------------| +| **All Devices** | Returns all devices across every site. Use this to build fleet-wide views or group by site. | +| **Open Alerts** | Returns open alerts scoped to an imported site object. Use this on site dashboards to surface active issues. | + +## Setup + +You will need the **Base URL**, **API Key** and **API Secret** for your Datto RMM account. + +1. Log in to Datto RMM and navigate to **Setup** > **API** +2. Copy the **API URL** — this is your Base URL (e.g. `https://merlot-api.centrastage.net`) +3. Under **API Users**, create a new API user or select an existing one +4. Copy the **API Key** and **API Secret** for that user diff --git a/plugins/DattoRMM/v1/icon.png b/plugins/DattoRMM/v1/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..da4522235a9831e5fa52e5025c8dc6d303da5165 GIT binary patch literal 2437 zcmai$i9ZvJ1BWNdo%DkvTTzPNX@8UMA+6s|zI}BcjP2d6{xF#~jNX z$$iWfRAFXAt>e42~Ph`TD~pe}ukuz#G@~s);tXxFh?rr+0o!Ikope86~D>noM19 zq^!mhX3&)r%2+R~`xzH3_JVvm~q?U}7Xsy-jBi z_cnNa%|ZUAeVI}h*9EpGQvbCm<)r1<-Iiv`pg|I-uXy&_jQGU_?OAY8<*62!`TFQC zK>}6CXC)FhwS@_pO^YR(mpnVtqMbgvzKy*#%UaFAd?Ra3sqwCazZI&btKRs!W%Hu- zw>j;}!>!0m`gWPNhrx#ol2tch@|iN-OS-W9s8XprTu-vT+rs44!lwg?r#lu*k3 zAV%fW1>jJ|uF_AwYcnxEhK~k9V6xlGA0)EDox~(9#9n=ZH-Eo=`c>E(`)aYVxX0u$ z61W~I_sRdUy9upeyGEIpl#Fr?YwvKDikRkc1O{MaY*;TLzbb}0QvcFz4j;v?#N(%3 z)30ZwF?W(4r5Y(0SgC}-1b~7^;{VM0wU_c(slG(6N2K<(ZM09@&lj+|*g!>}+1xmv zQ-%8#xrG1iW`13i4LGL~L7CWc_3Y3)E<2(C`Q)G5IEs?9=CssjJv$e}iO)EDF zE$}hl#75OT(*rRv;sTBUen5o z4f>5G3+U9~h>=H`3igFoDNwUAI;sU$O@Hf|gHdzp0b^>9v5Dtv*$rK($>BSK(E0~! z8UF?=*6=IP}hMH5DQprO(8xyW7S+VwPNy*#omZR%3+dgJYs`pT?<$;C4@BCCmwJ~NQZK&R(t2i8N zk0H$@pZr`_)S$_^cUnY-w81WX#b-TJs9y&)GpX$a&g37L8T2U z0}>fz$(?m*$t>qzF4`%&H+-ptY+n&!rP8EZ=D=q0Cd0{SIo#QH0PDP{DVPE2A@-Do zntFOllU1a{@@RO$m|gxJ!;#%lG^L&dp|7CeaihjyWob#st^5gR`sqtBtu4G(qNu0x zDM)fO8}#~~+m-gbCahoUMxv1xrna#n02?N5S?=-cpI4ft0q~r@px1&)K6T#te9ir% zABRmbD|hDdKR*+Rxj1T1KI{;ZxB9jbMUtwP+IzCH+gjHz4xjL=J8{&~jn6zL;oHdO zP`_^*^Q^MVg0pnzy8(%#+$&CQOqT_Gy{u(~1;pQ8n)nKFzVfVO6#-0WRs>ii!n@OH zEI8}F(J{KEd4gtYS=3nF{pz1Z*(wn!L@t(Ty>X??1w@9tJx*BTR@u%ciIS;(&q$#} zKNs&zoI0pw7|Vmv;CIq17;!+8izbPr0`4_+v3M00Il`ftCl9yR1Y}R)N~oIms@0d0 zpB~dq-*RU=<1n3Hz`8><-UU~bH8-o`&}c=@k=8H^_seOkKRA1ndN}F+iyZc#^wz=a z@12LUsxpH;T;AK`>{_-tK!(R4*BsdF7f%-Vmt#>WLqrl-vDU^0$ImBouniM^koO)R z46k5`(QudkY;RG^q_4@&m>>${|U%rQPwzk;gvp z3;jCgiyWL9+^&Xo_q@29*p-}Je~&}34z#Fud|j~m1r7uFj7v)2-!b{DHAwUA045BV znoJrRHVXPKUR_Ha-wghO45C-g?c!th%8|_nIKdJdWrw z2W@@e_x*Xs`P?5J3lltIxCyt07E(B)U1q0S*h737$4Jv%1B3-{Y^GXhb7v9zc8Yn< zOq3)opBf8uPmyT%Kt1(!nH^uuyxpTRhVdV+M&@vhOa0?0P2FETRKJ5LcPKhG&{Hm8 z<1~=$nm!*8dB|d7ql1WaaX-uDKi|5ubcc_y^uaJ$uTCXgS|3wqE!2FhJ(Cq2O;gKl zJ3um|i+A!CQ&ha>X{_EwQ%0ySv*P4M)OrUh+(4oA=l!#IQ&G3ZmWVaitP`C2u$gZ- zoVc8Emn~i)EIECMVG~3ByN9{HiSVu`YwEG)r_~5Rg?#Fk_qJWpVGHmbzHuX+RYjKP zmp^9Fp+w=3iM>Ck_{d;Gv5j!~U(FqIgzgLPH-Vq^mB+q#DaLU$-_4B!k?T_zE?zTS ox*05S5W_3>-`OE$rhmp%ll@dRSLSoUpRNKxOrXY API.", + "validation": { + "required": true, + "pattern": { + "value": "^https?://[^\\s]+$", + "message": "Please enter a valid URL starting with https://" + } + } + }, + { + "type": "text", + "name": "apiKey", + "label": "API Key", + "placeholder": "Enter your Datto RMM API Key", + "help": "Enter the API Key from the Datto RMM Access Control screen https://rmm.datto.com/help/en/Content/2SETUP/APIv2.htm", + "validation": { + "required": true + } + }, + { + "type": "password", + "name": "apiSecret", + "label": "API Secret", + "placeholder": "Enter your Datto RMM API Secret Key", + "help": "Enter the API Secret Key from the Datto RMM Access Control screen", + "validation": { + "required": true + } + } +] From 85fc425544927faab0805601f93b17d9d205a0ab Mon Sep 17 00:00:00 2001 From: Tim Wheeler <63284593+TimWheeler-SQUP@users.noreply.github.com> Date: Mon, 13 Apr 2026 10:01:27 +0100 Subject: [PATCH 10/10] Add paging to data streams --- .gitignore | 7 ------- .../DattoRMM/v1/dataStreams/dattoAllDevices.json | 15 +-------------- .../v1/dataStreams/dattoScopeClosedAlerts.json | 11 +++++++++-- .../v1/dataStreams/dattoScopeOpenAlerts.json | 9 ++++++++- plugins/DattoRMM/v1/dataStreams/importSites.json | 15 +-------------- 5 files changed, 19 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index dd3bb92..43ec304 100644 --- a/.gitignore +++ b/.gitignore @@ -81,13 +81,6 @@ logs/ *.local.json -############################################ -# Claude Code (local only, never commit) -############################################ - -*.local.md - - ############################################ # Optional: generated assets ############################################ diff --git a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json index 63ed896..da441ba 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -128,18 +128,5 @@ } ], "providesPluginDiagnostics": true, - "timeframes": [ - "last1hour", - "last12hours", - "last24hours", - "last7days", - "last30days", - "thisMonth", - "thisQuarter", - "thisYear", - "lastMonth", - "lastQuarter", - "lastYear", - "none" - ] + "timeframes": false } \ No newline at end of file diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json index 90bdce6..48b5cd7 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json @@ -13,7 +13,14 @@ "config": { "httpMethod": "get", "paging": { - "mode": "none" + "mode": "nextUrl", + "pageSize": { + "realm": { "value": "none", "label": "none" } + }, + "in": { + "realm": { "value": "payload", "label": "payload" }, + "path": "pageDetails.nextPageUrl" + } }, "expandInnerObjects": true, "endpointPath": "api/v2/site/{{objects[0].siteUid}}/alerts/resolved", @@ -71,7 +78,7 @@ { "displayName": "Resolved", "shape": ["date", { "timeZone": "Etc/UTC" }], - "name": "resolvedAt" + "name": "resolvedOn" }, { "pattern": ".*" diff --git a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json index 48829f0..7f59aa3 100644 --- a/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json @@ -13,7 +13,14 @@ "config": { "httpMethod": "get", "paging": { - "mode": "none" + "mode": "nextUrl", + "pageSize": { + "realm": { "value": "none", "label": "none" } + }, + "in": { + "realm": { "value": "payload", "label": "payload" }, + "path": "pageDetails.nextPageUrl" + } }, "expandInnerObjects": true, "endpointPath": "api/v2/site/{{objects[0].siteUid}}/alerts/open", diff --git a/plugins/DattoRMM/v1/dataStreams/importSites.json b/plugins/DattoRMM/v1/dataStreams/importSites.json index 15accd5..2d73df4 100644 --- a/plugins/DattoRMM/v1/dataStreams/importSites.json +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -83,18 +83,5 @@ "pattern": ".*" } ], - "timeframes": [ - "last1hour", - "last12hours", - "last24hours", - "last7days", - "last30days", - "thisMonth", - "thisQuarter", - "thisYear", - "lastMonth", - "lastQuarter", - "lastYear", - "none" - ] + "timeframes": false } \ No newline at end of file