forked from shaba/openuds
Added config for WOL on UDS
This commit is contained in:
parent
b9ba304493
commit
8c68da806a
@ -30,13 +30,60 @@
|
|||||||
"""
|
"""
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
|
import configparser
|
||||||
|
import logging
|
||||||
|
import typing
|
||||||
|
|
||||||
from django.utils.translation import ugettext_noop as _
|
from django.utils.translation import ugettext_noop as _
|
||||||
|
|
||||||
from uds.core import services
|
from uds.core import services
|
||||||
|
from uds.core.ui.user_interface import gui
|
||||||
|
from uds.core.util import net
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from uds.core.module import Module
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
VALID_CONFIG_SECTIONS = set(('wol',))
|
||||||
|
|
||||||
class PhysicalMachinesProvider(services.ServiceProvider):
|
class PhysicalMachinesProvider(services.ServiceProvider):
|
||||||
# No extra data needed
|
# No extra data needed
|
||||||
|
config = gui.TextField(
|
||||||
|
length=8192, multiline=6, label=_('Advanced configuration'), order=3,
|
||||||
|
tooltip=_('Advanced configuration data for the provider'),
|
||||||
|
required=True, tab=gui.ADVANCED_TAB
|
||||||
|
)
|
||||||
|
|
||||||
|
def initialize(self, values: 'Module.ValuesType') -> None:
|
||||||
|
if values is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.config.value = self.config.value.strip()
|
||||||
|
|
||||||
|
if self.config.value:
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
try:
|
||||||
|
config.read_string(self.config.value)
|
||||||
|
# Seems a valid configuration file, let's see if all se
|
||||||
|
except Exception as e:
|
||||||
|
raise services.ServiceProvider.ValidationException(_('Invalid advanced configuration: ') + str(e))
|
||||||
|
|
||||||
|
for section in config.sections():
|
||||||
|
if section not in VALID_CONFIG_SECTIONS:
|
||||||
|
raise services.ServiceProvider.ValidationException(_('Invalid section in advanced configuration: ') + section)
|
||||||
|
|
||||||
|
# Sections are valid, check values
|
||||||
|
# wol section
|
||||||
|
for key in config['wol']:
|
||||||
|
try:
|
||||||
|
net.networksFromString(key) # Raises exception if net is invalid
|
||||||
|
except Exception:
|
||||||
|
raise services.ServiceProvider.ValidationException(_('Invalid network in advanced configuration: ') + key)
|
||||||
|
# Now check value is an url
|
||||||
|
if config['wol'][key][:4] != 'http':
|
||||||
|
raise services.ServiceProvider.ValidationException(_('Invalid url in advanced configuration: ') + key)
|
||||||
|
|
||||||
|
|
||||||
# What services do we offer?
|
# What services do we offer?
|
||||||
typeName = _('Static IP Machines Provider')
|
typeName = _('Static IP Machines Provider')
|
||||||
@ -48,5 +95,20 @@ class PhysicalMachinesProvider(services.ServiceProvider):
|
|||||||
from .service_single import IPSingleMachineService
|
from .service_single import IPSingleMachineService
|
||||||
offers = [IPMachinesService, IPSingleMachineService]
|
offers = [IPMachinesService, IPSingleMachineService]
|
||||||
|
|
||||||
|
def wolURL(self, ip: str):
|
||||||
|
if not self.config.value:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
url = ''
|
||||||
|
try:
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read_string(self.config.value)
|
||||||
|
for key in config['wol']:
|
||||||
|
if net.ipInNetwork(ip, key):
|
||||||
|
return config['wol'][key]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Error parsing advanced configuration: %s', e)
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Physical Machines Provider"
|
return "Physical Machines Provider"
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"""
|
"""
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
import subprocess
|
import requests
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
@ -38,19 +38,8 @@ from uds.core import services
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# We have included a "hidden testing" for adding ip+mac as static machines list.
|
if typing.TYPE_CHECKING:
|
||||||
# (This is done using IP;MAC as IP on the IP list)
|
from . import provider
|
||||||
# This is a test for WOL, and to be used at your risk.
|
|
||||||
# Example:
|
|
||||||
# WOLAPP = "/usr/sbin/etherwake {MAC} -i eth0 -b"
|
|
||||||
# Remember that you MUST setuid /usr/sbin/etherwake (chmod +s ....) and allow only for uds user,
|
|
||||||
# so it allows uds user to execute "privileged" etherwake program
|
|
||||||
# Note:
|
|
||||||
# {MAC} will be replaced with the MAC if it exists
|
|
||||||
# {IP} will be replaced with the IP of the machine
|
|
||||||
# If empty, no WOL will be tried NEVER, if not empty
|
|
||||||
WOLAPP = ''
|
|
||||||
|
|
||||||
|
|
||||||
class IPServiceBase(services.Service):
|
class IPServiceBase(services.Service):
|
||||||
|
|
||||||
@ -65,6 +54,9 @@ class IPServiceBase(services.Service):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def parent(self) -> 'provider.PhysicalMachinesProvider':
|
||||||
|
return typing.cast('provider.PhysicalMachinesProvider', super().parent())
|
||||||
|
|
||||||
def getUnassignedMachine(self) -> typing.Optional[str]:
|
def getUnassignedMachine(self) -> typing.Optional[str]:
|
||||||
raise NotADirectoryError('getUnassignedMachine')
|
raise NotADirectoryError('getUnassignedMachine')
|
||||||
|
|
||||||
@ -72,11 +64,12 @@ class IPServiceBase(services.Service):
|
|||||||
raise NotADirectoryError('unassignMachine')
|
raise NotADirectoryError('unassignMachine')
|
||||||
|
|
||||||
def wakeup(self, ip: str, mac: typing.Optional[str]) -> None:
|
def wakeup(self, ip: str, mac: typing.Optional[str]) -> None:
|
||||||
if WOLAPP and mac:
|
if mac:
|
||||||
cmd = WOLAPP.replace('{MAC}', mac or '').replace('{IP}', ip or '')
|
wolurl = self.parent().wolURL(ip).replace('{MAC}', mac or '').replace('{IP}', ip or '')
|
||||||
logger.info('Launching WOL: %s', cmd)
|
if wolurl:
|
||||||
|
logger.info('Launching WOL: %s', wolurl)
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(cmd, shell=True, check=True)
|
requests.get(wolurl, verify=False)
|
||||||
# logger.debug('Result: %s', result)
|
# logger.debug('Result: %s', result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error on WOL: %s', e)
|
logger.error('Error on WOL: %s', e)
|
||||||
|
@ -46,7 +46,7 @@ from uds.core.util import config
|
|||||||
from uds.core.services import types as serviceTypes
|
from uds.core.services import types as serviceTypes
|
||||||
|
|
||||||
from .deployment import IPMachineDeployed
|
from .deployment import IPMachineDeployed
|
||||||
from .service_base import IPServiceBase, WOLAPP
|
from .service_base import IPServiceBase
|
||||||
|
|
||||||
# Not imported at runtime, just for type checking
|
# Not imported at runtime, just for type checking
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
@ -204,7 +204,7 @@ class IPMachinesService(IPServiceBase):
|
|||||||
continue # The check failed not so long ago, skip it...
|
continue # The check failed not so long ago, skip it...
|
||||||
self.storage.putPickle(theIP, now)
|
self.storage.putPickle(theIP, now)
|
||||||
# Now, check if it is available on port, if required...
|
# Now, check if it is available on port, if required...
|
||||||
if self._port > 0 and not WOLAPP: # If configured WOLAPP, then check port is a nonsense...
|
if self._port > 0 and not self.parent().wolURL(theIP): # If configured WOL, check is a nonsense
|
||||||
if (
|
if (
|
||||||
connection.testServer(theIP, self._port, timeOut=0.5)
|
connection.testServer(theIP, self._port, timeOut=0.5)
|
||||||
is False
|
is False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user