PlaceOS/drivers

feat(cisco/meraki): support webhook subscriptions for switch port up/down in existing Meraki Dashboard Driver

Opened this issue · 2 comments

w-le commented

Extend existing Meraki driver to support webhook subscriptions for switch port up and down

Taken from a private internal solution design document authored by Will:

3.1.1.2 New Logic Driver: Meraki Switch Port Status

A new PlaceOS Logic Module will initially fetch the state of every switch port that we are interested in (switch port connected to a desk that is being monitored) and expose these as status variables.
The Logic module will use the existing Meraki Dashboard API driver to fetch the data.
Logic Module’s settings (inherited from System/Zones) will include an array of Network Switch serial strings (e.g. "Q2ZP-VE3T-JC2X")
For each switch, get all it’s ports’ status
GET /devices/{serial}/switch/ports/statuses
Example Response

[
    {
        "portId": "1",
        "enabled": true,
        "status": "Disconnected",
        "isUplink": false,
        "errors": [
            "Port disconnected"
        ],
        "warnings": [],
        "speed": "",
        "duplex": "",
        "usageInKb": {
            "total": 0,
            "sent": 0,
            "recv": 0
        },
        "cdp": {
            "platform": "Cisco CISCO1921/K9",
            "deviceId": "CPE-REDACTED-BRISBANE-9272.cpe.overthew",
            "portId": "GigabitEthernet0/1",
            "address": "10.1.74.66",
            "managementAddress": "10.1.74.66",
            "version": "Cisco IOS Software, C1900 Software (C1900-UNIVERSALK9-M), Version 15.6(3)M4, RELEASE SOFTWARE (fc1)\nTechnical Support: http://www.cisco.com/techsupport\nCopyright (c) 1986-2018 by Cisco Systems, Inc.\nCompiled Mon 05-Feb-18 09:56 by prod_rel_team",
            "capabilities": "Router, Source route bridge, Switch"
        },
        "clientCount": 0,
        "powerUsageInWh": 0.0,
        "trafficInKbps": {
            "total": 0.0,
            "sent": 0.0,
            "recv": 0.0
        },
        "securePort": {
            "enabled": false,
            "active": false,
            "authenticationStatus": "Disabled",
            "configOverrides": {}
        }
    },
    {
        "portId": "11",
        "enabled": true,
        "status": "Connected",
        "isUplink": false,
        "errors": [],
        "warnings": [],
        "speed": "1 Gbps",
        "duplex": "full",
        "usageInKb": {
            "total": 615095,
            "sent": 380561,
            "recv": 234534
        },
        "lldp": {
            "portId": "REDACTED:MAC:ADDRESS",
            "chassisId": "REDACTED:MAC:ADDRESS"
        },
        "clientCount": 1,
        "powerUsageInWh": 0.0,
        "trafficInKbps": {
            "total": 58.3,
            "sent": 36.1,
            "recv": 22.2
        },
        "securePort": {
            "enabled": false,
            "active": false,
            "authenticationStatus": "Disabled",
            "configOverrides": {}
        }
    }
]

In order to unnecessary polling and reduce latency, the logic module (from 2) will subscribe to webhook updates from Meraki Dashboard API for:
Switch port has device connected
As seen from Dashboard API /organizations/:organizationId/webhooks/alertTypes

