gilesknap / maaspower

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

Additional type of device control - SSH #21

Closed FrostbyteGR closed 1 month ago

FrostbyteGR commented 5 months ago

Greetings,

I was wondering, whether an SSH type of device control could be implemented into the project.

Here's a generic example:

name: maaspower ssh example
ip_address: <MAASPOWER_LISTEN_IP>
port: <MAASPOWER_LISTEN_PORT>
username: <MAASPOWER_USERNAME>
password: <MAASPOWER_PASSWORD>
devices:
- type: SSH
    name: <DEVICE_NAME>\d+
    username: <DEVICE_USERNAME>
    password: <DEVICE_PASSWORD>
    ssh-key: <RSA_KEY_FILE_PATH>
    on: <DEVICE_ON_COMMAND>
    off: <DEVICE_OFF_COMMAND>
    query: <DEVICE_QUERY_COMMAND>
    query_on_regex: <DEVICE_QUERY_ON_REGEX>
    query_off_regex: <DEVICE_QUERY_OFF_REGEX>

Here's another example that could possibly work with MikroTik PoE devices (i.e. CRS328-24P-4S+RM):

name: maaspower mikrotik ssh example
ip_address: <MAASPOWER_LISTEN_IP>
port: <MAASPOWER_LISTEN_PORT>
username: <MAASPOWER_USERNAME>
password: <MAASPOWER_PASSWORD>
devices:
- type: SSH
    name: ether\d+
    username: <MIKROTIK_SSH_USERNAME>
    password: <MIKROTIK_SSH_PASSWORD>
    ssh-key: <RSA_KEY_FILE_PATH>
    on: interface ethernet poe set poe-out=off \g<0>
    off: interface ethernet poe set poe-out=auto-on \g<0>
    query: interface ethernet poe monitor \g<0> once
    query_on_regex: ^[\t ]*poe-out-status:[\t ]+powered-on$
    query_off_regex: ^[\t ]*poe-out-status:[\t ]+(waiting-for-load|disabled)$

NOTE: password and ssh-key arguments should be mutually exclusive?

I believe that right now, the same thing can be achieved via type: CommandLine like this:

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

And a maaspower_ssh_mikrotik.sh like this:

#!/bin/sh

# Configured variables
mtAddress=<MIKROTIK_ADDRESS>
mtUsername=<MIKROTIK_USERNAME>
mtPrivateKey=<MIKROTIK_SSH_KEY>
mtInterfacePrefix='ether'

# SSH command
sshCmd="ssh -i $mtPrivateKey $mtUsername@$mtAddress"

# MikroTik PoE commands
poeOnCmd="$sshCmd interface ethernet poe set poe-out=auto-on $1"
poeOffCmd="$sshCmd interface ethernet poe set poe-out=off $1"
poeCheckCmd="$sshCmd interface ethernet poe monitor $1 once"

# 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:[\t ]*[a-z\-]+' | awk '{print $2}' | sed -E 's/^(waiting-for-load|disabled)$/powered-off/' ;;
        *) usage ;;
esac

Thus, I would consider it as a very low priority kind of request.

Many thanks for your time and efforts on this project!

gilesknap commented 5 months ago

This seems reasonable.

I'm not actively developing this project at present. I would look at PRs if anyone is up for trying to implement this idea.

FrostbyteGR commented 1 month ago

Now that I've actually had the chance to play around with it, looks like I did not RTFM properly back then. I've updated my first post with a more appropriate version of what would be, plus the way I achieved it with a wrapper script.

Since this appears to be fairly easy to achieve and sufficient enough, I believe this request/idea would be redundant.

adam-vest commented 2 weeks ago

I know this is closed, but I'm wondering how your wrapper script is working? I took a very similar approach to you (having a bash script that just executed ssh commands) and I've found that any version newer than 0.6.0 won't work since the ssh binary stopped being shipped.

I can probably just include an apt update && apt install -y openssh-client as part of the script, but that seems messy.

FrostbyteGR commented 2 weeks ago

I know this is closed, but I'm wondering how your wrapper script is working? I took a very similar approach to you (having a bash script that just executed ssh commands) and I've found that any version newer than 0.6.0 won't work since the ssh binary stopped being shipped.

I can probably just include an apt update && apt install -y openssh-client as part of the script, but that seems messy.

Hi, You just need to have an ssh client on your machine (which ssh). It's pretty much just a plain bash script, which you can run on it's own.

The only relevance it really has with maaspower; is how I validate the input arguments, and the resulting output. (To be simple and friendly towards the regex you will set in the *.cfg)

adam-vest commented 2 weeks ago

Oh, ha, I should clarify that I'm using the docker container, which stopped shipping the ssh binary in its container after v0.6.0. And yeah, I got around this by just adding a quick blurb right at the beginning of my script:

if [[ ! $(which ssh) ]]; then
        apt update && apt install openssh-client -y
fi