diff options
-rw-r--r-- | actions.yml | 1 | ||||
-rw-r--r-- | automato/command.py | 37 | ||||
-rw-r--r-- | automato/transport.py | 23 | ||||
-rw-r--r-- | endpoints.yml | 6 |
4 files changed, 66 insertions, 1 deletions
diff --git a/actions.yml b/actions.yml index c91759c..caf6e70 100644 --- a/actions.yml +++ b/actions.yml @@ -11,3 +11,4 @@ send-hello: msg: Hello - host1.notify: msg: World! + - host1.wol: {} diff --git a/automato/command.py b/automato/command.py index 49956a0..1926c2e 100644 --- a/automato/command.py +++ b/automato/command.py @@ -1,5 +1,11 @@ from . import transport +import logging + +import binascii +import socket + +logger = logging.getLogger(__name__) ''' Implementations of Command: @@ -25,3 +31,34 @@ class NotifyCommand(Command): def execute(self, msg: str): self._transport.execHandleStderror(f'notify-send "{msg}"') + +''' +WakeOnLanCommand sends a WOL magic packet to wake a device. + +Transport: MetaDataTransport with attribute 'mac' set to the devices' +MAC Address in the standard XX:XX:XX:XX:XX:XX format. +''' +class WakeOnLanCommand(Command): + + def __init__(self, transport: transport.MetaDataTransport): + self._transport = transport + + def execute(self): + mac_bytes = b'' + try: + mac_bytes = binascii.unhexlify(self._transport.mac.replace(':','')) + except binascii.Error: + logger.error(f'MAC Address "{self._transport.mac}" failed to parse to binary') + return + + if len(mac_bytes) != 6: + logger.error(f'MAC Address "{self._transport.mac}" is malformed') + return + + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + magic = b'\xff' * 6 + mac_bytes * 16 + s.sendto(magic, ('<broadcast>', 7)) + + logger.debug(f'Sent magic packet to {self._transport.mac}') diff --git a/automato/transport.py b/automato/transport.py index 5067a92..327946e 100644 --- a/automato/transport.py +++ b/automato/transport.py @@ -1,6 +1,8 @@ import paramiko import logging +from typing import Union + logger = logging.getLogger(__name__) HOLD = 1 @@ -57,10 +59,29 @@ class Transport: def isConnected(self) -> bool: return self._connected +''' +MetaDataTransport holds any data passed to it. +It does not establish any connection and is only used +to store metadata that may be used by commands that do not +require a connection, such as Wake on Lan. +''' +class MetaDataTransport(Transport): + CONNECTION=THROWAWAY + + def __init__(self, **kwargs): + self._metadata = kwargs + + def __getattr__(self, attr): + return self._metadata[attr] + + def check(self): + return True + + class SshTransport(Transport): CONNECTION=HOLD - def __init__(self, hostname: str, port=22, username='root', password = None, id_file = None, allow_agent=False): + def __init__(self, hostname: str, port=22, username='root', password = None, id_file = None, allow_agent = False): super().__init__() self._hostname = hostname self._port = port diff --git a/endpoints.yml b/endpoints.yml index 26d5340..8a59517 100644 --- a/endpoints.yml +++ b/endpoints.yml @@ -5,10 +5,16 @@ host1: hostname: 'localhost' username: 'jonas' allow_agent: True + meta: + class: automato.transport.MetaDataTransport + mac: 00:00:00:00:00:00 commands: notify: class: automato.command.NotifyCommand transport: ssh + wol: + class: automato.command.WakeOnLanCommand + transport: meta states: user: class: automato.state.UserSessionState |