{
        "alertTypeId": "port_connected",
        "alertType": "Switch port connected",
        "example": {
            "version": "0.1",
            "sharedSecret": "secret",
            "sentAt": "2022-12-02T06:59:59.796865Z",
            "organizationId": "2930418",
            "organizationName": "My organization",
            "organizationUrl": "https://dashboard.meraki.com/o/VjjsAd/manage/organization/overview",
            "networkId": "REDACTED",
            "networkName": "Main Office",
            "networkUrl": "https://n1.meraki.com//n//manage/nodes/list",
            "networkTags": [],
            "deviceSerial": "REDACTED",
            "deviceMac": "REDACTED:MAC:ADDRESS",
            "deviceName": "My switch",
            "deviceUrl": "https://n1.meraki.com//n//manage/nodes/new_list/000000000000",
            "deviceTags": [
                "tag1",
                "tag2"
            ],
            "deviceModel": "MS",
            "alertId": "0000000000000000",
            "alertType": "Switch port connected",
            "alertTypeId": "port_connected",
            "alertLevel": "informational",
            "occurredAt": "2018-02-11T00:00:00.123450Z",
            "alertData": {
                "portNum": 3,
                "description": "Switch port is up at 10 Gbps",
                "status": "10 Gbps",
                "prevStatus": "down",
                "portDesc": "Corp Access"
            },
            "enrollmentString": "my-enrollment-string",
            "notes": "Additional description of the network",
            "productTypes": [
                "appliance",
                "switch",
                "wireless"
            ]
        }

Switch port has device disconnected
As seen from Dashboard API /organizations/:organizationId/webhooks/alertTypes

{
        "alertTypeId": "port_disconnected",
        "alertType": "Switch port disconnected",
        "example": {
            "version": "0.1",
            "sharedSecret": "secret",
            "sentAt": "2022-12-02T06:59:59.806170Z",
            "organizationId": "2930418",
            "organizationName": "My organization",
            "organizationUrl": "https://dashboard.meraki.com/o/VjjsAd/manage/organization/overview",
            "networkId": "N_24329156",
            "networkName": "Main Office",
            "networkUrl": "https://n1.meraki.com//n//manage/nodes/list",
            "networkTags": [],
            "deviceSerial": "Q234-ABCD-5678",
            "deviceMac": "00:11:22:33:44:55",
            "deviceName": "My switch",
            "deviceUrl": "https://n1.meraki.com//n//manage/nodes/new_list/000000000000",
            "deviceTags": [
                "tag1",
                "tag2"
            ],
            "deviceModel": "MS",
            "alertId": "0000000000000000",
            "alertType": "Switch port disconnected",
            "alertTypeId": "port_disconnected",
            "alertLevel": "warning",
            "occurredAt": "2018-02-11T00:00:00.123450Z",
            "alertData": {
                "portNum": 3,
                "description": "Switch port is down",
                "status": "down",
                "prevStatus": "100 Gbps",
                "portDesc": "Corp Access"
            },
            "enrollmentString": "my-enrollment-string",
            "notes": "Additional description of the network",
            "productTypes": [
                "appliance",
                "switch",
                "wireless"
            ]
        }

There are two scenarios in which the Logic driver must determine which USER (Azure AD User) is connected to the switch port:
After the initial poll of each switch’s port status (1.b)
There must then be a leap from the client mac address (from 1.b.ii lldp.portId) to the Meraki Client ID and description. The client.description is important for this particular implementation because the Meraki administrators have ensured that it matches the AAD User’s managedDevice’s deviceName. This will be done with GET /networks//clients?mac= which has example response:
[
{
"id": "ka44fb0",
"mac": "50:81:40:b1:96:c0",
"description": "XX-EBG8-12345",
"ip": "10.120.12.34",
"ip6": null,
"ip6Local": "fe80:0:0:0:683e:40bd:e0b:1234",
"user": null,
"firstSeen": "2021-10-20T23:28:22Z",
"lastSeen": "2022-12-05T11:59:32Z",
"manufacturer": "HP",
"os": null,
"deviceTypePrediction": null,
"recentDeviceSerial": "Q2ZP-VE3T-REDACTED",
"recentDeviceName": "REDACTED",
"recentDeviceMac": "ac:17:xx:52:76:xx",
"recentDeviceConnection": "Wired",
"ssid": null,
"vlan": "10",
"switchport": "11",
"usage": {
"sent": 190612,
"recv": 287176,
"total": 477789
},
"status": "Online",
"notes": "WS14/P75",
"smInstalled": false,
"groupPolicy8021x": null,
"adaptivePolicyGroup": null
}
]
When a “Port status: Connected” Webhook post is received (see section 3.1.1.1 point 3.d.ii.) from Meraki. See the example webhook data in 2.a.
Unfortunately there does not appear to be an API request available to get only the currently connected client’s details of a specific port of a Switch. So it appears we need to Get the status of all ports again (request 2a). We then locally filter for the port which changed to connected and use the client MAC in lldp.portId to determine the client data exactly as per 3.a.i.

w-le commented

@stakach has added support for receiving the webhook POST, in #412

There appears to be no way to create new webhook subscriptions via API calls, so we will have provide instructions to the meraki admin to post to us.

So there are no outstanding items related to webhooks. And the only remaining items for this gh issue are:

  1. Adding a new func to GET /devices/{serial}/switch/ports/statuses (REST GET, not webhook).
  2. Adding a new func to GET /networks//clients?mac= (see internal solution design doc section 3.1.1.2 bullet point 3.a.i

Correct me if I'm wrong on any of the above @stakach

w-le commented

deployed. poll works. webhook to be tested