1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-27 14:03:53 +03:00

Fixing up new servers model

This commit is contained in:
Adolfo Gómez García 2023-11-17 03:23:43 +01:00
parent f3ddb68381
commit 8def04ccd7
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
12 changed files with 59 additions and 49 deletions

View File

@ -91,7 +91,7 @@ def logOperation(
username = handler.request.user.pretty_name if handler.request.user else 'Unknown' username = handler.request.user.pretty_name if handler.request.user else 'Unknown'
doLog( doLog(
None, None, # > None Objects goes to SYSLOG (global log)
level=level, level=level,
message=f'{handler.request.ip} [{username}]: [{handler.request.method}/{response_code}] {path}'[ message=f'{handler.request.ip} [{username}]: [{handler.request.method}/{response_code}] {path}'[
:4096 :4096

View File

@ -35,6 +35,7 @@ import typing
from django.utils.translation import gettext from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from traitlets import default
from uds.core import messaging, types from uds.core import messaging, types
from uds.core.environment import Environment from uds.core.environment import Environment
@ -60,6 +61,7 @@ class Notifiers(ModelHandler):
'comments', 'comments',
'level', 'level',
'tags', 'tags',
'enabled',
] ]
table_title = typing.cast(str, _('Notifiers')) table_title = typing.cast(str, _('Notifiers'))
@ -67,6 +69,7 @@ class Notifiers(ModelHandler):
{'name': {'title': _('Name'), 'visible': True, 'type': 'iconType'}}, {'name': {'title': _('Name'), 'visible': True, 'type': 'iconType'}},
{'type_name': {'title': _('Type')}}, {'type_name': {'title': _('Type')}},
{'level': {'title': _('Level')}}, {'level': {'title': _('Level')}},
{'enabled': {'title': _('Enabled')}},
{'comments': {'title': _('Comments')}}, {'comments': {'title': _('Comments')}},
{'tags': {'title': _('tags'), 'visible': False}}, {'tags': {'title': _('tags'), 'visible': False}},
] ]
@ -94,6 +97,14 @@ class Notifiers(ModelHandler):
'tooltip': gettext('Level of notifications'), 'tooltip': gettext('Level of notifications'),
'type': types.ui.FieldType.CHOICE, 'type': types.ui.FieldType.CHOICE,
'order': 102, 'order': 102,
},
{
'name': 'enabled',
'label': gettext('Enabled'),
'tooltip': gettext('If checked, this notifier will be used'),
'type': types.ui.FieldType.CHECKBOX,
'order': 103,
'default': True,
} }
]: ]:
self.addField(localGui, field) self.addField(localGui, field)
@ -106,7 +117,8 @@ class Notifiers(ModelHandler):
return { return {
'id': item.uuid, 'id': item.uuid,
'name': item.name, 'name': item.name,
'level': item.level, 'level': str(item.level),
'enabled': item.enabled,
'tags': [tag.tag for tag in item.tags.all()], 'tags': [tag.tag for tag in item.tags.all()],
'comments': item.comments, 'comments': item.comments,
'type': type_.type(), 'type': type_.type(),

View File

@ -37,7 +37,7 @@ import typing
from django.utils.translation import gettext from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from uds.core import consts, transports, types from uds.core import consts, transports, types, ui
from uds.core.environment import Environment from uds.core.environment import Environment
from uds.core.util import ensure, permissions from uds.core.util import ensure, permissions
from uds.models import Network, ServicePool, Transport from uds.models import Network, ServicePool, Transport
@ -100,17 +100,14 @@ class Transports(ModelHandler):
'name': 'allowed_oss', 'name': 'allowed_oss',
'value': [], 'value': [],
'choices': sorted( 'choices': sorted(
[ [ui.gui.choiceItem(x.name, x.name) for x in consts.os.KNOWN_OS_LIST],
{'id': x.name, 'text': x.name}
for x in consts.os.KNOWN_OS_LIST
],
key=lambda x: x['text'].lower(), key=lambda x: x['text'].lower(),
), ),
'label': gettext('Allowed Devices'), 'label': gettext('Allowed Devices'),
'tooltip': gettext( 'tooltip': gettext(
'If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed' 'If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'
), ),
'type': 'multichoice', 'type': types.ui.FieldType.MULTICHOICE,
'tab': types.ui.Tab.ADVANCED, 'tab': types.ui.Tab.ADVANCED,
'order': 102, 'order': 102,
}, },
@ -121,13 +118,15 @@ class Transports(ModelHandler):
'name': 'pools', 'name': 'pools',
'value': [], 'value': [],
'choices': [ 'choices': [
{'id': x.uuid, 'text': x.name} ui.gui.choiceItem(x.uuid, x.name)
for x in ServicePool.objects.filter(service__isnull=False).order_by('name').prefetch_related('service') for x in ServicePool.objects.filter(service__isnull=False)
if transportType.protocol in x.service.getType().allowedProtocols .order_by('name')
.prefetch_related('service')
if transportType.protocol in x.service.getType().allowedProtocols
], ],
'label': gettext('Service Pools'), 'label': gettext('Service Pools'),
'tooltip': gettext('Currently assigned services pools'), 'tooltip': gettext('Currently assigned services pools'),
'type': 'multichoice', 'type': types.ui.FieldType.MULTICHOICE,
'order': 103, 'order': 103,
}, },
) )
@ -138,10 +137,8 @@ class Transports(ModelHandler):
'length': 32, 'length': 32,
'value': '', 'value': '',
'label': gettext('Label'), 'label': gettext('Label'),
'tooltip': gettext( 'tooltip': gettext('Metapool transport label (only used on metapool transports grouping)'),
'Metapool transport label (only used on metapool transports grouping)' 'type': types.ui.FieldType.TEXT,
),
'type': 'text',
'order': 201, 'order': 201,
'tab': types.ui.Tab.ADVANCED, 'tab': types.ui.Tab.ADVANCED,
}, },
@ -152,7 +149,7 @@ class Transports(ModelHandler):
def item_as_dict(self, item: 'Model') -> typing.Dict[str, typing.Any]: def item_as_dict(self, item: 'Model') -> typing.Dict[str, typing.Any]:
item = ensure.is_instance(item, Transport) item = ensure.is_instance(item, Transport)
type_ = item.getType() type_ = item.getType()
pools = [{'id': x.uuid} for x in item.deployedServices.all()] pools = list(item.deployedServices.all().values_list('uuid', flat=True))
return { return {
'id': item.uuid, 'id': item.uuid,
'name': item.name, 'name': item.name,
@ -161,10 +158,8 @@ class Transports(ModelHandler):
'priority': item.priority, 'priority': item.priority,
'label': item.label, 'label': item.label,
'net_filtering': item.net_filtering, 'net_filtering': item.net_filtering,
'networks': [{'id': n.uuid} for n in item.networks.all()], 'networks': list(item.networks.all().values_list('uuid', flat=True)),
'allowed_oss': [{'id': x} for x in item.allowed_oss.split(',')] 'allowed_oss': [x for x in item.allowed_oss.split(',')] if item.allowed_oss != '' else [],
if item.allowed_oss != ''
else [],
'pools': pools, 'pools': pools,
'pools_count': len(pools), 'pools_count': len(pools),
'deployed_count': item.deployedServices.count(), 'deployed_count': item.deployedServices.count(),
@ -180,9 +175,7 @@ class Transports(ModelHandler):
fields['label'] = fields['label'].strip().replace(' ', '-') fields['label'] = fields['label'].strip().replace(' ', '-')
# And ensure small_name chars are valid [ a-zA-Z0-9:-]+ # And ensure small_name chars are valid [ a-zA-Z0-9:-]+
if fields['label'] and not re.match(r'^[a-zA-Z0-9:-]+$', fields['label']): if fields['label'] and not re.match(r'^[a-zA-Z0-9:-]+$', fields['label']):
raise self.invalidRequestException( raise self.invalidRequestException(gettext('Label must contain only letters, numbers, ":" and "-"'))
gettext('Label must contain only letters, numbers, ":" and "-"')
)
def afterSave(self, item: 'Model') -> None: def afterSave(self, item: 'Model') -> None:
item = ensure.is_instance(item, Transport) item = ensure.is_instance(item, Transport)

View File

@ -457,14 +457,15 @@ class ServerManager(metaclass=singleton.Singleton):
Returns: Returns:
List of servers sorted by usage List of servers sorted by usage
""" """
now = model_utils.getSqlDatetime() with transaction.atomic():
fltrs = serverGroup.servers.filter(maintenance_mode=False) now = model_utils.getSqlDatetime()
fltrs = fltrs.filter(Q(locked_until=None) | Q(locked_until__lte=now)) # Only unlocked servers fltrs = serverGroup.servers.filter(maintenance_mode=False)
if excludeServersUUids: fltrs = fltrs.filter(Q(locked_until=None) | Q(locked_until__lte=now)) # Only unlocked servers
fltrs = fltrs.exclude(uuid__in=excludeServersUUids) if excludeServersUUids:
fltrs = fltrs.exclude(uuid__in=excludeServersUUids)
# Get the stats for all servers, but in parallel
serverStats = self.getServerStats(fltrs) # Get the stats for all servers, but in parallel
serverStats = self.getServerStats(fltrs)
# Sort by weight, lower first (lower is better) # Sort by weight, lower first (lower is better)
return [s[1] for s in sorted(serverStats, key=lambda x: x[0].weight() if x[0] else 999999999)] return [s[1] for s in sorted(serverStats, key=lambda x: x[0].weight() if x[0] else 999999999)]

View File

@ -61,13 +61,13 @@ def _requestActor(
url = userService.getCommsUrl() url = userService.getCommsUrl()
if not url: if not url:
# logger.warning('No notification is made because agent does not supports notifications: %s', userService.friendly_name) # logger.warning('No notification is made because agent does not supports notifications: %s', userService.friendly_name)
raise exceptions.NoActorComms(f'No notification urls for {userService.friendly_name}') raise exceptions.actor.NoActorComms(f'No notification urls for {userService.friendly_name}')
minVersion = minVersion or '3.5.0' minVersion = minVersion or '3.5.0'
version = userService.properties.get('actor_version', '0.0.0') version = userService.properties.get('actor_version', '0.0.0')
if '-' in version or version < minVersion: if '-' in version or version < minVersion:
logger.warning('Pool %s has old actors (%s)', userService.deployed_service.name, version) logger.warning('Pool %s has old actors (%s)', userService.deployed_service.name, version)
raise exceptions.OldActorVersion( raise exceptions.actor.OldActorVersion(
f'Old actor version {version} for {userService.friendly_name}'.format( f'Old actor version {version} for {userService.friendly_name}'.format(
version, userService.friendly_name version, userService.friendly_name
) )
@ -155,7 +155,7 @@ def checkUuid(userService: 'UserService') -> bool:
uuid, uuid,
) )
return False return False
except exceptions.NoActorComms: except exceptions.actor.NoActorComms:
pass pass
return True # Actor does not supports checking return True # Actor does not supports checking
@ -172,7 +172,7 @@ def requestScreenshot(userService: 'UserService') -> bytes:
png = _requestActor( png = _requestActor(
userService, 'screenshot', minVersion='3.0.0' userService, 'screenshot', minVersion='3.0.0'
) # First valid version with screenshot is 3.0 ) # First valid version with screenshot is 3.0
except exceptions.NoActorComms: except exceptions.actor.NoActorComms:
png = None png = None
return base64.b64decode(png or emptyPng) return base64.b64decode(png or emptyPng)
@ -187,7 +187,7 @@ def sendScript(userService: 'UserService', script: str, forUser: bool = False) -
if forUser: if forUser:
data['user'] = forUser data['user'] = forUser
_requestActor(userService, 'script', data=data) _requestActor(userService, 'script', data=data)
except exceptions.NoActorComms: except exceptions.actor.NoActorComms:
pass pass
@ -197,7 +197,7 @@ def requestLogoff(userService: 'UserService') -> None:
""" """
try: try:
_requestActor(userService, 'logout', data={}) _requestActor(userService, 'logout', data={})
except exceptions.NoActorComms: except exceptions.actor.NoActorComms:
pass pass
@ -207,5 +207,5 @@ def sendMessage(userService: 'UserService', message: str) -> None:
""" """
try: try:
_requestActor(userService, 'message', data={'message': message}) _requestActor(userService, 'message', data={'message': message})
except exceptions.NoActorComms: except exceptions.actor.NoActorComms:
pass pass

View File

@ -69,7 +69,7 @@ class MessageProcessorThread(BaseThread):
or time.time() - self._cached_stamp > CACHE_TIMEOUT or time.time() - self._cached_stamp > CACHE_TIMEOUT
): ):
self._cached_providers = [ self._cached_providers = [
(p.level, p.getInstance()) for p in Notifier.objects.all() (p.level, p.getInstance()) for p in Notifier.objects.filter(enabled=True)
] ]
self._cached_stamp = time.time() self._cached_stamp = time.time()
return self._cached_providers return self._cached_providers

View File

@ -73,7 +73,7 @@ class Cache:
] = _basic_deserialize ] = _basic_deserialize
def __init__(self, owner: typing.Union[str, bytes]): def __init__(self, owner: typing.Union[str, bytes]):
self._owner = owner.decode('utf-8') if isinstance(owner, bytes) else owner self._owner = typing.cast(str, owner.decode('utf-8') if isinstance(owner, bytes) else owner)
self._bowner = self._owner.encode('utf8') self._bowner = self._owner.encode('utf8')
def __getKey(self, key: typing.Union[str, bytes]) -> str: def __getKey(self, key: typing.Union[str, bytes]) -> str:

View File

@ -45,7 +45,7 @@ _saveLater: typing.List[typing.Tuple['Config.Value', typing.Any]] = []
_getLater: typing.List['Config.Value'] = [] _getLater: typing.List['Config.Value'] = []
# For custom params (for choices mainly) # For custom params (for choices mainly)
_configParams = {} _configParams: typing.Dict[str, typing.Any] = {}
# Pair of section/value removed from current UDS version # Pair of section/value removed from current UDS version
# Note: As of version 4.0, all previous REMOVED values has been moved to migration script 0043 # Note: As of version 4.0, all previous REMOVED values has been moved to migration script 0043

View File

@ -56,6 +56,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
Sample of transports are RDP, Spice, Web file uploader, etc... Sample of transports are RDP, Spice, Web file uploader, etc...
""" """
# Constants for net_filter # Constants for net_filter
NO_FILTERING = 'n' NO_FILTERING = 'n'
ALLOW = 'a' ALLOW = 'a'
@ -89,9 +90,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
ordering = ('name',) ordering = ('name',)
app_label = 'uds' app_label = 'uds'
def getInstance( def getInstance(self, values: typing.Optional[typing.Dict[str, str]] = None) -> 'transports.Transport':
self, values: typing.Optional[typing.Dict[str, str]] = None
) -> 'transports.Transport':
return typing.cast('transports.Transport', super().getInstance(values=values)) return typing.cast('transports.Transport', super().getInstance(values=values))
def getType(self) -> typing.Type['transports.Transport']: def getType(self) -> typing.Type['transports.Transport']:
@ -127,11 +126,16 @@ class Transport(ManagedObjectModel, TaggingMixin):
:note: Ip addresses has been only tested with IPv4 addresses :note: Ip addresses has been only tested with IPv4 addresses
""" """
# Avoid circular import
from uds.models import Network # pylint: disable=import-outside-toplevel
if self.net_filtering == Transport.NO_FILTERING: if self.net_filtering == Transport.NO_FILTERING:
return True return True
ip, version = net.ipToLong(ipStr) ip, version = net.ipToLong(ipStr)
# Allow # Allow
exists = self.networks.filter(start__lte=Network.hexlify(ip), end__gte=Network.hexlify(ip), version=version).exists() exists = self.networks.filter(
start__lte=Network.hexlify(ip), end__gte=Network.hexlify(ip), version=version
).exists()
if self.net_filtering == Transport.ALLOW: if self.net_filtering == Transport.ALLOW:
return exists return exists
# Deny, must not be in any network # Deny, must not be in any network

