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/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..da441ba --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoAllDevices.json @@ -0,0 +1,132 @@ +{ + "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": false +} \ 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..48b5cd7 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeClosedAlerts.json @@ -0,0 +1,88 @@ +{ + "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": "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", + "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": "resolvedOn" + }, + { + "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..7f59aa3 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/dattoScopeOpenAlerts.json @@ -0,0 +1,84 @@ +{ + "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": "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", + "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..2d73df4 --- /dev/null +++ b/plugins/DattoRMM/v1/dataStreams/importSites.json @@ -0,0 +1,87 @@ +{ + "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": false +} \ 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 0000000..da45222 Binary files /dev/null and b/plugins/DattoRMM/v1/icon.png differ 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" } + ] + } + } + ] +} diff --git a/plugins/DattoRMM/v1/metadata.json b/plugins/DattoRMM/v1/metadata.json new file mode 100644 index 0000000..bed35bf --- /dev/null +++ b/plugins/DattoRMM/v1/metadata.json @@ -0,0 +1,62 @@ +{ + "name": "datto-rmm", + "displayName": "Datto RMM", + "version": "1.0.0", + "author": { + "name": "@TimWheeler-SQUP", + "type": "community" + }, + "description": "Find and monitor your Datto RMM devices, sites and alerts.", + "category": "Monitoring", + "importNotSupported": false, + "type": "cloud", + "schemaVersion": "2.0", + "base": { + "plugin": "WebAPI", + "majorVersion": "1", + "config": { + "headers": [ + { + "value": "application/json", + "key": "Accept" + } + ], + "queryArgs": [], + "oauth2TokenExtraArgs": [ + { + "value": "password", + "key": "grant_type" + }, + { + "value": "{{apiKey}}", + "key": "username" + }, + { + "value": "{{apiSecret}}", + "key": "password" + } + ], + "oauth2ClientSecret": "public", + "oauth2ClientSecretLocationDuringAuth": "header", + "authMode": "oauth2", + "oauth2GrantType": "clientCredentials", + "baseUrl": "{{baseUrl}}", + "oauth2TokenExtraHeaders": [], + "oauth2ClientId": "public-client", + "oauth2TokenUrl": "{{baseUrl}}/auth/oauth/token", + "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 diff --git a/plugins/DattoRMM/v1/ui.json b/plugins/DattoRMM/v1/ui.json new file mode 100644 index 0000000..c84554a --- /dev/null +++ b/plugins/DattoRMM/v1/ui.json @@ -0,0 +1,36 @@ +[ + { + "type": "text", + "name": "baseUrl", + "label": "Base URL", + "placeholder": "https://merlot-api.centrastage.net", + "help": "Enter the root URL of your Datto RMM API instance (without /api/v2/). Find this in your Datto RMM account under Setup > 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 + } + } +]