mirror of
https://github.com/dkmstr/openuds.git
synced 2025-03-20 06:50:23 +03:00
Formating & minor typing fixes
This commit is contained in:
parent
8c4b84e7db
commit
03bfb3efbb
@ -47,12 +47,17 @@ class Environment:
|
||||
not stored with main module data.
|
||||
The environment is composed of a "cache" and a "storage". First are volatile data, while second are persistent data.
|
||||
"""
|
||||
|
||||
_key: str
|
||||
_cache: Cache
|
||||
_storage: Storage
|
||||
_idGenerators: typing.Dict[str, UniqueIDGenerator]
|
||||
|
||||
def __init__(self, uniqueKey: str, idGenerators: typing.Optional[typing.Dict[str, UniqueIDGenerator]] = None):
|
||||
def __init__(
|
||||
self,
|
||||
uniqueKey: str,
|
||||
idGenerators: typing.Optional[typing.Dict[str, UniqueIDGenerator]] = None,
|
||||
):
|
||||
"""
|
||||
Initialized the Environment for the specified id
|
||||
@param uniqueKey: Key for this environment
|
||||
@ -112,7 +117,11 @@ class Environment:
|
||||
v.release()
|
||||
|
||||
@staticmethod
|
||||
def getEnvForTableElement(tblName, id_, idGeneratorsTypes: typing.Optional[typing.Dict[str, typing.Any]] = None) -> 'Environment':
|
||||
def getEnvForTableElement(
|
||||
tblName,
|
||||
id_,
|
||||
idGeneratorsTypes: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
||||
) -> 'Environment':
|
||||
"""
|
||||
From a table name, and a id, tries to load the associated environment or creates a new
|
||||
one if no environment exists at database. The table name and the id are used to obtain the key
|
||||
@ -155,7 +164,9 @@ class Environment:
|
||||
"""
|
||||
Provides global environment
|
||||
"""
|
||||
return Environment(GLOBAL_ENV) # This environment is a global environment for general utility.
|
||||
return Environment(
|
||||
GLOBAL_ENV
|
||||
) # This environment is a global environment for general utility.
|
||||
|
||||
|
||||
class Environmentable:
|
||||
|
@ -97,8 +97,11 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
Environmentable is a base class that provides utility method to access a separate Environment for every single
|
||||
module.
|
||||
"""
|
||||
|
||||
# Types
|
||||
ValuesType = typing.Optional[typing.Dict[str, typing.Any]] # values type value will be str or list[str] int most cases
|
||||
ValuesType = typing.Optional[
|
||||
typing.Dict[str, typing.Any]
|
||||
] # values type value will be str or list[str] int most cases
|
||||
|
||||
# : Which coded to use to encode module by default.
|
||||
# : Basic name used to provide the administrator an "huma readable" form for the module
|
||||
@ -108,7 +111,9 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
# : Description of this module, used at admin level
|
||||
typeDescription: typing.ClassVar[str] = 'Base Module'
|
||||
# : Icon file, relative to module folders
|
||||
iconFile: typing.ClassVar[str] = 'base.png' # This is expected to be png, use this format always
|
||||
iconFile: typing.ClassVar[
|
||||
str
|
||||
] = 'base.png' # This is expected to be png, use this format always
|
||||
|
||||
# Not defined, but declared. If module is groupable, this value will contain to which group belongs
|
||||
group: typing.ClassVar[str]
|
||||
@ -175,7 +180,10 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
Base 64 encoded or raw image, obtained from the specified file at
|
||||
'iconFile' class attribute
|
||||
"""
|
||||
file_ = open(os.path.dirname(sys.modules[cls.__module__].__file__) + '/' + cls.iconFile, 'rb')
|
||||
file_ = open(
|
||||
os.path.dirname(sys.modules[cls.__module__].__file__) + '/' + cls.iconFile,
|
||||
'rb',
|
||||
)
|
||||
data = file_.read()
|
||||
file_.close()
|
||||
|
||||
@ -206,7 +214,12 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
"""
|
||||
return [True, _("No connection checking method is implemented.")]
|
||||
|
||||
def __init__(self, environment: Environment, values: ValuesType = None, uuid: typing.Optional[str] = None):
|
||||
def __init__(
|
||||
self,
|
||||
environment: Environment,
|
||||
values: ValuesType = None,
|
||||
uuid: typing.Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Do not forget to invoke this in your derived class using
|
||||
"super(self.__class__, self).__init__(environment, values)".
|
||||
@ -273,7 +286,7 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
Returns:
|
||||
Internacionalized (using ugettext) string of result of the check.
|
||||
"""
|
||||
return _("No check method provided.")
|
||||
return _("No check method provided.")
|
||||
|
||||
def getUuid(self) -> str:
|
||||
return self._uuid
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -12,7 +12,7 @@
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
@ -33,6 +33,7 @@
|
||||
import base64
|
||||
import typing
|
||||
|
||||
|
||||
class Serializable:
|
||||
"""
|
||||
This class represents the interface that all serializable objects must provide.
|
||||
|
@ -108,9 +108,9 @@ class StorageAsDict(MutableMapping):
|
||||
@property
|
||||
def _db(self) -> typing.Union[models.QuerySet, models.Manager]:
|
||||
if self._atomic:
|
||||
return DBStorage.objects.select_for_update()
|
||||
return DBStorage.objects.select_for_update() # type: ignore
|
||||
else:
|
||||
return DBStorage.objects
|
||||
return DBStorage.objects # type: ignore
|
||||
|
||||
@property
|
||||
def _filtered(self) -> 'models.QuerySet[DBStorage]':
|
||||
|
@ -36,11 +36,13 @@ import typing
|
||||
|
||||
from django.db import transaction, OperationalError, connection
|
||||
from django.db.utils import IntegrityError
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
from uds.models.unique_id import UniqueId
|
||||
from uds.models.util import getSqlDatetimeAsUnix
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.db import models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MAX_SEQ = 1000000000000000
|
||||
@ -65,13 +67,13 @@ class UniqueIDGenerator:
|
||||
|
||||
def __filter(
|
||||
self, rangeStart: int, rangeEnd: int = MAX_SEQ, forUpdate: bool = False
|
||||
) -> QuerySet:
|
||||
) -> 'models.QuerySet[UniqueId]':
|
||||
# Order is defined on UniqueId model, and is '-seq' by default (so this gets items in sequence order)
|
||||
# if not for update, do not use the clause :)
|
||||
obj = UniqueId.objects.select_for_update() if forUpdate else UniqueId.objects
|
||||
return obj.filter(
|
||||
basename=self._baseName, seq__gte=rangeStart, seq__lte=rangeEnd
|
||||
) # @UndefinedVariable
|
||||
)
|
||||
|
||||
def get(self, rangeStart: int = 0, rangeEnd: int = MAX_SEQ) -> int:
|
||||
"""
|
||||
|
@ -41,6 +41,7 @@ from uds.core.util import log
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HangedCleaner(Job):
|
||||
frecuency = 3601
|
||||
frecuency_cfg = GlobalConfig.MAX_INITIALIZING_TIME
|
||||
@ -51,9 +52,7 @@ class HangedCleaner(Job):
|
||||
since_state = now - timedelta(
|
||||
seconds=GlobalConfig.MAX_INITIALIZING_TIME.getInt()
|
||||
)
|
||||
since_removing = now -timedelta(
|
||||
seconds=GlobalConfig.MAX_REMOVAL_TIME.getInt()
|
||||
)
|
||||
since_removing = now - timedelta(seconds=GlobalConfig.MAX_REMOVAL_TIME.getInt())
|
||||
# Filter for locating machine not ready
|
||||
flt = Q(state_date__lt=since_state, state=State.PREPARING) | Q(
|
||||
state_date__lt=since_state, state=State.USABLE, os_state=State.PREPARING
|
||||
@ -72,7 +71,8 @@ class HangedCleaner(Job):
|
||||
userServices__state_date__lt=since_state,
|
||||
userServices__state=State.USABLE,
|
||||
userServices__os_state=State.PREPARING,
|
||||
) | Q(
|
||||
)
|
||||
| Q(
|
||||
userServices__state_date__lt=since_removing,
|
||||
userServices__state=State.REMOVING,
|
||||
),
|
||||
@ -95,7 +95,9 @@ class HangedCleaner(Job):
|
||||
): # It's waiting for removal, skip this very specific case
|
||||
continue
|
||||
logger.debug('Found hanged service %s', us)
|
||||
if us.state == State.REMOVING: # Removing too long, remark it as removable
|
||||
if (
|
||||
us.state == State.REMOVING
|
||||
): # Removing too long, remark it as removable
|
||||
log.doLog(
|
||||
us,
|
||||
log.ERROR,
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2013-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2013-2019 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -11,7 +11,7 @@
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
@ -35,6 +35,7 @@ class RequestDebug:
|
||||
"""
|
||||
Used for logging some request data on develeopment
|
||||
"""
|
||||
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
|
@ -35,7 +35,11 @@ from .views import guacamole
|
||||
|
||||
urlpatterns = [
|
||||
# Authenticated path
|
||||
url(r'^uds/guacamole/auth/(?P<token>[^/]+)/(?P<tunnelId>.+)$', guacamole, name='dispatcher.guacamole'),
|
||||
url(
|
||||
r'^uds/guacamole/auth/(?P<token>[^/]+)/(?P<tunnelId>.+)$',
|
||||
guacamole,
|
||||
name='dispatcher.guacamole',
|
||||
),
|
||||
# Non authenticated path. Disabled
|
||||
# url(r'^uds/guacamole/(?P<tunnelId>.+)$', guacamole, name='dispatcher.guacamole.noauth'),
|
||||
]
|
||||
|
@ -54,7 +54,9 @@ def dict2resp(dct: typing.Mapping[typing.Any, typing.Any]) -> str:
|
||||
return '\r'.join((str(k) + '\t' + str(v) for k, v in dct.items()))
|
||||
|
||||
|
||||
def guacamole(request: ExtendedHttpRequestWithUser, token: str, tunnelId: str) -> HttpResponse:
|
||||
def guacamole(
|
||||
request: ExtendedHttpRequestWithUser, token: str, tunnelId: str
|
||||
) -> HttpResponse:
|
||||
if not TunnelToken.validateToken(token):
|
||||
logger.error('Invalid token %s from %s', token, request.ip)
|
||||
return HttpResponse(ERROR, content_type=CONTENT_TYPE)
|
||||
@ -65,12 +67,14 @@ def guacamole(request: ExtendedHttpRequestWithUser, token: str, tunnelId: str) -
|
||||
tunnelId, scrambler = tunnelId.split('.')
|
||||
|
||||
# All strings excetp "ticket-info", that is fixed if it exists later
|
||||
val = typing.cast(typing.MutableMapping[str, str], TicketStore.get(tunnelId, invalidate=False))
|
||||
val = typing.cast(
|
||||
typing.MutableMapping[str, str], TicketStore.get(tunnelId, invalidate=False)
|
||||
)
|
||||
|
||||
# Extra check that the ticket data belongs to original requested user service/user
|
||||
if 'ticket-info' in val:
|
||||
ti = typing.cast(typing.Mapping[str, str], val['ticket-info'])
|
||||
del val['ticket-info'] # Do not send this data to guacamole!! :)
|
||||
del val['ticket-info'] # Do not send this data to guacamole!! :)
|
||||
|
||||
try:
|
||||
userService = UserService.objects.get(uuid=ti['userService'])
|
||||
@ -85,16 +89,21 @@ def guacamole(request: ExtendedHttpRequestWithUser, token: str, tunnelId: str) -
|
||||
userService.deployed_service,
|
||||
events.ET_TUNNEL_OPEN,
|
||||
username=userService.user.pretty_name,
|
||||
source='HTML5-' + protocol, # On HTML5, currently src is not provided by Guacamole
|
||||
source='HTML5-'
|
||||
+ protocol, # On HTML5, currently src is not provided by Guacamole
|
||||
dstip=host,
|
||||
uniqueid=userService.unique_id,
|
||||
)
|
||||
|
||||
except Exception:
|
||||
logger.error('The requested guacamole userservice does not exists anymore')
|
||||
logger.error(
|
||||
'The requested guacamole userservice does not exists anymore'
|
||||
)
|
||||
raise
|
||||
if userService.user.uuid != ti['user']:
|
||||
logger.error('The requested userservice has changed owner and is not accesible')
|
||||
logger.error(
|
||||
'The requested userservice has changed owner and is not accesible'
|
||||
)
|
||||
raise Exception()
|
||||
|
||||
if 'password' in val:
|
||||
|
@ -34,5 +34,9 @@ from django.conf.urls import url
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^uds/ognotify/(?P<msg>[a-z]+)/(?P<token>[a-zA-Z0-9-_]+)/(?P<uuid>[a-zA-Z0-9-_]+)$', views.opengnsys, name='dispatcher.opengnsys'),
|
||||
url(
|
||||
r'^uds/ognotify/(?P<msg>[a-z]+)/(?P<token>[a-zA-Z0-9-_]+)/(?P<uuid>[a-zA-Z0-9-_]+)$',
|
||||
views.opengnsys,
|
||||
name='dispatcher.opengnsys',
|
||||
),
|
||||
]
|
||||
|
@ -52,7 +52,9 @@ def opengnsys(request: HttpRequest, msg: str, token: str, uuid: str) -> HttpResp
|
||||
|
||||
def getUserService() -> typing.Optional[UserService]:
|
||||
try:
|
||||
userService = UserService.objects.get(uuid=processUuid(uuid), state=states.userService.USABLE)
|
||||
userService = UserService.objects.get(
|
||||
uuid=processUuid(uuid), state=states.userService.USABLE
|
||||
)
|
||||
if userService.getProperty('token') == token:
|
||||
return userService
|
||||
logger.warning(
|
||||
@ -63,7 +65,9 @@ def opengnsys(request: HttpRequest, msg: str, token: str, uuid: str) -> HttpResp
|
||||
# Sleep a while in case of error?
|
||||
except Exception as e:
|
||||
# Any exception will stop process
|
||||
logger.warning('OpenGnsys: invalid userService %s:%s. (Ignored)', token, uuid)
|
||||
logger.warning(
|
||||
'OpenGnsys: invalid userService %s:%s. (Ignored)', token, uuid
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
@ -79,9 +83,14 @@ def opengnsys(request: HttpRequest, msg: str, token: str, uuid: str) -> HttpResp
|
||||
if userService:
|
||||
# Ignore login to cached machines...
|
||||
if userService.cache_level != 0:
|
||||
logger.info('Ignored OpenGnsys login to %s to cached machine', userService.friendly_name)
|
||||
logger.info(
|
||||
'Ignored OpenGnsys login to %s to cached machine',
|
||||
userService.friendly_name,
|
||||
)
|
||||
return
|
||||
logger.debug('Processing login from OpenGnsys %s', userService.friendly_name)
|
||||
logger.debug(
|
||||
'Processing login from OpenGnsys %s', userService.friendly_name
|
||||
)
|
||||
actor_v3.Login.process_login(userService, 'OpenGnsys')
|
||||
|
||||
def logout() -> None:
|
||||
@ -89,9 +98,14 @@ def opengnsys(request: HttpRequest, msg: str, token: str, uuid: str) -> HttpResp
|
||||
if userService:
|
||||
# Ignore logout to cached machines...
|
||||
if userService.cache_level != 0:
|
||||
logger.info('Ignored OpenGnsys logout to %s to cached machine', userService.friendly_name)
|
||||
logger.info(
|
||||
'Ignored OpenGnsys logout to %s to cached machine',
|
||||
userService.friendly_name,
|
||||
)
|
||||
return
|
||||
logger.debug('Processing logout from OpenGnsys %s', userService.friendly_name)
|
||||
logger.debug(
|
||||
'Processing logout from OpenGnsys %s', userService.friendly_name
|
||||
)
|
||||
actor_v3.Logout.process_logout(userService, 'OpenGnsys')
|
||||
|
||||
fnc: typing.Optional[typing.Callable[[], None]] = {
|
||||
|
@ -54,7 +54,11 @@ def pam(request: ExtendedHttpRequestWithUser) -> HttpResponse:
|
||||
# If request is not forged...
|
||||
if len(ids) == 1:
|
||||
userId = ids[0]
|
||||
logger.debug("Auth request for user [%s] and pass [%s]", request.GET['id'], request.GET['pass'])
|
||||
logger.debug(
|
||||
"Auth request for user [%s] and pass [%s]",
|
||||
request.GET['id'],
|
||||
request.GET['pass'],
|
||||
)
|
||||
try:
|
||||
password = TicketStore.get(userId)
|
||||
if password == request.GET['pass']:
|
||||
@ -63,7 +67,11 @@ def pam(request: ExtendedHttpRequestWithUser) -> HttpResponse:
|
||||
# Non existing ticket, log it and stop
|
||||
logger.info('Invalid access from %s using user %s', request.ip, userId)
|
||||
else:
|
||||
logger.warning('Invalid request from %s: %s', request.ip, [v for v in request.GET.lists()])
|
||||
logger.warning(
|
||||
'Invalid request from %s: %s',
|
||||
request.ip,
|
||||
[v for v in request.GET.lists()],
|
||||
)
|
||||
elif 'uid' in request.GET:
|
||||
# This is an "get name for id" call
|
||||
logger.debug("NSS Request for id [%s]", request.GET['uid'])
|
||||
|
@ -57,7 +57,9 @@ class Command(BaseCommand):
|
||||
mod, name = first
|
||||
else:
|
||||
mod, name = GLOBAL_SECTION, first[0]
|
||||
if Config.update(mod, name, value) is False: # If not exists, try to store value without any special parameters
|
||||
if (
|
||||
Config.update(mod, name, value) is False
|
||||
): # If not exists, try to store value without any special parameters
|
||||
Config.section(mod).value(name, value).get()
|
||||
except Exception as e:
|
||||
print('The command could not be processed: {}'.format(e))
|
||||
|
@ -50,9 +50,15 @@ PID_FILE = 'taskmanager.pid'
|
||||
def getPidFile():
|
||||
return settings.BASE_DIR + '/' + PID_FILE
|
||||
|
||||
|
||||
# become_daemon seems te be removed on django 1.9
|
||||
# This is a copy of posix version from django 1.8
|
||||
def become_daemon(our_home_dir: str = '.', out_log: str = '/dev/null', err_log: str = '/dev/null', umask: int = 0o022):
|
||||
def become_daemon(
|
||||
our_home_dir: str = '.',
|
||||
out_log: str = '/dev/null',
|
||||
err_log: str = '/dev/null',
|
||||
umask: int = 0o022,
|
||||
):
|
||||
"""Robustly turn into a UNIX daemon, running in our_home_dir."""
|
||||
# First fork
|
||||
try:
|
||||
@ -93,21 +99,21 @@ class Command(BaseCommand):
|
||||
action='store_true',
|
||||
dest='start',
|
||||
default=False,
|
||||
help='Starts a new daemon'
|
||||
help='Starts a new daemon',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--stop',
|
||||
action='store_true',
|
||||
dest='stop',
|
||||
default=False,
|
||||
help='Stop any running daemon'
|
||||
help='Stop any running daemon',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--foreground',
|
||||
action='store_true',
|
||||
dest='foreground',
|
||||
default=False,
|
||||
help='Stop any running daemon'
|
||||
help='Stop any running daemon',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options) -> None:
|
||||
@ -141,7 +147,11 @@ class Command(BaseCommand):
|
||||
logger.info('Starting task manager.')
|
||||
|
||||
if not foreground:
|
||||
become_daemon(settings.BASE_DIR, settings.LOGDIR + '/taskManagerStdout.log', settings.LOGDIR + '/taskManagerStderr.log')
|
||||
become_daemon(
|
||||
settings.BASE_DIR,
|
||||
settings.LOGDIR + '/taskManagerStdout.log',
|
||||
settings.LOGDIR + '/taskManagerStderr.log',
|
||||
)
|
||||
pid = os.getpid()
|
||||
|
||||
open(getPidFile(), 'w+').write('{}\n'.format(pid))
|
||||
@ -149,8 +159,10 @@ class Command(BaseCommand):
|
||||
manager = taskManager()()
|
||||
manager.run()
|
||||
|
||||
if not start and not stop:
|
||||
if not start and not stop:
|
||||
if pid:
|
||||
sys.stdout.write("Task manager found running (pid file exists: {0})\n".format(pid))
|
||||
sys.stdout.write(
|
||||
"Task manager found running (pid file exists: {0})\n".format(pid)
|
||||
)
|
||||
else:
|
||||
sys.stdout.write("Task manager not foud (pid file do not exits)\n")
|
||||
|
@ -105,7 +105,7 @@ class Authenticator(ManagedObjectModel, TaggingMixin):
|
||||
"""
|
||||
Get the type of the object this record represents.
|
||||
|
||||
The type is Python type, it obtains this type from ServiceProviderFactory and associated record field.
|
||||
The type is Python type, it obtains this type from AuthsFactory and associated record field.
|
||||
|
||||
Returns:
|
||||
The python type for this record object
|
||||
|
@ -64,7 +64,7 @@ class Config(models.Model):
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['section', 'key'], name='u_cfg_section_key')
|
||||
]
|
||||
|
||||
|
||||
app_label = 'uds'
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
@ -48,8 +48,11 @@ class DelayedTask(models.Model):
|
||||
|
||||
This table contains uds.core.util.jobs.DelayedTask references
|
||||
"""
|
||||
|
||||
type = models.CharField(max_length=128)
|
||||
tag = models.CharField(max_length=64, db_index=True) # A tag for letting us locate delayed publications...
|
||||
tag = models.CharField(
|
||||
max_length=64, db_index=True
|
||||
) # A tag for letting us locate delayed publications...
|
||||
instance = models.TextField()
|
||||
insert_date = models.DateTimeField()
|
||||
execution_delay = models.PositiveIntegerField()
|
||||
@ -62,7 +65,10 @@ class DelayedTask(models.Model):
|
||||
"""
|
||||
Meta class to declare default order and unique multiple field index
|
||||
"""
|
||||
|
||||
app_label = 'uds'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "Run Queue task {0} owned by {3},inserted at {1} and with {2} seconds delay".format(self.type, self.insert_date, self.execution_delay, self.execution_time)
|
||||
return "Run Queue task {0} owned by {3},inserted at {1} and with {2} seconds delay".format(
|
||||
self.type, self.insert_date, self.execution_delay, self.execution_time
|
||||
)
|
||||
|
@ -79,7 +79,9 @@ class Group(UUIDModel):
|
||||
app_label = 'uds'
|
||||
# unique_together = (("manager", "name"),)
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['manager', 'name'], name='u_grp_manager_name')
|
||||
models.UniqueConstraint(
|
||||
fields=['manager', 'name'], name='u_grp_manager_name'
|
||||
)
|
||||
]
|
||||
|
||||
@property
|
||||
|
@ -81,7 +81,7 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
|
||||
TRANSPORT_SELECT: typing.Mapping[int, str] = {
|
||||
AUTO_TRANSPORT_SELECT: _('Automatic selection'),
|
||||
COMMON_TRANSPORT_SELECT: _('Use only common transports'),
|
||||
LABEL_TRANSPORT_SELECT: _('Group Transports by label')
|
||||
LABEL_TRANSPORT_SELECT: _('Group Transports by label'),
|
||||
}
|
||||
|
||||
name = models.CharField(max_length=128, default='')
|
||||
|
@ -72,7 +72,7 @@ class OSManager(ManagedObjectModel, TaggingMixin): # type: ignore
|
||||
"""
|
||||
Get the type of the object this record represents.
|
||||
|
||||
The type is Python type, it obtains this type from ServiceProviderFactory and associated record field.
|
||||
The type is Python type, it obtains this OsManagersFactory and associated record field.
|
||||
|
||||
Returns:
|
||||
The python type for this record object
|
||||
|
@ -88,7 +88,9 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
|
||||
ordering = ('name',)
|
||||
app_label = 'uds'
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['provider', 'name'], name='u_srv_provider_name')
|
||||
models.UniqueConstraint(
|
||||
fields=['provider', 'name'], name='u_srv_provider_name'
|
||||
)
|
||||
]
|
||||
|
||||
def getEnvironment(self) -> Environment:
|
||||
@ -105,7 +107,9 @@ class Service(ManagedObjectModel, TaggingMixin): # type: ignore
|
||||
},
|
||||
)
|
||||
|
||||
def getInstance(self, values: typing.Optional[typing.Dict[str, str]] = None) -> 'services.Service':
|
||||
def getInstance(
|
||||
self, values: typing.Optional[typing.Dict[str, str]] = None
|
||||
) -> 'services.Service':
|
||||
"""
|
||||
Instantiates the object this record contains.
|
||||
|
||||
|
@ -159,7 +159,7 @@ class ServicePool(UUIDModel, TaggingMixin): # type: ignore
|
||||
userServices: 'models.QuerySet[UserService]'
|
||||
calendarAccess: 'models.QuerySet[CalendarAccess]'
|
||||
changelog: 'models.QuerySet[ServicePoolPublicationChangelog]'
|
||||
|
||||
|
||||
calendaraction_set: typing.Any
|
||||
|
||||
class Meta(UUIDModel.Meta):
|
||||
|
@ -49,11 +49,18 @@ class ServicePoolGroup(UUIDModel):
|
||||
"""
|
||||
A deployed service is the Service produced element that is assigned finally to an user (i.e. a Virtual Machine, etc..)
|
||||
"""
|
||||
|
||||
# pylint: disable=model-missing-unicode
|
||||
name = models.CharField(max_length=128, default='', db_index=True, unique=True)
|
||||
comments = models.CharField(max_length=256, default='')
|
||||
priority = models.IntegerField(default=0, db_index=True)
|
||||
image: 'models.ForeignKey[ServicePoolGroup, Image]' = models.ForeignKey(Image, null=True, blank=True, related_name='servicesPoolsGroup', on_delete=models.SET_NULL)
|
||||
image: 'models.ForeignKey[ServicePoolGroup, Image]' = models.ForeignKey(
|
||||
Image,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='servicesPoolsGroup',
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
|
||||
# "fake" declarations for type checking
|
||||
objects: 'models.BaseManager[ServicePoolGroup]'
|
||||
@ -62,11 +69,14 @@ class ServicePoolGroup(UUIDModel):
|
||||
"""
|
||||
Meta class to declare the name of the table at database
|
||||
"""
|
||||
|
||||
db_table = 'uds__pools_groups'
|
||||
app_label = 'uds'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return 'Service Pool group {}({}): {}'.format(self.name, self.comments, self.image.name)
|
||||
return 'Service Pool group {}({}): {}'.format(
|
||||
self.name, self.comments, self.image.name
|
||||
)
|
||||
|
||||
@property
|
||||
def as_dict(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
@ -75,12 +85,12 @@ class ServicePoolGroup(UUIDModel):
|
||||
'name': self.name,
|
||||
'comments': self.comments,
|
||||
'priority': self.priority,
|
||||
'imageUuid': self.image.uuid if self.image is not None else 'x'
|
||||
'imageUuid': self.image.uuid if self.image is not None else 'x',
|
||||
}
|
||||
|
||||
@property
|
||||
def thumb64(self) -> str:
|
||||
return self.image.thumb64 if self.image else DEFAULT_THUMB_BASE64
|
||||
return self.image.thumb64 if self.image else DEFAULT_THUMB_BASE64
|
||||
|
||||
@staticmethod
|
||||
def default() -> 'ServicePoolGroup':
|
||||
|
@ -109,7 +109,6 @@ class ServicePoolPublication(UUIDModel):
|
||||
objects: 'models.BaseManager[ServicePoolPublication]'
|
||||
userServices: 'models.QuerySet[UserService]'
|
||||
|
||||
|
||||
class Meta(UUIDModel.Meta):
|
||||
"""
|
||||
Meta class to declare default order and unique multiple field index
|
||||
|
@ -73,7 +73,7 @@ class StatsCounters(models.Model):
|
||||
@staticmethod
|
||||
def get_grouped(
|
||||
owner_type: typing.Union[int, typing.Iterable[int]], counter_type: int, **kwargs
|
||||
) -> 'models.QuerySet[StatsCounters]': # pylint: disable=too-many-locals
|
||||
) -> 'models.QuerySet[StatsCounters]':
|
||||
"""
|
||||
Returns the average stats grouped by interval for owner_type and owner_id (optional)
|
||||
|
||||
|
@ -42,10 +42,13 @@ class Storage(models.Model):
|
||||
General storage model. Used to store specific instances (transport, service, servicemanager, ...) persistent information
|
||||
not intended to be serialized/deserialized everytime one object instance is loaded/saved.
|
||||
"""
|
||||
|
||||
owner = models.CharField(max_length=128, db_index=True)
|
||||
key = models.CharField(max_length=64, primary_key=True)
|
||||
data = models.TextField(default='')
|
||||
attr1 = models.CharField(max_length=64, db_index=True, null=True, blank=True, default=None)
|
||||
attr1 = models.CharField(
|
||||
max_length=64, db_index=True, null=True, blank=True, default=None
|
||||
)
|
||||
|
||||
# "fake" declarations for type checking
|
||||
objects: 'models.BaseManager[Storage]'
|
||||
@ -54,7 +57,10 @@ class Storage(models.Model):
|
||||
"""
|
||||
Meta class to declare the name of the table at database
|
||||
"""
|
||||
|
||||
app_label = 'uds'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '{} {} > str= {}, {}'.format(self.owner, self.key, self.data, '/'.join([self.attr1]))
|
||||
return '{} {} > str= {}, {}'.format(
|
||||
self.owner, self.key, self.data, '/'.join([self.attr1])
|
||||
)
|
||||
|
@ -89,7 +89,9 @@ class TicketStore(UUIDModel):
|
||||
|
||||
@staticmethod
|
||||
def generateUuid() -> str:
|
||||
return cryptoManager().randomString(40).lower() # Temporary fix lower() for compat with 3.0
|
||||
return (
|
||||
cryptoManager().randomString(40).lower()
|
||||
) # Temporary fix lower() for compat with 3.0
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
|
@ -88,7 +88,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
|
||||
"""
|
||||
Get the type of the object this record represents.
|
||||
|
||||
The type is Python type, it obtains this type from ServiceProviderFactory and associated record field.
|
||||
The type is Python type, it obtains this type from TransportsFactory and associated record field.
|
||||
|
||||
Returns:
|
||||
The python type for this record object
|
||||
|
@ -33,6 +33,7 @@ import typing
|
||||
from django.db import models
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
|
||||
|
||||
class TunnelToken(models.Model):
|
||||
"""
|
||||
UDS Tunnel tokens on DB
|
||||
@ -56,7 +57,9 @@ class TunnelToken(models.Model):
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def validateToken(token: str, request: typing.Optional[ExtendedHttpRequest] = None) -> bool:
|
||||
def validateToken(
|
||||
token: str, request: typing.Optional[ExtendedHttpRequest] = None
|
||||
) -> bool:
|
||||
try:
|
||||
tt = TunnelToken.objects.get(token=token)
|
||||
# We could check the request ip here
|
||||
|
@ -187,18 +187,18 @@ class User(UUIDModel):
|
||||
number_belongs_meta=Count('groups', filter=Q(groups__id__in=grps))
|
||||
) # g.groups.filter(id__in=grps).count()
|
||||
):
|
||||
numberGroupsBelongingInMeta: int = g.number_belongs_meta
|
||||
numberGroupsBelongingInMeta: int = g.number_belongs_meta # type: ignore # anottation
|
||||
|
||||
logger.debug('gn = %s', numberGroupsBelongingInMeta)
|
||||
logger.debug('groups count: %s', g.number_groups)
|
||||
logger.debug('groups count: %s', g.number_groups) # type: ignore # anottation
|
||||
|
||||
if g.meta_if_any is True and numberGroupsBelongingInMeta > 0:
|
||||
numberGroupsBelongingInMeta = g.number_groups
|
||||
numberGroupsBelongingInMeta = g.number_groups # type: ignore # anottation
|
||||
|
||||
logger.debug('gn after = %s', numberGroupsBelongingInMeta)
|
||||
|
||||
# If a meta group is empty, all users belongs to it. we can use gn != 0 to check that if it is empty, is not valid
|
||||
if numberGroupsBelongingInMeta == g.number_groups:
|
||||
if numberGroupsBelongingInMeta == g.number_groups: # type: ignore # anottation
|
||||
# This group matches
|
||||
yield g
|
||||
|
||||
|
@ -63,7 +63,9 @@ class UserServiceProperty(models.Model): # pylint: disable=too-many-public-meth
|
||||
db_table = 'uds__user_service_property'
|
||||
app_label = 'uds'
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['name', 'user_service'], name='u_uprop_name_userservice')
|
||||
models.UniqueConstraint(
|
||||
fields=['name', 'user_service'], name='u_uprop_name_userservice'
|
||||
)
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
@ -42,6 +42,7 @@ logger = logging.getLogger(__name__)
|
||||
NEVER = datetime(1972, 7, 1)
|
||||
NEVER_UNIX = int(mktime(NEVER.timetuple()))
|
||||
|
||||
|
||||
class UnsavedForeignKey(models.ForeignKey):
|
||||
"""
|
||||
From 1.8 of django, we need to point to "saved" objects.
|
||||
@ -49,9 +50,11 @@ class UnsavedForeignKey(models.ForeignKey):
|
||||
|
||||
We need to trick in some cases, because for example, root user is not in DB
|
||||
"""
|
||||
|
||||
# Allows pointing to an unsaved object
|
||||
allow_unsaved_instance_assignment = True
|
||||
|
||||
|
||||
def getSqlDatetime() -> datetime:
|
||||
"""
|
||||
Returns the current date/time of the database server.
|
||||
@ -64,17 +67,25 @@ def getSqlDatetime() -> datetime:
|
||||
"""
|
||||
if connection.vendor in ('mysql', 'microsoft'):
|
||||
cursor = connection.cursor()
|
||||
sentence = 'SELECT NOW()' if connection.vendor == 'mysql' else 'SELECT CURRENT_TIMESTAMP'
|
||||
sentence = (
|
||||
'SELECT NOW()'
|
||||
if connection.vendor == 'mysql'
|
||||
else 'SELECT CURRENT_TIMESTAMP'
|
||||
)
|
||||
cursor.execute(sentence)
|
||||
date = cursor.fetchone()[0]
|
||||
else:
|
||||
date = datetime.now() # If not know how to get database datetime, returns local datetime (this is fine for sqlite, which is local)
|
||||
date = (
|
||||
datetime.now()
|
||||
) # If not know how to get database datetime, returns local datetime (this is fine for sqlite, which is local)
|
||||
|
||||
return date
|
||||
|
||||
|
||||
def getSqlDatetimeAsUnix() -> int:
|
||||
return int(mktime(getSqlDatetime().timetuple()))
|
||||
|
||||
|
||||
def getSqlFnc(fncName: str) -> str:
|
||||
"""
|
||||
Convert different sql functions for different platforms
|
||||
|
@ -46,42 +46,60 @@ OSManagersFactory.factory().insert(LinuxRandomPassManager)
|
||||
|
||||
downloadsManager().registerDownloadable(
|
||||
'udsactor_{version}_all.deb'.format(version=VERSION),
|
||||
_('UDS Actor for Debian, Ubuntu, ... Linux machines <b>(Requires python >= 3.6)</b>'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor_{version}_all.deb'.format(version=VERSION),
|
||||
'application/x-debian-package'
|
||||
_(
|
||||
'UDS Actor for Debian, Ubuntu, ... Linux machines <b>(Requires python >= 3.6)</b>'
|
||||
),
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/udsactor_{version}_all.deb'.format(version=VERSION),
|
||||
'application/x-debian-package',
|
||||
)
|
||||
|
||||
downloadsManager().registerDownloadable(
|
||||
'udsactor-{version}-1.noarch.rpm'.format(version=VERSION),
|
||||
_('UDS Actor for Centos, Fedora, RH, Suse, ... Linux machines <b>(Requires python >= 3.6)</b>'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor-{version}-1.noarch.rpm'.format(version=VERSION),
|
||||
'application/x-redhat-package-manager'
|
||||
_(
|
||||
'UDS Actor for Centos, Fedora, RH, Suse, ... Linux machines <b>(Requires python >= 3.6)</b>'
|
||||
),
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/udsactor-{version}-1.noarch.rpm'.format(version=VERSION),
|
||||
'application/x-redhat-package-manager',
|
||||
)
|
||||
|
||||
downloadsManager().registerDownloadable(
|
||||
'udsactor-unmanaged_{version}_all.deb'.format(version=VERSION),
|
||||
_('UDS Actor for Debian based Linux machines. Used ONLY for static machines. <b>(Requires python >= 3.6)</b>'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor-unmanaged_{version}_all.deb'.format(version=VERSION),
|
||||
'application/x-debian-package'
|
||||
_(
|
||||
'UDS Actor for Debian based Linux machines. Used ONLY for static machines. <b>(Requires python >= 3.6)</b>'
|
||||
),
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/udsactor-unmanaged_{version}_all.deb'.format(version=VERSION),
|
||||
'application/x-debian-package',
|
||||
)
|
||||
|
||||
downloadsManager().registerDownloadable(
|
||||
'udsactor_2.2.0_legacy.deb',
|
||||
_('<b>Legacy</b> UDS Actor for Debian, Ubuntu, ... Linux machines <b>(Requires python 2.7)</b>'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor_2.2.0_legacy.deb',
|
||||
'application/x-debian-package'
|
||||
_(
|
||||
'<b>Legacy</b> UDS Actor for Debian, Ubuntu, ... Linux machines <b>(Requires python 2.7)</b>'
|
||||
),
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/udsactor_2.2.0_legacy.deb',
|
||||
'application/x-debian-package',
|
||||
)
|
||||
|
||||
downloadsManager().registerDownloadable(
|
||||
'udsactor-legacy-2.2.1-1.noarch.rpm',
|
||||
_('<b>Legacy</b> UDS Actor for Centos, Fedora, RH, ... Linux machines <b>(Requires python 2.7)</b>'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor-legacy-2.2.1-1.noarch.rpm',
|
||||
'application/x-redhat-package-manager'
|
||||
_(
|
||||
'<b>Legacy</b> UDS Actor for Centos, Fedora, RH, ... Linux machines <b>(Requires python 2.7)</b>'
|
||||
),
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/udsactor-legacy-2.2.1-1.noarch.rpm',
|
||||
'application/x-redhat-package-manager',
|
||||
)
|
||||
|
||||
downloadsManager().registerDownloadable(
|
||||
'udsactor-opensuse-legacy-2.2.1-1.noarch.rpm',
|
||||
_('<b>Legacy</b> UDS Actor for OpenSUSE, ... Linux machines <b>(Requires python 2.7)</b>'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor-opensuse-legacy-2.2.1-1.noarch.rpm',
|
||||
'application/x-redhat-package-manager'
|
||||
_(
|
||||
'<b>Legacy</b> UDS Actor for OpenSUSE, ... Linux machines <b>(Requires python 2.7)</b>'
|
||||
),
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/udsactor-opensuse-legacy-2.2.1-1.noarch.rpm',
|
||||
'application/x-redhat-package-manager',
|
||||
)
|
||||
|
@ -65,17 +65,25 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
values=[
|
||||
{'id': 'keep', 'text': ugettext_lazy('Keep service assigned')},
|
||||
{'id': 'remove', 'text': ugettext_lazy('Remove service')},
|
||||
{'id': 'keep-always', 'text': ugettext_lazy('Keep service assigned even on new publication')},
|
||||
{
|
||||
'id': 'keep-always',
|
||||
'text': ugettext_lazy('Keep service assigned even on new publication'),
|
||||
},
|
||||
],
|
||||
defvalue='keep')
|
||||
defvalue='keep',
|
||||
)
|
||||
|
||||
idle = gui.NumericField(
|
||||
label=_("Max.Idle time"),
|
||||
length=4,
|
||||
defvalue=-1,
|
||||
rdonly=False, order=11,
|
||||
tooltip=_('Maximum idle time (in seconds) before session is automatically closed to the user (<= 0 means no max idle time).'),
|
||||
required=True)
|
||||
rdonly=False,
|
||||
order=11,
|
||||
tooltip=_(
|
||||
'Maximum idle time (in seconds) before session is automatically closed to the user (<= 0 means no max idle time).'
|
||||
),
|
||||
required=True,
|
||||
)
|
||||
|
||||
deadLine = gui.CheckBoxField(
|
||||
label=_('Calendar logout'),
|
||||
@ -114,7 +122,9 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
Says if a machine is removable on logout
|
||||
'''
|
||||
if not userService.in_use:
|
||||
if (self._onLogout == 'remove') or (not userService.isValidPublication() and self._onLogout == 'keep'):
|
||||
if (self._onLogout == 'remove') or (
|
||||
not userService.isValidPublication() and self._onLogout == 'keep'
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -174,13 +184,18 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
def readyNotified(self, userService):
|
||||
return
|
||||
|
||||
def actorData(self, userService: 'UserService') -> typing.MutableMapping[str, typing.Any]:
|
||||
return {
|
||||
'action': 'rename',
|
||||
'name': userService.getName()
|
||||
}
|
||||
def actorData(
|
||||
self, userService: 'UserService'
|
||||
) -> typing.MutableMapping[str, typing.Any]:
|
||||
return {'action': 'rename', 'name': userService.getName()}
|
||||
|
||||
def process(self, userService: 'UserService', message: str, data: typing.Any, options: typing.Optional[typing.Dict[str, typing.Any]] = None) -> str:
|
||||
def process(
|
||||
self,
|
||||
userService: 'UserService',
|
||||
message: str,
|
||||
data: typing.Any,
|
||||
options: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
||||
) -> str:
|
||||
"""
|
||||
We understand this messages:
|
||||
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class), old method
|
||||
@ -189,17 +204,24 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
* msg = logoff, data = Username, Informs that the username has logged out of the machine
|
||||
* msg = ready, data = None, Informs machine ready to be used
|
||||
"""
|
||||
logger.info("Invoked LinuxOsManager for %s with params: %s, %s", userService, message, data)
|
||||
logger.info(
|
||||
"Invoked LinuxOsManager for %s with params: %s, %s",
|
||||
userService,
|
||||
message,
|
||||
data,
|
||||
)
|
||||
# We get from storage the name for this userService. If no name, we try to assign a new one
|
||||
ret = "ok"
|
||||
notifyReady = False
|
||||
doRemove = False
|
||||
state = userService.os_state
|
||||
if message in ('ready', 'ip'):
|
||||
if not isinstance(data, dict): # Older actors?, previous to 2.5, convert it information..
|
||||
if not isinstance(
|
||||
data, dict
|
||||
): # Older actors?, previous to 2.5, convert it information..
|
||||
data = {
|
||||
'ips': [v.split('=') for v in typing.cast(str, data).split(',')],
|
||||
'hostname': userService.friendly_name
|
||||
'hostname': userService.friendly_name,
|
||||
}
|
||||
|
||||
# Old "info" state, will be removed in a near future
|
||||
@ -246,7 +268,12 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
This function can update userService values. Normal operation will be remove machines if this state is not valid
|
||||
"""
|
||||
if self.isRemovableOnLogout(userService):
|
||||
log.doLog(userService, log.INFO, 'Unused user service for too long. Removing due to OS Manager parameters.', log.OSMANAGER)
|
||||
log.doLog(
|
||||
userService,
|
||||
log.INFO,
|
||||
'Unused user service for too long. Removing due to OS Manager parameters.',
|
||||
log.OSMANAGER,
|
||||
)
|
||||
userService.remove()
|
||||
|
||||
def isPersistent(self):
|
||||
@ -260,7 +287,9 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
"""
|
||||
On production environments, will return no idle for non removable machines
|
||||
"""
|
||||
if self._idle <= 0: # or (settings.DEBUG is False and self._onLogout != 'remove'):
|
||||
if (
|
||||
self._idle <= 0
|
||||
): # or (settings.DEBUG is False and self._onLogout != 'remove'):
|
||||
return None
|
||||
|
||||
return self._idle
|
||||
@ -269,7 +298,9 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
"""
|
||||
Serializes the os manager data so we can store it in database
|
||||
"""
|
||||
return '\t'.join(['v3', self._onLogout, str(self._idle), gui.boolToStr(self._deadLine)]).encode('utf8')
|
||||
return '\t'.join(
|
||||
['v3', self._onLogout, str(self._idle), gui.boolToStr(self._deadLine)]
|
||||
).encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes):
|
||||
values = data.decode('utf8').split('\t')
|
||||
@ -280,9 +311,17 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
elif values[0] == 'v2':
|
||||
self._onLogout, self._idle = values[1], int(values[2])
|
||||
elif values[0] == 'v3':
|
||||
self._onLogout, self._idle, self._deadLine = values[1], int(values[2]), gui.strToBool(values[3])
|
||||
self._onLogout, self._idle, self._deadLine = (
|
||||
values[1],
|
||||
int(values[2]),
|
||||
gui.strToBool(values[3]),
|
||||
)
|
||||
|
||||
self.__setProcessUnusedMachines()
|
||||
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
return {'onLogout': self._onLogout, 'idle': str(self._idle), 'deadLine': gui.boolToStr(self._deadLine) }
|
||||
return {
|
||||
'onLogout': self._onLogout,
|
||||
'idle': str(self._idle),
|
||||
'deadLine': gui.boolToStr(self._deadLine),
|
||||
}
|
||||
|
@ -48,14 +48,23 @@ logger = logging.getLogger(__name__)
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models.user_service import UserService
|
||||
|
||||
|
||||
class LinuxRandomPassManager(LinuxOsManager):
|
||||
typeName = _('Linux Random Password OS Manager')
|
||||
typeType = 'LinRandomPasswordManager'
|
||||
typeDescription = _('Os Manager to control linux machines, with user password set randomly.')
|
||||
typeDescription = _(
|
||||
'Os Manager to control linux machines, with user password set randomly.'
|
||||
)
|
||||
iconFile = 'losmanager.png'
|
||||
|
||||
# Apart form data from linux os manager, we need also domain and credentials
|
||||
userAccount = gui.TextField(length=64, label=_('Account'), order=2, tooltip=_('User account to change password'), required=True)
|
||||
userAccount = gui.TextField(
|
||||
length=64,
|
||||
label=_('Account'),
|
||||
order=2,
|
||||
tooltip=_('User account to change password'),
|
||||
required=True,
|
||||
)
|
||||
|
||||
# Inherits base "onLogout"
|
||||
onLogout = LinuxOsManager.onLogout
|
||||
@ -68,12 +77,16 @@ class LinuxRandomPassManager(LinuxOsManager):
|
||||
super(LinuxRandomPassManager, self).__init__(environment, values)
|
||||
if values is not None:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an user account!!!'))
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
_('Must provide an user account!!!')
|
||||
)
|
||||
self._userAccount = values['userAccount']
|
||||
else:
|
||||
self._userAccount = ''
|
||||
|
||||
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
|
||||
def processUserPassword(
|
||||
self, userService: 'UserService', username: str, password: str
|
||||
) -> typing.Tuple[str, str]:
|
||||
if username == self._userAccount:
|
||||
return (username, userService.recoverValue('linOsRandomPass'))
|
||||
return username, password
|
||||
@ -81,25 +94,39 @@ class LinuxRandomPassManager(LinuxOsManager):
|
||||
def genPassword(self, service):
|
||||
randomPass = service.recoverValue('linOsRandomPass')
|
||||
if randomPass is None:
|
||||
randomPass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(16))
|
||||
randomPass = ''.join(
|
||||
random.SystemRandom().choice(string.ascii_letters + string.digits)
|
||||
for _ in range(16)
|
||||
)
|
||||
service.storeValue('linOsRandomPass', randomPass)
|
||||
log.doLog(service, log.INFO, "Password set to \"{}\"".format(randomPass), log.OSMANAGER)
|
||||
log.doLog(
|
||||
service,
|
||||
log.INFO,
|
||||
"Password set to \"{}\"".format(randomPass),
|
||||
log.OSMANAGER,
|
||||
)
|
||||
|
||||
return randomPass
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'rename:{0}\t{1}\t\t{2}'.format(self.getName(service), self._userAccount, self.genPassword(service))
|
||||
return 'rename:{0}\t{1}\t\t{2}'.format(
|
||||
self.getName(service), self._userAccount, self.genPassword(service)
|
||||
)
|
||||
|
||||
def infoValue(self, service):
|
||||
return 'rename\r{0}\t{1}\t\t{2}'.format(self.getName(service), self._userAccount, self.genPassword(service))
|
||||
return 'rename\r{0}\t{1}\t\t{2}'.format(
|
||||
self.getName(service), self._userAccount, self.genPassword(service)
|
||||
)
|
||||
|
||||
def actorData(self, userService: 'UserService') -> typing.MutableMapping[str, typing.Any]:
|
||||
def actorData(
|
||||
self, userService: 'UserService'
|
||||
) -> typing.MutableMapping[str, typing.Any]:
|
||||
return {
|
||||
'action': 'rename',
|
||||
'name': userService.getName(),
|
||||
'username': self._userAccount,
|
||||
'password': '', # On linux, user password is not needed so we provide an empty one
|
||||
'new_password': self.genPassword(userService)
|
||||
'new_password': self.genPassword(userService),
|
||||
}
|
||||
|
||||
def marshal(self) -> bytes:
|
||||
@ -107,7 +134,9 @@ class LinuxRandomPassManager(LinuxOsManager):
|
||||
Serializes the os manager data so we can store it in database
|
||||
"""
|
||||
base = LinuxOsManager.marshal(self)
|
||||
return '\t'.join(['v1', self._userAccount, codecs.encode(base, 'hex').decode()]).encode('utf8')
|
||||
return '\t'.join(
|
||||
['v1', self._userAccount, codecs.encode(base, 'hex').decode()]
|
||||
).encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
values = data.split(b'\t')
|
||||
|
@ -50,11 +50,15 @@ osmanagers.factory().insert(WinRandomPassManager)
|
||||
managers.downloadsManager().registerDownloadable(
|
||||
'UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
_('UDS Actor for windows machines'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
'application/x-msdos-program')
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
'application/x-msdos-program',
|
||||
)
|
||||
|
||||
managers.downloadsManager().registerDownloadable(
|
||||
'UDSActorUnmanagedSetup-{version}.exe'.format(version=VERSION),
|
||||
_('UDS Actor for Unmanaged windows machines. Used ONLY for static machines.'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/UDSActorUnmanagedSetup-{version}.exe'.format(version=VERSION),
|
||||
'application/x-msdos-program')
|
||||
os.path.dirname(sys.modules[__package__].__file__)
|
||||
+ '/files/UDSActorUnmanagedSetup-{version}.exe'.format(version=VERSION),
|
||||
'application/x-msdos-program',
|
||||
)
|
||||
|
@ -350,7 +350,9 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
"""
|
||||
Serializes the os manager data so we can store it in database
|
||||
"""
|
||||
return '\t'.join(['v3', self._onLogout, str(self._idle), gui.boolToStr(self._deadLine)]).encode('utf8')
|
||||
return '\t'.join(
|
||||
['v3', self._onLogout, str(self._idle), gui.boolToStr(self._deadLine)]
|
||||
).encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
vals = data.decode('utf8').split('\t')
|
||||
@ -362,7 +364,11 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
elif vals[0] == 'v2':
|
||||
self._onLogout, self._idle = vals[1], int(vals[2])
|
||||
elif vals[0] == 'v3':
|
||||
self._onLogout, self._idle, self._deadLine = vals[1], int(vals[2]), gui.strToBool(vals[3])
|
||||
self._onLogout, self._idle, self._deadLine = (
|
||||
vals[1],
|
||||
int(vals[2]),
|
||||
gui.strToBool(vals[3]),
|
||||
)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
'Exception unmarshalling. Some values left as default ones'
|
||||
@ -371,4 +377,8 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
self.__setProcessUnusedMachines()
|
||||
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
return {'onLogout': self._onLogout, 'idle': str(self._idle), 'deadLine': gui.boolToStr(self._deadLine) }
|
||||
return {
|
||||
'onLogout': self._onLogout,
|
||||
'idle': str(self._idle),
|
||||
'deadLine': gui.boolToStr(self._deadLine),
|
||||
}
|
||||
|
@ -58,12 +58,26 @@ logger = logging.getLogger(__name__)
|
||||
class WinRandomPassManager(WindowsOsManager):
|
||||
typeName = _('Windows Random Password OS Manager')
|
||||
typeType = 'WinRandomPasswordManager'
|
||||
typeDescription = _('Os Manager to control windows machines, with user password set randomly.')
|
||||
typeDescription = _(
|
||||
'Os Manager to control windows machines, with user password set randomly.'
|
||||
)
|
||||
iconFile = 'wosmanager.png'
|
||||
|
||||
# Apart form data from windows os manager, we need also domain and credentials
|
||||
userAccount = gui.TextField(length=64, label=_('Account'), order=2, tooltip=_('User account to change password'), required=True)
|
||||
password = gui.PasswordField(length=64, label=_('Password'), order=3, tooltip=_('Current (template) password of the user account'), required=True)
|
||||
userAccount = gui.TextField(
|
||||
length=64,
|
||||
label=_('Account'),
|
||||
order=2,
|
||||
tooltip=_('User account to change password'),
|
||||
required=True,
|
||||
)
|
||||
password = gui.PasswordField(
|
||||
length=64,
|
||||
label=_('Password'),
|
||||
order=3,
|
||||
tooltip=_('Current (template) password of the user account'),
|
||||
required=True,
|
||||
)
|
||||
|
||||
# Inherits base "onLogout"
|
||||
onLogout = WindowsOsManager.onLogout
|
||||
@ -74,55 +88,87 @@ class WinRandomPassManager(WindowsOsManager):
|
||||
super().__init__(environment, values)
|
||||
if values:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an user account!!!'))
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
_('Must provide an user account!!!')
|
||||
)
|
||||
if values['password'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a password for the account!!!'))
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
_('Must provide a password for the account!!!')
|
||||
)
|
||||
self._userAccount = values['userAccount']
|
||||
self._password = values['password']
|
||||
else:
|
||||
self._userAccount = ''
|
||||
self._password = ""
|
||||
|
||||
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
|
||||
def processUserPassword(
|
||||
self, userService: 'UserService', username: str, password: str
|
||||
) -> typing.Tuple[str, str]:
|
||||
if username == self._userAccount:
|
||||
password = userService.recoverValue('winOsRandomPass')
|
||||
|
||||
return WindowsOsManager.processUserPassword(self, userService, username, password)
|
||||
return WindowsOsManager.processUserPassword(
|
||||
self, userService, username, password
|
||||
)
|
||||
|
||||
def genPassword(self, userService: 'UserService'):
|
||||
randomPass = userService.recoverValue('winOsRandomPass')
|
||||
if not randomPass:
|
||||
# Generates a password that conforms to complexity
|
||||
rnd = random.SystemRandom()
|
||||
base = ''.join(rnd.choice(v) for v in (string.ascii_lowercase, string.ascii_uppercase, string.digits)) + rnd.choice('.+-')
|
||||
randomPass = ''.join(rnd.choice(string.ascii_letters + string.digits) for _ in range(12))
|
||||
base = ''.join(
|
||||
rnd.choice(v)
|
||||
for v in (string.ascii_lowercase, string.ascii_uppercase, string.digits)
|
||||
) + rnd.choice('.+-')
|
||||
randomPass = ''.join(
|
||||
rnd.choice(string.ascii_letters + string.digits) for _ in range(12)
|
||||
)
|
||||
pos = rnd.randrange(0, len(randomPass))
|
||||
randomPass = randomPass[:pos] + base + randomPass[pos:]
|
||||
userService.storeValue('winOsRandomPass', randomPass)
|
||||
log.doLog(userService, log.INFO, "Password set to \"{}\"".format(randomPass), log.OSMANAGER)
|
||||
log.doLog(
|
||||
userService,
|
||||
log.INFO,
|
||||
"Password set to \"{}\"".format(randomPass),
|
||||
log.OSMANAGER,
|
||||
)
|
||||
return randomPass
|
||||
|
||||
def actorData(self, userService: 'UserService') -> typing.MutableMapping[str, typing.Any]:
|
||||
def actorData(
|
||||
self, userService: 'UserService'
|
||||
) -> typing.MutableMapping[str, typing.Any]:
|
||||
return {
|
||||
'action': 'rename',
|
||||
'name': userService.getName(),
|
||||
'username': self._userAccount,
|
||||
'password': self._password,
|
||||
'new_password': self.genPassword(userService)
|
||||
'new_password': self.genPassword(userService),
|
||||
}
|
||||
|
||||
def infoVal(self, userService: 'UserService') -> str:
|
||||
return 'rename:{0}\t{1}\t{2}\t{3}'.format(self.getName(userService), self._userAccount, self._password, self.genPassword(userService))
|
||||
return 'rename:{0}\t{1}\t{2}\t{3}'.format(
|
||||
self.getName(userService),
|
||||
self._userAccount,
|
||||
self._password,
|
||||
self.genPassword(userService),
|
||||
)
|
||||
|
||||
def infoValue(self, userService: 'UserService') -> str:
|
||||
return 'rename\r{0}\t{1}\t{2}\t{3}'.format(self.getName(userService), self._userAccount, self._password, self.genPassword(userService))
|
||||
return 'rename\r{0}\t{1}\t{2}\t{3}'.format(
|
||||
self.getName(userService),
|
||||
self._userAccount,
|
||||
self._password,
|
||||
self.genPassword(userService),
|
||||
)
|
||||
|
||||
def marshal(self) -> bytes:
|
||||
'''
|
||||
Serializes the os manager data so we can store it in database
|
||||
'''
|
||||
base = codecs.encode(super().marshal(), 'hex').decode()
|
||||
return '\t'.join(['v1', self._userAccount, cryptoManager().encrypt(self._password), base]).encode('utf8')
|
||||
return '\t'.join(
|
||||
['v1', self._userAccount, cryptoManager().encrypt(self._password), base]
|
||||
).encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
values = data.decode('utf8').split('\t')
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -12,7 +12,7 @@
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
@ -53,7 +53,7 @@ def __init__():
|
||||
"""
|
||||
from uds.core import osmanagers
|
||||
|
||||
# Dinamycally import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
|
||||
# Dinamycally import children of this package.
|
||||
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
|
||||
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
@ -63,7 +63,7 @@ def __init__():
|
||||
importlib.invalidate_caches()
|
||||
|
||||
p = osmanagers.OSManager
|
||||
# This is marked as error in IDE, but it's not (__subclasses__)
|
||||
|
||||
for cls in p.__subclasses__():
|
||||
osmanagers.factory().insert(cls)
|
||||
|
||||
|
@ -32,7 +32,3 @@
|
||||
"""
|
||||
|
||||
from .provider import PhysicalMachinesProvider
|
||||
|
||||
# Now we use __subclasses__ method to locate Service Providers
|
||||
# and register them inside factory
|
||||
# ServiceProviderFactory.factory().insert(PhysicalMachinesProvider)
|
||||
|
@ -58,7 +58,7 @@ def __init__():
|
||||
"""
|
||||
from uds.core import services
|
||||
|
||||
# Dinamycally import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
|
||||
# Dinamycally import children of this package.
|
||||
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
# __import__('uds.services.' + name, globals(), locals(), [])
|
||||
|
Loading…
x
Reference in New Issue
Block a user