File diff suppressed because one or more lines are too long

View File

@ -102,6 +102,6 @@
</svg> </svg>
</div> </div>
</uds-root> </uds-root>
<script src="/uds/res/admin/runtime.js?stamp=1699891841" type="module"></script><script src="/uds/res/admin/polyfills.js?stamp=1699891841" type="module"></script><script src="/uds/res/admin/main.js?stamp=1699891841" type="module"></script></body> <script src="/uds/res/admin/runtime.js?stamp=1700178945" type="module"></script><script src="/uds/res/admin/polyfills.js?stamp=1700178945" type="module"></script><script src="/uds/res/admin/main.js?stamp=1700178945" type="module"></script></body>
</html> </html>

View File

@ -1 +1 @@
hPF/H21BzZ0VU9HjimiOa1go9TJVsqmKsgGqB4V4X3cjB6G3NkSa1O45ub3gf+gOriElibPRbXzet4zma4qnBACLzAZQjmmxDRK9gC7eN6p0z0TKg18U6/hKf5gs6ICjQZyONg2gvBBrYUz7JhYoefq9SZRAna7373N0minKoJoBPLB+ylkemBNhKcsN5bRQlEGU03mLREGk/h642qN6ebQhIzY+JMo3c9CwtRS6SCiLhiaYkPFxdEX9e7AGSpTgGSFh4+Mc3QEge4sOquWszX4ocJJc23SHl5GdZSfhn3Bst5lLKILVUT5w7zaZOqa/xx/HjpCmxROJKm/bkR+HK8VMRh4N5c5yvavXid0IwgN8Uc+SOIUh4+wxbOyJI3ySS/77gUI/1TDw+r/gRkSUPwcRSFKuyQMN2yR6yr2BgOXlGmlNwZ/MzsDIIwgGeMlkKZZzLI64aj9VG2QsWHrlw2HWuFfBGGIX4T49p0tvdRm5o1jg/cdsLsHC8of5Vn4wgwyZwlScndDLcBJq76v4wnWUMg4IQpeOoI/PEbgeUfZDuntSt/ZT5icB78nN07hUo56d5Z5q1ktuWEHJSWCVSg59KGOcvaaPub50+anm6Uzac5rynZ0/gqA8Y0IV3dgRalBMZCiCy89lHW1YyO52A4DBka6hG4gKt5VUs+eT+vI= mzEKyhRHnv5zWHZvuCfZrW6pq0V9NNTVfLrLmuP649dw5+Llpl80QL6F84vzaCuiTGebBrObT9cTO+JKi3gIlmgSfLVHSkOFaLOfX/IVzsQclcP7zn5B6dYwUPgBhrMN1CyvHP0hqvjXQkVgLxI3OFR/wSZ7VllyFBAnD4/EawUa2CIXRTnnCUBr4K5YFiV3esQu8sOCVYYMONwk4FAJUdt1UDfjGKQo15x9Y8S96tuBpVwQOGvF+ioEndQTUSC1GBlmPT6IgffJhI6Tm0xOji8QIdvUcJ/8ipK7qaWFplcJ7Sc/uKSgvcM7P2r6D45TmqbmGYhQgdMnQd7HmRaDi25gEnFckTCAzdEHiy8iibMATs0zqGS07h85vtlkllsi2xFF12ZcRR5AAIjSKmo5CDApjdQegVcHJgwYV8XjZRDyc2kBWvywbN7zob/rDuF5ncvFLwDDLFV6EZ1a15dEP/L6rR2NI1lGDdAqWwQmm0c28dfM3jv3GvyGOwTqJjmXgUrlSIBpM6EkdRMz8yIzdhJAhUxrwxVMi6qi+pWkWbtM9BXqgBgLqfaF5c8cGPup2uUvwvarexgrON28zsqwVvIHo2dqrrRWzjIrZzZpXAvteVLw9SFRlTVi3ilqHF7Zs9pQ7lp/D83SuI7+CWDu4co+3PX2Y9HYT2JfrlYnEjY=