More fixes for WOL on Phisical Machines

This commit is contained in:
Adolfo Gómez García 2021-03-24 17:18:34 +01:00
parent 26aa9f6db7
commit 93a12c180e
4 changed files with 82 additions and 49 deletions

View File

@ -35,9 +35,12 @@ import typing
from django.utils.translation import ugettext_lazy as _
import dns.resolver
from uds.core import services
from uds.core.util.state import State
from uds.core.util.auto_attributes import AutoAttributes
from uds.core.util import net
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
@ -69,12 +72,22 @@ class IPMachineDeployed(services.UserDeployment, AutoAttributes):
def getIp(self) -> str:
# If single machine, ip is IP~counter,
# If multiple and has a ';' on IP, the values is IP;MAC
return self._ip.split('~')[0].split(';')[0]
ip = self._ip.split('~')[0].split(';')[0]
# If ip is in fact a hostname...
if not net.ipToLong(ip):
# Try to resolve name...
try:
res = dns.resolver.resolve(ip)
ip = res[0].address
except Exception:
pass
return ip
def getName(self) -> str:
# If single machine, ip is IP~counter,
# If multiple and has a ';' on IP, the values is IP;MAC
return _("IP ") + self._ip.replace('~', ':')
return self._ip.replace('~', ':')
def getUniqueId(self) -> str:
# If single machine, ip is IP~counter,

View File

@ -36,6 +36,8 @@ import typing
from django.utils.translation import ugettext_noop as _
import dns.resolver
from uds.core import services
from uds.core.ui.user_interface import gui
from uds.core.util import net
@ -47,15 +49,28 @@ logger = logging.getLogger(__name__)
VALID_CONFIG_SECTIONS = set(('wol',))
class PhysicalMachinesProvider(services.ServiceProvider):
# No extra data needed
config = gui.TextField(
length=8192, multiline=6, label=_('Advanced configuration'), order=3,
length=8192,
multiline=6,
label=_('Advanced configuration'),
order=3,
tooltip=_('Advanced configuration data for the provider'),
required=True, tab=gui.ADVANCED_TAB
required=True,
tab=gui.ADVANCED_TAB,
)
def initialize(self, values: 'Module.ValuesType') -> None:
"""checks and initializes values
Args:
values (Module.ValuesType): List of values on initialization (maybe None)
Raises:
services.ServiceProvider.ValidationException
"""
if values is None:
return
@ -67,23 +82,30 @@ class PhysicalMachinesProvider(services.ServiceProvider):
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))
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)
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)
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)
raise services.ServiceProvider.ValidationException(
_('Invalid url in advanced configuration: ') + key
)
# What services do we offer?
typeName = _('Static IP Machines Provider')
@ -93,22 +115,46 @@ class PhysicalMachinesProvider(services.ServiceProvider):
from .service_multi import IPMachinesService
from .service_single import IPSingleMachineService
offers = [IPMachinesService, IPSingleMachineService]
def wolURL(self, ip: str):
if not self.config.value or not ip:
def wolURL(self, ip: str, mac: str) -> str:
"""Tries to get WOL server for indicated IP
Args:
ip (str): ip of target machine
Returns:
str: URL of WOL server or empty ('') if no server for the ip is found
"""
if not self.config.value or not ip or not mac:
return ''
# If ip is in fact a hostname...
if not net.ipToLong(ip):
# Try to resolve name...
try:
res = dns.resolver.resolve(ip)
ip = res[0].address
except Exception:
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]
return (
config['wol'][key]
.replace('{MAC}', mac)
.replace('{IP}', ip)
)
except Exception as e:
logger.error('Error parsing advanced configuration: %s', e)
return ''
def __str__(self):
return "Physical Machines Provider"

View File

@ -34,39 +34,26 @@ import requests
import logging
import typing
import dns.resolver
from uds.core import services
from uds.core.util import net
logger = logging.getLogger(__name__)
if typing.TYPE_CHECKING:
from . import provider
class IPServiceBase(services.Service):
class IPServiceBase(services.Service):
@staticmethod
def getIp(ipData: str) -> str:
ip = ipData.split('~')[0].split(';')[0]
# If ip is in fact a hostname...
if not net.ipToLong(ip):
# Try to resolve name...
try:
res = dns.resolver.resolve(ip)
ip = res[0].address
except Exception:
return ''
return ip
return ipData.split('~')[0].split(';')[0]
@staticmethod
def getMac(ipData: str) -> typing.Optional[str]:
def getMac(ipData: str) -> str:
try:
return ipData.split('~')[0].split(';')[1]
except Exception:
return None
return ''
def parent(self) -> 'provider.PhysicalMachinesProvider':
return typing.cast('provider.PhysicalMachinesProvider', super().parent())
@ -79,7 +66,10 @@ class IPServiceBase(services.Service):
def wakeup(self, ip: str, mac: typing.Optional[str]) -> None:
if mac:
wolurl = self.parent().wolURL(ip).replace('{MAC}', mac or '').replace('{IP}', ip or '')
wolurl = (
self.parent()
.wolURL(ip, mac)
)
if wolurl:
logger.info('Launching WOL: %s', wolurl)
try:

View File

@ -31,7 +31,6 @@
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
import pickle
import subprocess
import logging
import typing
@ -197,18 +196,6 @@ class IPMachinesService(IPServiceBase):
consideredFreeTime = now - config.GlobalConfig.SESSION_EXPIRE_TIME.getInt(force=False) * 3600
for ip in self._ips:
theIP = IPServiceBase.getIp(ip)
if not theIP:
self.parent().doLog(
log.WARN,
'Hostname in {} could not be resolved. Skipped.'.format(
ip
),
)
logger.warning(
'Hostname in %s could not be resolved. Skipped.', ip
)
continue
theMAC = IPServiceBase.getMac(ip)
locked = self.storage.getPickle(theIP)
if not locked or locked < consideredFreeTime:
@ -216,7 +203,7 @@ class IPMachinesService(IPServiceBase):
continue # The check failed not so long ago, skip it...
self.storage.putPickle(theIP, now)
# Is WOL enabled?
wolENABLED = bool(theMAC and self.parent().wolURL(theIP))
wolENABLED = bool(self.parent().wolURL(theIP, theMAC))
# Now, check if it is available on port, if required...
if self._port > 0 and not wolENABLED: # If configured WOL, check is a nonsense
if (
@ -277,9 +264,6 @@ class IPMachinesService(IPServiceBase):
IPMachineDeployed, userDeployment
)
theIP = IPServiceBase.getIp(assignableId)
if not theIP:
return userServiceInstance.error('Hostname could not be resolved')
if self.storage.readData(theIP) is None:
self.storage.saveData(theIP, theIP)
return userServiceInstance.assign(theIP)