gilesknap / maaspower

Provide MAAS power control via webhooks for various remote control power switches.
Apache License 2.0
21 stars 14 forks source link

Additional type of device control - REST #33

Open FrostbyteGR opened 4 months ago

FrostbyteGR commented 4 months ago

Greetings,

Inspired by my previous idea, I believe that a RESTful type of device control could be more useful.

The added benefits versus the SSH variant would be:

Here's a generic example:

name: maaspower rest example
ip_address: <MAASPOWER_LISTEN_IP>
port: <MAASPOWER_LISTEN_PORT>
username: <MAASPOWER_USERNAME>
password: <MAASPOWER_PASSWORD>
devices:
- type: REST
    name: <DEVICE_NAME>\d+
    username: <DEVICE_USERNAME>
    password: <DEVICE_PASSWORD>
    on: <DEVICE_ON_URL>
    on-method: <GET|PATCH|PUT|DELETE|POST>
    off: <DEVICE_OFF_URL>
    off-method: <GET|PATCH|PUT|DELETE|POST>
    query: <DEVICE_QUERY_URL>
    query-method: <GET|PATCH|PUT|DELETE|POST>
    query_on_regex: <DEVICE_QUERY_ON_REGEX>
    query_off_regex: <DEVICE_QUERY_OFF_REGEX>

As usual, an example on how it could work with MikroTik PoE devices (i.e. CRS328-24P-4S+RM):

name: maaspower mikrotik rest example
ip_address: <MAASPOWER_LISTEN_IP>
port: <MAASPOWER_LISTEN_PORT>
username: <MAASPOWER_USERNAME>
password: <MAASPOWER_PASSWORD>
devices:
- type: REST
    name: ether\d+
    username: <MIKROTIK_REST_USERNAME>
    password: <MIKROTIK_REST_PASSWORD>
    on: http://<MIKROTIK_ADDRESS>/rest/interface/ethernet/poe/set
    on-method: POST
    on-data: {".id":"\g<0>","poe-out":"auto-on"}
    off: http://<MIKROTIK_ADDRESS>/rest/interface/ethernet/poe/set
    off-method: POST
    off-data: {".id":"\g<0>","poe-out":"off"}
    query: http://<MIKROTIK_ADDRESS>/rest/interface/ethernet/poe/monitor
    query-method: POST
    query-data: {"once":"1",".id":"\g<0>"}
    query_on_regex: \"poe-out-status\":\"powered-on\"
    query_off_regex: \"poe-out-status\":\"(waiting-for-load|disabled)\"

NOTE: on-data,off-data and query-data should be ignored if their respective method is undefined, blank or set to GET. There might also be a need to define additional options like the request header. (i.e. Content-Type: application/json)

Here's how I'm currently achieving it via type: CommandLine:

  - type: CommandLine
    name: ether\d+
    on: maaspower_rest_mikrotik.sh \g<0> on
    off: maaspower_rest_mikrotik.sh \g<0> off
    query: maaspower_rest_mikrotik.sh \g<0> check
    query_on_regex: ^powered-on$
    query_off_regex: ^powered-off$

And a maaspower_rest_mikrotik.sh that looks like this:

#!/bin/sh

# Configured variables
mtAddress=<MIKROTIK_ADDRESS>
mtUsername=<MIKROTIK_USERNAME>
mtPassword=<MIKROTIK_PASSWORD>
mtInterfacePrefix='ether'

# cURL command
curlCmd="curl -s -u '$mtUsername:$mtPassword' -X POST -H 'Content-Type: application/json' http://$mtAddress/rest"

# MikroTik PoE commands
poeOnCmd="$curlCmd/interface/ethernet/poe/set --data '{\".id\":\"$1\",\"poe-out\":\"auto-on\"}'"
poeOffCmd="$curlCmd/interface/ethernet/poe/set --data '{\".id\":\"$1\",\"poe-out\":\"off\"}'"
poeCheckCmd="$curlCmd/interface/ethernet/poe/monitor --data '{\"once\":\"1\",\".id\":\"$1\"}'"

# Usage helper function
usage() {
cat << EOF
Usage:
$0 <interface> <on|off|check>
Example: $0 ether1 check
EOF
exit 3
}

# Validate user-supplied arguments
[  $# -eq 2 ] && [ -z $(echo $1 | grep -Ev "^$mtInterfacePrefix[0-9]+$") ] || usage
case $2 in
        on) eval $poeOnCmd ;;
        off) eval $poeOffCmd ;;
        check) eval $poeCheckCmd | grep -Eo '\"poe-out-status\":\"[a-z\-]+\"' | awk -F\" '{print $4}' | sed -E 's/^(waiting-for-load|disabled)$/powered-off/' ;;
        *) usage ;;
esac

And as always, many thanks again for this project!

gilesknap commented 4 months ago

Hi @FrostbyteGR thanks for the suggestion.

It seems like a good idea to me. I'm not personally running MAAS anymore so I don't expect to get around to making new features here.

If you are offering to have a go at implementing this then I'd be happy to review and will merge any useful PRs.