mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
Done basic server events REST methods
This commit is contained in:
parent
e96369bd71
commit
d9b7771f21
@ -64,6 +64,15 @@ class ServerEventsLoginLogoutTest(rest.test.RESTTestCase):
|
||||
# 'user_service': 'uuid', # MUST BE PRESENT
|
||||
# 'username': 'username', # Optional
|
||||
# }
|
||||
# Returns:
|
||||
#
|
||||
# {
|
||||
# 'ip': src.ip,
|
||||
# 'hostname': src.hostname,
|
||||
# 'dead_line': deadLine,
|
||||
# 'max_idle': maxIdle,
|
||||
# 'session_id': session_id,
|
||||
# }
|
||||
response = self.client.rest_post(
|
||||
'/servers/event',
|
||||
data={
|
||||
@ -76,6 +85,14 @@ class ServerEventsLoginLogoutTest(rest.test.RESTTestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.user_service_managed.refresh_from_db()
|
||||
self.assertEqual(self.user_service_managed.in_use, True)
|
||||
result = response.json()['result']
|
||||
self.assertEqual(self.user_service_managed.src_ip, result['ip'])
|
||||
self.assertEqual(self.user_service_managed.src_hostname, result['hostname'])
|
||||
session = self.user_service_managed.sessions.first()
|
||||
if session is None:
|
||||
self.fail('Session not found')
|
||||
self.assertEqual(session.session_id, result['session_id'])
|
||||
self.assertEqual(self.user_service_managed.properties.get('last_username', ''), 'local_user_name')
|
||||
|
||||
# TODO: Finish this test
|
||||
|
||||
@ -102,7 +119,6 @@ class ServerEventsLoginLogoutTest(rest.test.RESTTestCase):
|
||||
# 'user_service': 'uuid', # MUST BE PRESENT
|
||||
# 'username': 'username', # Optional
|
||||
# }
|
||||
|
||||
response = self.client.rest_post(
|
||||
'/servers/event',
|
||||
data={
|
||||
@ -110,6 +126,7 @@ class ServerEventsLoginLogoutTest(rest.test.RESTTestCase):
|
||||
'type': 'logout',
|
||||
'user_service': self.user_service_managed.uuid,
|
||||
'username': 'local_user_name',
|
||||
'session_id': '',
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@ -129,3 +146,48 @@ class ServerEventsLoginLogoutTest(rest.test.RESTTestCase):
|
||||
self.assertIsNotNone(response.content)
|
||||
self.assertIsNotNone(response.json())
|
||||
self.assertIn('error', response.json())
|
||||
|
||||
# No session id, shouls return error
|
||||
response = self.client.rest_post(
|
||||
'/servers/event',
|
||||
data={
|
||||
'token': self.server.token,
|
||||
'type': 'logout',
|
||||
'user_service': self.user_service_managed.uuid,
|
||||
'username': 'local_user_name',
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNotNone(response.content)
|
||||
self.assertIsNotNone(response.json())
|
||||
self.assertIn('error', response.json())
|
||||
|
||||
def test_loging_logout(self) -> None:
|
||||
response = self.client.rest_post(
|
||||
'/servers/event',
|
||||
data={
|
||||
'token': self.server.token,
|
||||
'type': 'login',
|
||||
'user_service': self.user_service_managed.uuid,
|
||||
'username': 'local_user_name',
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
session_id = response.json()['result']['session_id']
|
||||
self.assertIsNotNone(session_id)
|
||||
self.user_service_managed.refresh_from_db()
|
||||
self.assertEqual(self.user_service_managed.in_use, True)
|
||||
|
||||
response = self.client.rest_post(
|
||||
'/servers/event',
|
||||
data={
|
||||
'token': self.server.token,
|
||||
'type': 'logout',
|
||||
'user_service': self.user_service_managed.uuid,
|
||||
'username': 'local_user_name',
|
||||
'session_id': session_id,
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.user_service_managed.refresh_from_db()
|
||||
self.assertEqual(self.user_service_managed.in_use, False)
|
||||
|
@ -33,8 +33,9 @@ import random
|
||||
import typing
|
||||
from unittest import mock
|
||||
|
||||
from uds.core import types
|
||||
from uds.core import types, consts
|
||||
from uds.core.util import log
|
||||
from uds.core.util.model import getSqlStamp
|
||||
|
||||
from ...fixtures import servers as servers_fixtures
|
||||
from ...utils import random_ip_v4, random_ip_v6, random_mac, rest
|
||||
@ -107,8 +108,17 @@ class ServerEventsPingTest(rest.test.RESTTestCase):
|
||||
|
||||
server_stats = self.server.properties.get('stats', None)
|
||||
self.assertIsNotNone(server_stats)
|
||||
statsResponse = types.servers.ServerStatsType.fromDict(server_stats)
|
||||
# Get stats, but clear stamp
|
||||
statsResponse = types.servers.ServerStatsType.fromDict(server_stats, stamp=0)
|
||||
self.assertEqual(statsResponse, stats)
|
||||
# Ensure that stamp is not 0 on server_stats dict
|
||||
self.assertNotEqual(server_stats['stamp'], 0)
|
||||
|
||||
# Ensure stat is valid right now
|
||||
statsResponse = types.servers.ServerStatsType.fromDict(server_stats)
|
||||
self.assertTrue(statsResponse.is_valid)
|
||||
statsResponse = types.servers.ServerStatsType.fromDict(server_stats, stamp=getSqlStamp() - consts.DEFAULT_CACHE_TIMEOUT - 1)
|
||||
self.assertFalse(statsResponse.is_valid)
|
||||
|
||||
def test_event_ping_without_stats(self) -> None:
|
||||
# Create an stat object
|
||||
|
@ -203,7 +203,7 @@ class Client(Handler):
|
||||
# ensures that we mark the service as accessed by client
|
||||
# so web interface can show can react to this
|
||||
if userService:
|
||||
userService.properties['accessedByClient'] = True
|
||||
userService.properties['accessed_by_client'] = True
|
||||
|
||||
def get(self) -> typing.Dict[str, typing.Any]:
|
||||
"""
|
||||
|
@ -163,7 +163,7 @@ class ServersServers(DetailHandler):
|
||||
return {'field': 'maintenance_mode', 'prefix': 'row-maintenance-'}
|
||||
|
||||
def getGui(self, parent: 'models.ServerGroup', forType: str = '') -> typing.List[typing.Any]:
|
||||
kind, subkind = parent.serverType, parent.subtype
|
||||
kind, subkind = parent.server_type, parent.subtype
|
||||
title = _('of type') + f' {subkind.upper()} {kind.name.capitalize()}'
|
||||
if kind == types.servers.ServerType.UNMANAGED:
|
||||
return self.addField(
|
||||
@ -301,7 +301,7 @@ class ServersServers(DetailHandler):
|
||||
def deleteItem(self, parent: 'models.ServerGroup', item: str) -> None:
|
||||
try:
|
||||
server = models.Server.objects.get(uuid=processUuid(item))
|
||||
if parent.serverType == types.servers.ServerType.UNMANAGED:
|
||||
if parent.server_type == types.servers.ServerType.UNMANAGED:
|
||||
parent.servers.remove(server) # Remove reference
|
||||
server.delete() # and delete server
|
||||
else:
|
||||
|
@ -90,4 +90,9 @@ TRUE_STR: typing.Final[str] = 'true'
|
||||
FALSE_STR: typing.Final[str] = 'false'
|
||||
|
||||
# Default length for Gui Text Fields
|
||||
DEFAULT_TEXT_LENGTH: typing.Final[int] = 64
|
||||
DEFAULT_TEXT_LENGTH: typing.Final[int] = 64
|
||||
|
||||
# Default timeouts, in seconds
|
||||
DEFAULT_CACHE_TIMEOUT: typing.Final[int] = 60 * 3 # 3 minutes
|
||||
LONG_CACHE_TIMEOUT: typing.Final[int] = DEFAULT_CACHE_TIMEOUT * 20 # 1 hour
|
||||
SMALL_CACHE_TIMEOUT: typing.Final[int] = DEFAULT_CACHE_TIMEOUT // 3 # 1 minute
|
||||
|
@ -31,12 +31,11 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from uds.core.util.model import getSqlDatetime
|
||||
from uds.core import types, consts
|
||||
|
||||
from uds.REST.utils import rest_result
|
||||
from uds import models
|
||||
from uds.core import consts, osmanagers, types
|
||||
from uds.core.util import log
|
||||
from uds.core.util.model import getSqlDatetime, getSqlStamp
|
||||
from uds.REST.utils import rest_result
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -55,15 +54,49 @@ def process_log(data: typing.Dict[str, typing.Any]) -> typing.Any:
|
||||
|
||||
|
||||
def process_login(data: typing.Dict[str, typing.Any]) -> typing.Any:
|
||||
server = models.Server.objects.get(token=data['token'])
|
||||
userService = models.UserService.objects.get(uuid=data['user_service'])
|
||||
userService.setInUse(True)
|
||||
server.setActorVersion(userService)
|
||||
|
||||
return rest_result(consts.OK)
|
||||
if not userService.in_use: # If already logged in, do not add a second login (windows does this i.e.)
|
||||
osmanagers.OSManager.loggedIn(userService, data['username'])
|
||||
|
||||
# Get the source of the connection and a new session id
|
||||
src = userService.getConnectionSource()
|
||||
session_id = userService.initSession() # creates a session for every login requested
|
||||
|
||||
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
|
||||
maxIdle = osManager.maxIdle() if osManager else None
|
||||
|
||||
logger.debug('Max idle: %s', maxIdle)
|
||||
|
||||
deadLine = deadLine = (
|
||||
userService.deployed_service.getDeadline() if not osManager or osManager.ignoreDeadLine() else None
|
||||
)
|
||||
|
||||
return rest_result(
|
||||
{
|
||||
'ip': src.ip,
|
||||
'hostname': src.hostname,
|
||||
'dead_line': deadLine,
|
||||
'max_idle': maxIdle,
|
||||
'session_id': session_id,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def process_logout(data: typing.Dict[str, typing.Any]) -> typing.Any:
|
||||
userService = models.UserService.objects.get(uuid=data['user_service'])
|
||||
userService.setInUse(False)
|
||||
|
||||
session_id = data['session_id']
|
||||
userService.closeSession(session_id)
|
||||
|
||||
if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
|
||||
osmanagers.OSManager.loggedOut(userService, data['username'])
|
||||
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
|
||||
if not osManager or osManager.isRemovableOnLogout(userService):
|
||||
logger.debug('Removable on logout: %s', osManager)
|
||||
userService.remove()
|
||||
|
||||
return rest_result(consts.OK)
|
||||
|
||||
@ -71,11 +104,9 @@ def process_logout(data: typing.Dict[str, typing.Any]) -> typing.Any:
|
||||
def process_ping(data: typing.Dict[str, typing.Any]) -> typing.Any:
|
||||
server = models.Server.objects.get(token=data['token'])
|
||||
if 'stats' in data:
|
||||
# Load anc check stats
|
||||
stats = types.servers.ServerStatsType.fromDict(data['stats'])
|
||||
server.stats = types.servers.ServerStatsType.fromDict(data['stats'])
|
||||
# Set stats on server
|
||||
server.properties['stats'] = stats.asDict()
|
||||
server.properties['last_ping'] = getSqlDatetime()
|
||||
server.last_ping = getSqlDatetime()
|
||||
|
||||
return rest_result(consts.OK)
|
||||
|
||||
@ -103,7 +134,7 @@ def process(data: typing.Dict[str, typing.Any]) -> typing.Any:
|
||||
return rest_result('error', error=f'Invalid event type {data.get("type", "not_found")}')
|
||||
|
||||
try:
|
||||
fnc(data)
|
||||
return fnc(data)
|
||||
except Exception as e:
|
||||
logger.error('Exception processing event %s: %s', data, e)
|
||||
return rest_result('error', error=str(e))
|
||||
|
@ -221,7 +221,7 @@ class OSManager(Module):
|
||||
'''
|
||||
Resets login counter to 0
|
||||
'''
|
||||
userService.properties['loginsCounter'] = 0
|
||||
userService.properties['logins_counter'] = 0
|
||||
# And execute ready notification method
|
||||
self.readyNotified(userService)
|
||||
|
||||
@ -235,6 +235,7 @@ class OSManager(Module):
|
||||
"""
|
||||
uniqueId = userService.unique_id
|
||||
userService.setInUse(True)
|
||||
userService.properties['last_username'] = userName or 'unknown' # Store it for convenience
|
||||
userServiceInstance = userService.getInstance()
|
||||
userServiceInstance.userLoggedIn(userName or 'unknown')
|
||||
userService.updateData(userServiceInstance)
|
||||
@ -277,8 +278,8 @@ class OSManager(Module):
|
||||
|
||||
# Context makes a transaction, so we can use it to update the counter
|
||||
with userService.properties as p:
|
||||
counter = int(typing.cast(str, p.get('loginsCounter', 0))) + 1
|
||||
p['loginsCounter'] = counter
|
||||
counter = int(typing.cast(str, p.get('logins_counter', 0))) + 1
|
||||
p['logins_counter'] = counter
|
||||
|
||||
@staticmethod
|
||||
def loggedOut(userService: 'UserService', userName: typing.Optional[str] = None) -> None:
|
||||
@ -289,10 +290,10 @@ class OSManager(Module):
|
||||
- Invokes userLoggedIn for user service instance
|
||||
"""
|
||||
with userService.properties as p:
|
||||
counter = int(typing.cast(str, p.get('loginsCounter', 0))) - 1
|
||||
counter = int(typing.cast(str, p.get('logins_counter', 0))) - 1
|
||||
if counter > 0:
|
||||
counter -= 1
|
||||
p['loginsCounter'] = counter
|
||||
p['logins_counter'] = counter
|
||||
|
||||
if GlobalConfig.EXCLUSIVE_LOGOUT.getBool(True) and counter > 0:
|
||||
return
|
||||
|
@ -30,12 +30,12 @@
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import enum
|
||||
import time
|
||||
import datetime
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from uds.core.consts import images
|
||||
from uds.core import consts
|
||||
from uds.core.util import singleton
|
||||
from uds.core.util.model import getSqlStamp
|
||||
|
||||
@ -110,7 +110,7 @@ class ServerSubType(metaclass=singleton.Singleton):
|
||||
# I.e. "linuxapp" will be registered by the Linux Applications Provider
|
||||
# The main usage of this subtypes is to allow to group servers by type, and to allow to filter by type
|
||||
ServerSubType.manager().register(
|
||||
ServerType.UNMANAGED, 'ip', 'Unmanaged IP Server', images.DEFAULT_IMAGE_BASE64, False
|
||||
ServerType.UNMANAGED, 'ip', 'Unmanaged IP Server', consts.images.DEFAULT_IMAGE_BASE64, False
|
||||
)
|
||||
|
||||
|
||||
@ -131,6 +131,16 @@ class ServerStatsType(typing.NamedTuple):
|
||||
@property
|
||||
def memfree_ratio(self) -> float:
|
||||
return (self.memtotal - self.memused) / (self.memtotal or 1) / (self.current_users + 1)
|
||||
|
||||
@property
|
||||
def is_valid( self ) -> bool:
|
||||
"""If the stamp is lesss than consts.DEFAULT_CACHE_TIMEOUT, it is considered valid
|
||||
|
||||
Returns:
|
||||
bool: True if valid, False otherwise
|
||||
"""
|
||||
return self.stamp > getSqlStamp() - consts.DEFAULT_CACHE_TIMEOUT
|
||||
|
||||
|
||||
def weight(self, minMemory: int = 0) -> float:
|
||||
# Weights are calculated as:
|
||||
@ -145,7 +155,9 @@ class ServerStatsType(typing.NamedTuple):
|
||||
return 1 / ((self.cpufree_ratio * 1.3 + self.memfree_ratio) or 1)
|
||||
|
||||
@staticmethod
|
||||
def fromDict(dct: typing.Dict[str, typing.Any]) -> 'ServerStatsType':
|
||||
def fromDict(data: typing.Mapping[str, typing.Any], **kwargs: typing.Any) -> 'ServerStatsType':
|
||||
dct = { k:v for k, v in data.items()} # Make a copy
|
||||
dct.update(kwargs) # and update with kwargs
|
||||
disks: typing.List[typing.Tuple[str, int, int]] = []
|
||||
for disk in dct.get('disks', []):
|
||||
disks.append((disk['name'], disk['used'], disk['total']))
|
||||
|
@ -656,7 +656,7 @@ class gui:
|
||||
|
||||
def _setValue(self, value: typing.Any):
|
||||
# Internally stores an string
|
||||
super()._setValue(str(value))
|
||||
super()._setValue(value)
|
||||
|
||||
def num(self) -> int:
|
||||
"""
|
||||
|
@ -28,25 +28,26 @@
|
||||
'''
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
import typing
|
||||
import datetime
|
||||
import secrets
|
||||
import typing
|
||||
|
||||
from django.db import models
|
||||
|
||||
from uds.core import types
|
||||
from uds.core.util.os_detector import KnownOS
|
||||
from uds.core import consts, types
|
||||
from uds.core.consts import MAC_UNKNOWN, MAX_DNS_NAME_LENGTH, MAX_IPV6_LENGTH, SERVER_DEFAULT_LISTEN_PORT
|
||||
from uds.core.types.request import ExtendedHttpRequest
|
||||
from uds.core.util import properties, log, resolver, net
|
||||
from uds.core.util import log, net, properties, resolver
|
||||
from uds.core.util.model import getSqlStamp
|
||||
from uds.core.util.os_detector import KnownOS
|
||||
|
||||
from uds.core.consts import MAX_DNS_NAME_LENGTH, MAX_IPV6_LENGTH, MAC_UNKNOWN, SERVER_DEFAULT_LISTEN_PORT
|
||||
|
||||
from .uuid_model import UUIDModel
|
||||
from .tag import TaggingMixin
|
||||
|
||||
from .uuid_model import UUIDModel
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models.transport import Transport
|
||||
from uds.models.user import User
|
||||
from uds.models.user_service import UserService
|
||||
|
||||
|
||||
class ServerGroup(UUIDModel, TaggingMixin, properties.PropertiesMixin):
|
||||
@ -93,13 +94,19 @@ class ServerGroup(UUIDModel, TaggingMixin, properties.PropertiesMixin):
|
||||
if self.port == 0:
|
||||
return self.host
|
||||
return f'{self.host}:{self.port}'
|
||||
|
||||
|
||||
@property
|
||||
def serverType(self) -> types.servers.ServerType:
|
||||
def server_type(self) -> types.servers.ServerType:
|
||||
"""Returns the server type of this server"""
|
||||
try:
|
||||
return types.servers.ServerType(self.type)
|
||||
except ValueError:
|
||||
return types.servers.ServerType.UNMANAGED # Invalid value, return default
|
||||
return types.servers.ServerType.UNMANAGED
|
||||
|
||||
@server_type.setter
|
||||
def server_type(self, value: types.servers.ServerType) -> None:
|
||||
"""Sets the server type of this server"""
|
||||
self.type = value
|
||||
|
||||
def https_url(self, path: str) -> str:
|
||||
if not path.startswith('/'):
|
||||
@ -200,42 +207,12 @@ class Server(UUIDModel, TaggingMixin, properties.PropertiesMixin):
|
||||
return self.uuid, 'server'
|
||||
|
||||
@property
|
||||
def serverType(self) -> types.servers.ServerType:
|
||||
def server_type(self) -> types.servers.ServerType:
|
||||
"""Returns the server type of this server"""
|
||||
try:
|
||||
return types.servers.ServerType(self.type)
|
||||
except ValueError:
|
||||
return types.servers.ServerType.UNMANAGED # Invalid value, return default
|
||||
|
||||
@staticmethod
|
||||
def create_token() -> str:
|
||||
return create_token() # Return global function
|
||||
|
||||
@staticmethod
|
||||
def validateToken(
|
||||
token: str,
|
||||
serverType: typing.Union[typing.Iterable[types.servers.ServerType], types.servers.ServerType],
|
||||
request: typing.Optional[ExtendedHttpRequest] = None,
|
||||
) -> bool:
|
||||
# Ensure token is valid
|
||||
try:
|
||||
if isinstance(serverType, types.servers.ServerType):
|
||||
tt = Server.objects.get(token=token, type=serverType.value)
|
||||
else:
|
||||
tt = Server.objects.get(token=token, type__in=[st.value for st in serverType])
|
||||
# We could check the request ip here
|
||||
if request and request.ip != tt.ip:
|
||||
raise Exception('Invalid ip')
|
||||
return True
|
||||
except Server.DoesNotExist:
|
||||
pass
|
||||
except Server.MultipleObjectsReturned:
|
||||
raise Exception('Multiple objects returned for token')
|
||||
return False
|
||||
|
||||
@property
|
||||
def server_type(self) -> types.servers.ServerType:
|
||||
"""Returns the server type of this server"""
|
||||
return types.servers.ServerType(self.type)
|
||||
return types.servers.ServerType.UNMANAGED
|
||||
|
||||
@server_type.setter
|
||||
def server_type(self, value: types.servers.ServerType) -> None:
|
||||
@ -245,7 +222,7 @@ class Server(UUIDModel, TaggingMixin, properties.PropertiesMixin):
|
||||
@property
|
||||
def host(self) -> str:
|
||||
"""Returns the host of this server
|
||||
|
||||
|
||||
Host returns first the IP if it exists, and if not, the hostname (resolved)
|
||||
"""
|
||||
# If hostname exists, try first to resolve it
|
||||
@ -262,6 +239,76 @@ class Server(UUIDModel, TaggingMixin, properties.PropertiesMixin):
|
||||
"""Returns the ip version of this server"""
|
||||
return 6 if ':' in self.ip else 4
|
||||
|
||||
@property
|
||||
def stats(self) -> typing.Optional[types.servers.ServerStatsType]:
|
||||
"""Returns the current stats of this server, or None if not available"""
|
||||
statsDct = self.properties.get('stats', None)
|
||||
if statsDct:
|
||||
stats = types.servers.ServerStatsType.fromDict(statsDct)
|
||||
if stats.is_valid:
|
||||
return stats
|
||||
return None
|
||||
|
||||
@stats.setter
|
||||
def stats(self, value: typing.Optional[types.servers.ServerStatsType]) -> None:
|
||||
"""Sets the current stats of this server"""
|
||||
if value is None:
|
||||
del self.properties['stats']
|
||||
else:
|
||||
# Set stamp to current time and save it
|
||||
statsDict = value.asDict()
|
||||
statsDict['stamp'] = getSqlStamp()
|
||||
self.properties['stats'] = statsDict
|
||||
|
||||
@property
|
||||
def last_ping(self) -> datetime.datetime:
|
||||
"""Returns the last ping of this server"""
|
||||
return self.properties.get('last_ping', consts.NEVER)
|
||||
|
||||
@last_ping.setter
|
||||
def last_ping(self, value: datetime.datetime) -> None:
|
||||
"""Sets the last ping of this server"""
|
||||
self.properties['last_ping'] = value
|
||||
|
||||
@staticmethod
|
||||
def create_token() -> str:
|
||||
return create_token() # Return global function
|
||||
|
||||
@staticmethod
|
||||
def validateToken(
|
||||
token: str,
|
||||
serverType: typing.Union[typing.Iterable[types.servers.ServerType], types.servers.ServerType],
|
||||
request: typing.Optional[ExtendedHttpRequest] = None,
|
||||
) -> bool:
|
||||
"""Ensures that a token is valid for a server type
|
||||
|
||||
Args:
|
||||
token: Token to validate
|
||||
serverType: Server type to validate token for
|
||||
request: Optional request to check ip against token ip
|
||||
|
||||
Returns:
|
||||
True if token is valid for server type, False otherwise
|
||||
|
||||
Note:
|
||||
This allows to keep Tunnels, Servers, Actors.. etc on same table, and validate tokens for each kind
|
||||
"""
|
||||
# Ensure token is valid for a kind
|
||||
try:
|
||||
if isinstance(serverType, types.servers.ServerType):
|
||||
tt = Server.objects.get(token=token, type=serverType.value)
|
||||
else:
|
||||
tt = Server.objects.get(token=token, type__in=[st.value for st in serverType])
|
||||
# We could check the request ip here
|
||||
if request and request.ip != tt.ip:
|
||||
raise Exception('Invalid ip')
|
||||
return True
|
||||
except Server.DoesNotExist:
|
||||
pass
|
||||
except Server.MultipleObjectsReturned:
|
||||
raise Exception('Multiple objects returned for token')
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def search(ip_or_host: str) -> typing.Optional['Server']:
|
||||
"""Locates a server by ip or hostname
|
||||
@ -283,6 +330,10 @@ class Server(UUIDModel, TaggingMixin, properties.PropertiesMixin):
|
||||
found = Server.objects.filter(hostname=ip_or_host).first()
|
||||
return found
|
||||
|
||||
def setActorVersion(self, userService: 'UserService') -> None:
|
||||
"""Sets the actor version of this server to the userService"""
|
||||
userService.setActorVersion(f'Server {self.version or "unknown"}')
|
||||
|
||||
def getCommsUrl(self, *, path: typing.Optional[str] = None) -> typing.Optional[str]:
|
||||
"""
|
||||
Returns the url for a path to this server
|
||||
|
@ -419,7 +419,7 @@ def enableService(
|
||||
|
||||
userService, trans = res[1], res[3]
|
||||
|
||||
userService.properties['accessedByClient'] = False # Reset accesed property to
|
||||
userService.properties['accessed_by_client'] = False # Reset accesed property to
|
||||
|
||||
typeTrans = trans.getType()
|
||||
|
||||
|
@ -180,7 +180,7 @@ def userServiceStatus(
|
||||
ip = False
|
||||
|
||||
ready = 'ready'
|
||||
if userService.properties.get('accessedByClient', False) is True:
|
||||
if userService.properties.get('accessed_by_client', False) is True:
|
||||
ready = 'accessed'
|
||||
|
||||
status = 'running' if ip is None else 'error' if ip is False else ready
|
||||
|
Loading…
Reference in New Issue
Block a user