1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

more refactoring and fixes and tests...

This commit is contained in:
Adolfo Gómez García 2024-01-16 00:14:00 +01:00
parent d21f66408f
commit 9dbb47a4ad
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
29 changed files with 358 additions and 351 deletions

2
actor

@ -1 +1 @@
Subproject commit 0489009e08acfd59ec9936ab33457cb32151e11f
Subproject commit a7a2ff7cf60b5063a8b717a197ff25da2c130feb

View File

@ -74,7 +74,7 @@ class NotifyActionType(enum.StrEnum):
# Helpers
def fixIdsList(idsList: list[str]) -> list[str]:
def fix_list_of_ids(idsList: list[str]) -> list[str]:
"""
Params:
idsList: List of ids to fix
@ -151,7 +151,7 @@ class ActorV3Action(Handler):
}
)
def getUserService(self) -> UserService:
def get_userservice(self) -> UserService:
'''
Looks for an userService and, if not found, raises a exceptions.rest.BlockAccess request
'''
@ -179,7 +179,7 @@ class ActorV3Action(Handler):
raise exceptions.rest.AccessDenied('Access denied')
# Some helpers
def notifyService(self, action: NotifyActionType) -> None:
def notify_service(self, action: NotifyActionType) -> None:
try:
# If unmanaged, use Service locator
service: 'services.Service' = Service.objects.get(token=self._params['token']).get_instance()
@ -190,7 +190,7 @@ class ActorV3Action(Handler):
idsList = [x['ip'] for x in self._params['id']] + [x['mac'] for x in self._params['id']][:10]
# ensure idsLists has upper and lower versions for case sensitive databases
idsList = fixIdsList(idsList)
idsList = fix_list_of_ids(idsList)
validId: typing.Optional[str] = service.get_valid_id(idsList)
@ -430,7 +430,7 @@ class Initialize(ActorV3Action):
# Valid actor token, now validate access allowed. That is, look for a valid mac from the ones provided.
try:
# ensure idsLists has upper and lower versions for case sensitive databases
idsList = fixIdsList(idsList)
idsList = fix_list_of_ids(idsList)
# Set full filter
dbFilter = dbFilter.filter(
unique_id__in=idsList,
@ -446,7 +446,7 @@ class Initialize(ActorV3Action):
# Set last seen actor version
userService.actor_version = self._params['version']
osData: collections.abc.MutableMapping[str, typing.Any] = {}
osManager = userService.getOsManagerInstance()
osManager = userService.get_osmanager_instance()
if osManager:
osData = osManager.actor_data(userService)
@ -484,7 +484,7 @@ class BaseReadyChange(ActorV3Action):
}
"""
logger.debug('Args: %s, Params: %s', self._args, self._params)
userService = self.getUserService()
userService = self.get_userservice()
# Stores known IP and notifies it to deployment
userService.log_ip(self._params['ip'])
userServiceInstance = userService.get_instance()
@ -502,7 +502,7 @@ class BaseReadyChange(ActorV3Action):
if userService.os_state != State.USABLE:
userService.setOsState(State.USABLE)
# Notify osManager or readyness if has os manager
osManager = userService.getOsManagerInstance()
osManager = userService.get_osmanager_instance()
if osManager:
osManager.to_ready(userService)
@ -550,7 +550,7 @@ class Ready(BaseReadyChange):
result = super().action()
# Maybe we could also set as "inUse" to false because a ready can only ocurr if an user is not logged in
userService = self.getUserService()
userService = self.get_userservice()
userService.setInUse(False)
return result
@ -566,7 +566,7 @@ class Version(ActorV3Action):
def action(self) -> dict[str, typing.Any]:
logger.debug('Version Args: %s, Params: %s', self._args, self._params)
userService = self.getUserService()
userService = self.get_userservice()
userService.actor_version = self._params['version']
userService.log_ip(self._params['ip'])
@ -589,52 +589,53 @@ class Login(ActorV3Action):
# }
@staticmethod
def process_login(userService: UserService, username: str) -> typing.Optional[osmanagers.OSManager]:
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
if not userService.in_use: # If already logged in, do not add a second login (windows does this i.e.)
osmanagers.OSManager.logged_in(userService, username)
def process_login(userservice: UserService, username: str) -> typing.Optional[osmanagers.OSManager]:
osManager: typing.Optional[osmanagers.OSManager] = userservice.get_osmanager_instance()
if not userservice.in_use: # If already logged in, do not add a second login (windows does this i.e.)
osmanagers.OSManager.logged_in(userservice, username)
return osManager
def action(self) -> dict[str, typing.Any]:
isManaged = self._params.get('type') != consts.actor.UNMANAGED
src = types.connections.ConnectionSource('', '')
deadLine = maxIdle = None
deadline = max_idle = None
session_id = ''
logger.debug('Login Args: %s, Params: %s', self._args, self._params)
try:
userService: UserService = self.getUserService()
osManager = Login.process_login(userService, self._params.get('username') or '')
userservice: UserService = self.get_userservice()
os_manager = Login.process_login(userservice, self._params.get('username') or '')
maxIdle = osManager.max_idle() if osManager else None
max_idle = os_manager.max_idle() if os_manager else None
logger.debug('Max idle: %s', maxIdle)
logger.debug('Max idle: %s', max_idle)
src = userService.getConnectionSource()
session_id = userService.start_session() # creates a session for every login requested
src = userservice.getConnectionSource()
session_id = userservice.start_session() # creates a session for every login requested
if osManager: # For os managed services, let's check if we honor deadline
if osManager.ignore_deadline():
deadLine = userService.deployed_service.get_deadline()
if os_manager: # For os managed services, let's check if we honor deadline
if os_manager.ignore_deadline():
deadline = userservice.deployed_service.get_deadline()
else:
deadLine = None
deadline = None
else: # For non os manager machines, process deadline as always
deadLine = userService.deployed_service.get_deadline()
deadline = userservice.deployed_service.get_deadline()
except (
Exception
): # If unamanaged host, lest do a bit more work looking for a service with the provided parameters...
if isManaged:
raise
self.notifyService(action=NotifyActionType.LOGIN)
self.notify_service(action=NotifyActionType.LOGIN)
return ActorV3Action.actor_result(
{
'ip': src.ip,
'hostname': src.hostname,
'dead_line': deadLine,
'max_idle': maxIdle,
'dead_line': deadline, # Kept for compat, will be removed on 5.x
'deadline': deadline,
'max_idle': max_idle,
'session_id': session_id,
}
)
@ -648,41 +649,41 @@ class Logout(ActorV3Action):
name = 'logout'
@staticmethod
def process_logout(userService: UserService, username: str, session_id: str) -> None:
def process_logout(userservice: UserService, username: str, session_id: str) -> None:
"""
This method is static so can be invoked from elsewhere
"""
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
osManager: typing.Optional[osmanagers.OSManager] = userservice.get_osmanager_instance()
# Close session
# For compat, we have taken '' as "all sessions"
userService.end_session(session_id)
userservice.end_session(session_id)
if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
osmanagers.OSManager.logged_out(userService, username)
if userservice.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
osmanagers.OSManager.logged_out(userservice, username)
if osManager:
if osManager.is_removable_on_logout(userService):
if osManager.is_removable_on_logout(userservice):
logger.debug('Removable on logout: %s', osManager)
userService.remove()
userservice.remove()
else:
userService.remove()
userservice.remove()
def action(self) -> dict[str, typing.Any]:
isManaged = self._params.get('type') != consts.actor.UNMANAGED
is_managed = self._params.get('type') != consts.actor.UNMANAGED
logger.debug('Args: %s, Params: %s', self._args, self._params)
try:
userService: UserService = self.getUserService() # if not exists, will raise an error
userservice: UserService = self.get_userservice() # if not exists, will raise an error
Logout.process_logout(
userService,
userservice,
self._params.get('username') or '',
self._params.get('session_id') or '',
)
# If unamanaged host, lets do a bit more work looking for a service with the provided parameters...
except Exception:
if isManaged:
if is_managed:
raise
self.notifyService(NotifyActionType.LOGOUT) # Logout notification
self.notify_service(NotifyActionType.LOGOUT) # Logout notification
# Result is that we have not processed the logout in fact, but notified the service
return ActorV3Action.actor_result('notified')
@ -698,14 +699,14 @@ class Log(ActorV3Action):
def action(self) -> dict[str, typing.Any]:
logger.debug('Args: %s, Params: %s', self._args, self._params)
userService = self.getUserService()
if userService.actor_version < '4.0.0':
userservice = self.get_userservice()
if userservice.actor_version < '4.0.0':
# Adjust loglevel to own, we start on 10000 for OTHER, and received is 0 for OTHER
level = log.LogLevel.from_int(int(self._params['level']) + 10000)
else:
level = log.LogLevel.from_int(int(self._params['level']))
log.log(
userService,
userservice,
level,
self._params['message'],
log.LogSource.ACTOR,
@ -766,53 +767,53 @@ class Unmanaged(ActorV3Action):
# Build the possible ids and ask service if it recognizes any of it
# If not recognized, will generate anyway the certificate, but will not be saved
idsList = [x['ip'] for x in self._params['id']] + [x['mac'] for x in self._params['id']][:10]
validId: typing.Optional[str] = service.get_valid_id(idsList)
list_of_ids = [x['ip'] for x in self._params['id']] + [x['mac'] for x in self._params['id']][:10]
valid_id: typing.Optional[str] = service.get_valid_id(list_of_ids)
# ensure idsLists has upper and lower versions for case sensitive databases
idsList = fixIdsList(idsList)
list_of_ids = fix_list_of_ids(list_of_ids)
# Check if there is already an assigned user service
# To notify it logout
userService: typing.Optional[UserService]
userservice: typing.Optional[UserService]
try:
dbFilter = UserService.objects.filter(
unique_id__in=idsList,
db_filter = UserService.objects.filter(
unique_id__in=list_of_ids,
state__in=[State.USABLE, State.PREPARING],
)
userService = next(
userservice = next(
iter(
dbFilter.filter(
unique_id__in=idsList,
db_filter.filter(
unique_id__in=list_of_ids,
state__in=[State.USABLE, State.PREPARING],
)
)
)
except StopIteration:
userService = None
userservice = None
# Try to infer the ip from the valid id (that could be an IP or a MAC)
ip: str
try:
ip = next(x['ip'] for x in self._params['id'] if validId in (x['ip'], x['mac']))
ip = next(x['ip'] for x in self._params['id'] if valid_id in (x['ip'], x['mac']))
except StopIteration:
ip = self._params['id'][0]['ip'] # Get first IP if no valid ip found
# Generates a certificate and send it to client (actor).
privateKey, certificate, password = security.create_self_signed_cert(ip)
private_key, certificate, password = security.create_self_signed_cert(ip)
if validId:
if valid_id:
# If id is assigned to an user service, notify "logout" to it
if userService:
Logout.process_logout(userService, 'init', '')
if userservice:
Logout.process_logout(userservice, 'init', '')
else:
# If it is not assgined to an user service, notify service
service.notify_initialization(validId)
service.notify_initialization(valid_id)
# Store certificate, secret & port with service if validId
service.store_id_info(
validId,
valid_id,
{
'cert': certificate,
'secret': self._params['secret'],
@ -820,7 +821,7 @@ class Unmanaged(ActorV3Action):
},
)
return ActorV3Action.actorCertResult(privateKey, certificate, password)
return ActorV3Action.actorCertResult(private_key, certificate, password)
class Notify(ActorV3Action):
@ -847,7 +848,7 @@ class Notify(ActorV3Action):
elif action == NotifyActionType.LOGOUT:
Logout.action(typing.cast(Logout, self))
elif action == NotifyActionType.DATA:
self.notifyService(action)
self.notify_service(action)
return ActorV3Action.actor_result('ok')
except UserService.DoesNotExist:

View File

@ -347,7 +347,7 @@ class BaseModelHandler(Handler):
if isinstance(item, ManagedObjectModel):
i = item.get_instance()
i.init_gui() # Defaults & stuff
res.update(i.get_dict_of_values())
res.update(i.get_dict_of_fields_values())
return res
# Exceptions

View File

@ -276,7 +276,7 @@ class RegexLdap(auths.Authenticator):
def mfa_identifier(self, username: str) -> str:
return self.storage.get_unpickle(self.mfaStorageKey(username)) or ''
def get_dict_of_values(self) -> gui.ValuesDictType:
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
return {
'host': self._host,
'port': self._port,

View File

@ -241,7 +241,7 @@ class SimpleLDAPAuthenticator(auths.Authenticator):
self._verifySsl = gui.as_bool(values['verifySsl'])
self._certificate = values['certificate']
def get_dict_of_values(self) -> gui.ValuesDictType:
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
return {
'host': self._host,
'port': self._port,

View File

@ -75,7 +75,7 @@ def process_login(server: 'models.Server', data: dict[str, typing.Any]) -> typin
{
'ip': 'ip of connection origin',
'hostname': 'hostname of connection origin',
'dead_line': 'dead line of service', # The point in time when the service will be automatically removed, optional (None if not set)
'deadline': 'dead line of service', # The point in time when the service will be automatically removed, optional (None if not set)
'max_idle': 'max idle time of service', # The max time the service can be idle before being removed, optional (None if not set)
'session_id': 'session id', # The session id assigned to this login
'ticket': 'ticket if any' # optional
@ -99,7 +99,7 @@ def process_login(server: 'models.Server', data: dict[str, typing.Any]) -> typin
src = userService.getConnectionSource()
session_id = userService.start_session() # creates a session for every login requested
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
osManager: typing.Optional[osmanagers.OSManager] = userService.get_osmanager_instance()
maxIdle = osManager.max_idle() if osManager else None
logger.debug('Max idle: %s', maxIdle)
@ -111,7 +111,7 @@ def process_login(server: 'models.Server', data: dict[str, typing.Any]) -> typin
'ip': src.ip,
'hostname': src.hostname,
'session_id': session_id,
'dead_line': deadLine, # Can be None
'deadline': deadLine, # For compatibility with old clients
'max_idle': maxIdle, # Can be None
}
# If ticket is included, add it to result (the content of the ticket, not the ticket id itself)
@ -138,7 +138,7 @@ def process_logout(server: 'models.Server', data: dict[str, typing.Any]) -> typi
if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
osmanagers.OSManager.logged_out(userService, data['username'])
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
osManager: typing.Optional[osmanagers.OSManager] = userService.get_osmanager_instance()
if not osManager or osManager.is_removable_on_logout(userService):
logger.debug('Removable on logout: %s', osManager)
userService.remove()

View File

@ -66,8 +66,8 @@ class OSManager(Module):
icon_file = 'osmanager.png'
# If true, this os manager will be invoked with every user service assigned, but not used
# The interval is defined as a global config
processUnusedMachines: bool = False
# This is an object variable, so it can be overriden on derived classes on runtime
handles_unused_userservices: bool = False
# : Type of services for which this OS Manager is designed
# : Defaults to all. (list or tuple)
@ -93,7 +93,7 @@ class OSManager(Module):
Default implementation does nothing
"""
def release(self, userService: 'UserService') -> None:
def release(self, userservice: 'UserService') -> None:
"""
Called by a service that is in Usable state before destroying it so osmanager can release data associated with it
Only invoked for services that reach the state "removed"
@ -102,7 +102,7 @@ class OSManager(Module):
# These methods must be overriden
def actor_data(
self, userService: 'UserService' # pylint: disable=unused-argument
self, userservice: 'UserService' # pylint: disable=unused-argument
) -> collections.abc.MutableMapping[str, typing.Any]:
"""
This method provides information to actor, so actor can complete os configuration.
@ -144,7 +144,7 @@ class OSManager(Module):
"""
return {}
def check_state(self, userService: 'UserService') -> str: # pylint: disable=unused-argument
def check_state(self, userservice: 'UserService') -> str: # pylint: disable=unused-argument
"""
This method must be overriden so your os manager can respond to requests from system to the current state of the service
This method will be invoked when:
@ -157,13 +157,14 @@ class OSManager(Module):
"""
return State.FINISHED
def process_unused(self, userService: 'UserService') -> None:
def handle_unused(self, userservice: 'UserService') -> None:
"""
This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME
This function can update userService values. Normal operation will be remove machines if this state is not valid
"""
def is_removable_on_logout(self, userService: 'UserService') -> bool: # pylint: disable=unused-argument
pass
def is_removable_on_logout(self, userservice: 'UserService') -> bool: # pylint: disable=unused-argument
"""
If returns true, when actor notifies "logout", UDS will mark service for removal
can be overriden
@ -190,7 +191,7 @@ class OSManager(Module):
def process_user_password(
self,
userService: 'UserService', # pylint: disable=unused-argument
userservice: 'UserService', # pylint: disable=unused-argument
username: str,
password: str,
) -> tuple[str, str]:
@ -227,42 +228,42 @@ class OSManager(Module):
self.ready_notified(userService)
@staticmethod
def logged_in(userService: 'UserService', userName: typing.Optional[str] = None) -> None:
def logged_in(userservice: 'UserService', username: typing.Optional[str] = None) -> None:
"""
This method:
- Add log in event to stats
- Sets service in use
- Invokes userLoggedIn for user service instance
"""
uniqueId = userService.unique_id
userService.setInUse(True)
userService.properties['last_username'] = userName or 'unknown' # Store it for convenience
userServiceInstance = userService.get_instance()
userServiceInstance.user_logged_in(userName or 'unknown')
userService.update_data(userServiceInstance)
uniqueId = userservice.unique_id
userservice.setInUse(True)
userservice.properties['last_username'] = username or 'unknown' # Store it for convenience
userServiceInstance = userservice.get_instance()
userServiceInstance.user_logged_in(username or 'unknown')
userservice.update_data(userServiceInstance)
serviceIp = userServiceInstance.get_ip()
fullUserName = userService.user.pretty_name if userService.user else 'unknown'
fullUserName = userservice.user.pretty_name if userservice.user else 'unknown'
knownUserIP = userService.src_ip + ':' + userService.src_hostname
knownUserIP = userservice.src_ip + ':' + userservice.src_hostname
knownUserIP = knownUserIP if knownUserIP != ':' else 'unknown'
userName = userName or 'unknown'
username = username or 'unknown'
add_event(
userService.deployed_service,
userservice.deployed_service,
types.stats.EventType.LOGIN,
fld1=userName,
fld1=username,
fld2=knownUserIP,
fld3=serviceIp,
fld4=fullUserName,
)
log.log(
userService,
userservice,
log.LogLevel.INFO,
f'User {userName} has logged in',
f'User {username} has logged in',
log.LogSource.OSMANAGER,
)
@ -270,27 +271,27 @@ class OSManager(Module):
'login',
uniqueId,
serviceIp,
userName,
username,
knownUserIP,
fullUserName,
userService.friendly_name,
userService.deployed_service.name,
userservice.friendly_name,
userservice.deployed_service.name,
)
# Context makes a transaction, so we can use it to update the counter
with userService.properties as p:
with userservice.properties as p:
counter = int(typing.cast(str, p.get('logins_counter', 0))) + 1
p['logins_counter'] = counter
@staticmethod
def logged_out(userService: 'UserService', userName: typing.Optional[str] = None) -> None:
def logged_out(userservice: 'UserService', username: typing.Optional[str] = None) -> None:
"""
This method:
- Add log in event to stats
- Sets service in use
- Invokes userLoggedIn for user service instance
"""
with userService.properties as p:
with userservice.properties as p:
counter = int(typing.cast(str, p.get('logins_counter', 0))) - 1
if counter > 0:
counter -= 1
@ -299,49 +300,49 @@ class OSManager(Module):
if GlobalConfig.EXCLUSIVE_LOGOUT.as_bool(True) and counter > 0:
return
uniqueId = userService.unique_id
userService.setInUse(False)
userServiceInstance = userService.get_instance()
userServiceInstance.user_logged_out(userName or 'unknown')
userService.update_data(userServiceInstance)
unique_id = userservice.unique_id
userservice.setInUse(False)
user_service_instance = userservice.get_instance()
user_service_instance.user_logged_out(username or 'unknown')
userservice.update_data(user_service_instance)
serviceIp = userServiceInstance.get_ip()
service_ip = user_service_instance.get_ip()
fullUserName = userService.user.pretty_name if userService.user else 'unknown'
full_username = userservice.user.pretty_name if userservice.user else 'unknown'
knownUserIP = userService.src_ip + ':' + userService.src_hostname
knownUserIP = knownUserIP if knownUserIP != ':' else 'unknown'
known_user_ip = userservice.src_ip + ':' + userservice.src_hostname
known_user_ip = known_user_ip if known_user_ip != ':' else 'unknown'
userName = userName or 'unknown'
username = username or 'unknown'
add_event(
userService.deployed_service,
userservice.deployed_service,
types.stats.EventType.LOGOUT,
fld1=userName,
fld2=knownUserIP,
fld3=serviceIp,
fld4=fullUserName,
fld1=username,
fld2=known_user_ip,
fld3=service_ip,
fld4=full_username,
)
log.log(
userService,
userservice,
log.LogLevel.INFO,
f'User {userName} has logged out',
f'User {username} has logged out',
log.LogSource.OSMANAGER,
)
log.log_use(
'logout',
uniqueId,
serviceIp,
userName,
knownUserIP,
fullUserName,
userService.friendly_name,
userService.deployed_service.name,
unique_id,
service_ip,
username,
known_user_ip,
full_username,
userservice.friendly_name,
userservice.deployed_service.name,
)
def ready_notified(self, userService: 'UserService') -> None:
def ready_notified(self, userservice: 'UserService') -> None:
"""
Invoked by actor when userService is ready
"""

View File

@ -1387,7 +1387,7 @@ class UserInterface(metaclass=UserInterfaceAbstract):
of this posibility in a near version...
"""
def get_dict_of_values(self) -> gui.ValuesDictType:
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
"""
Returns own data needed for user interaction as a dict of key-names ->
values. The values returned must be strings.

View File

@ -47,10 +47,12 @@ from ldap import (
from django.utils.translation import gettext as _
from django.conf import settings
# So it is avaliable for importers
from ldap.ldapobject import LDAPObject
from uds.core.util import utils
logger = logging.getLogger(__name__)
LDAPResultType = collections.abc.MutableMapping[str, typing.Any]

View File

@ -78,13 +78,13 @@ class AssignedAndUnused(Job):
# If do not needs os manager, this is
if ds.osmanager:
osm = ds.osmanager.get_instance()
if osm.processUnusedMachines:
if osm.handles_unused_userservices:
logger.debug(
'Processing unused services for %s, %s', ds, ds.osmanager
)
for us in unusedMachines:
logger.debug('Found unused assigned service %s', us)
osm.process_unused(us)
osm.handle_unused(us)
else: # No os manager, simply remove unused services in specified time
for us in unusedMachines:
logger.debug(

View File

@ -57,7 +57,7 @@ def getSerializedFromManagedObject(
try:
obj = mod.get_instance()
gui = {i['name']: i['gui']['type'] for i in obj.gui_description()}
values = obj.get_dict_of_values()
values = obj.get_dict_of_fields_values()
# Remove password fields
for k, v in gui.items():
if v == 'password':

View File

@ -277,7 +277,7 @@ class UserService(UUIDModel, properties.PropertiesMixin):
self.update_data(si)
return self.unique_id
def storeValue(self, name: str, value: str) -> None:
def store_value(self, name: str, value: str) -> None:
"""
Stores a value inside custom storage
@ -288,7 +288,7 @@ class UserService(UUIDModel, properties.PropertiesMixin):
# Store value as a property
self.properties[name] = value
def recoverValue(self, name: str) -> str:
def recover_value(self, name: str) -> str:
"""
Recovers a value from custom storage
@ -346,7 +346,7 @@ class UserService(UUIDModel, properties.PropertiesMixin):
def getOsManager(self) -> typing.Optional['OSManager']:
return self.deployed_service.osmanager
def getOsManagerInstance(self) -> typing.Optional['osmanagers.OSManager']:
def get_osmanager_instance(self) -> typing.Optional['osmanagers.OSManager']:
osManager = self.getOsManager()
if osManager:
return osManager.get_instance()

View File

@ -111,30 +111,33 @@ class EmailNotifier(messaging.Notifier):
tab=_('SMTP Server'),
)
fromEmail = gui.TextField(
from_email = gui.TextField(
length=128,
label=_('From Email'),
order=11,
tooltip=_('Email address that will be used as sender'),
required=True,
tab=_('Config'),
stored_field_name='fromEmail'
)
toEmail = gui.TextField(
to_email = gui.TextField(
length=128,
label=_('To Email'),
order=12,
tooltip=_('Email address that will be used as recipient'),
required=True,
tab=_('Config'),
stored_field_name='toEmail'
)
enableHTML = gui.CheckBoxField(
enable_html = gui.CheckBoxField(
label=_('Enable HTML'),
order=13,
tooltip=_('Enable HTML in emails'),
default=True,
tab=_('Config'),
stored_field_name='enableHTML'
)
def initialize(self, values: 'Module.ValuesType' = None):
@ -160,8 +163,8 @@ class EmailNotifier(messaging.Notifier):
self.hostname.value = validators.validate_fqdn(host)
# now check from email and to email
self.fromEmail.value = validators.validate_email(self.fromEmail.value)
self.toEmail.value = validators.validate_email(self.toEmail.value)
self.from_email.value = validators.validate_email(self.from_email.value)
self.to_email.value = validators.validate_email(self.to_email.value)
# Done
@ -172,18 +175,18 @@ class EmailNotifier(messaging.Notifier):
# Create message container
msg = MIMEMultipart('alternative')
msg['Subject'] = f'{group} - {identificator}'
msg['From'] = self.fromEmail.value
msg['To'] = self.toEmail.value
msg['From'] = self.from_email.value
msg['To'] = self.to_email.value
part1 = MIMEText(message, 'plain')
part2 = MIMEText(message, 'html')
msg.attach(part1)
if self.enableHTML.value:
if self.enable_html.value:
msg.attach(part2)
smtp.sendmail(self.fromEmail.value, self.toEmail.value, msg.as_string())
smtp.sendmail(self.from_email.value, self.to_email.value, msg.as_string())
except smtplib.SMTPException as e:
logger.error('Error sending email: %s', e)

View File

@ -36,4 +36,4 @@ class TelegramReceiver(jobs.Job):
logger.error('Notifier %s is not a Telegram notifier', telegramDbNotifier.name)
continue
n.retrieveMessages()
n.retrieve_messages()

View File

@ -80,7 +80,7 @@ class TelegramNotifier(messaging.Notifier):
tab=_('Telegram'),
)
accessToken = gui.TextField(
access_token = gui.TextField(
length=64,
label=_('Access Token'),
order=2,
@ -88,6 +88,7 @@ class TelegramNotifier(messaging.Notifier):
required=True,
default='',
tab=_('Telegram'),
stored_field_name='accessToken',
)
# Secret key used to validate join and subscribe requests
@ -104,7 +105,7 @@ class TelegramNotifier(messaging.Notifier):
# The bot will allow commmand (/join {secret} or /subscribe {secret} and /leave or /unsubscribe) to subscribe and unsubscribe
# For this to work, we will process the message and check if it is a command from time to time
# This var defines the delay in secods between checks (1 hour by default, we do not need to check this every second)
checkDelay = gui.NumericField(
check_delay = gui.NumericField(
length=3,
label=_('Check delay'),
order=3,
@ -114,6 +115,7 @@ class TelegramNotifier(messaging.Notifier):
min_value=60,
max_value=86400,
tab=_('Telegram'),
stored_field_name='checkDelay',
)
def initialize(self, values: 'Module.ValuesType' = None):
@ -126,7 +128,7 @@ class TelegramNotifier(messaging.Notifier):
# check hostname for stmp server si valid and is in the right format
# that is a hostname or ip address with optional port
# if hostname is not valid, we will raise an exception
for i in (self.botname, self.accessToken, self.secret):
for i in (self.botname, self.access_token, self.secret):
s = i.as_clean_str()
if not s:
raise exceptions.validation.ValidationError(_('Invalid value for {}').format(i.label))
@ -139,54 +141,54 @@ class TelegramNotifier(messaging.Notifier):
def notify(self, group: str, identificator: str, level: messaging.LogLevel, message: str) -> None:
telegramMsg = f'{group} - {identificator} - {str(level)}: {message}'
logger.debug('Sending telegram message: %s', telegramMsg)
# load chatIds
chatIds = self.storage.get_unpickle('chatIds') or []
t = telegram.Telegram(self.accessToken.value, self.botname.value)
for chatId in chatIds:
# load chat_ids
chat_ids = self.storage.get_unpickle('chat_ids') or []
t = telegram.Telegram(self.access_token.value, self.botname.value)
for chatId in chat_ids:
with ignore_exceptions():
t.send_message(chatId, telegramMsg)
# Wait a bit, so we don't send more than 10 messages per second
time.sleep(0.1)
def subscribeUser(self, chatId: int) -> None:
def subscribe_user(self, chat_id: int) -> None:
# we do not expect to have a lot of users, so we will use a simple storage
# that holds a list of chatIds
chatIds = self.storage.get_unpickle('chatIds') or []
if chatId not in chatIds:
chatIds.append(chatId)
self.storage.put_pickle('chatIds', chatIds)
logger.info('User %s subscribed to notifications', chatId)
# that holds a list of chat_ids
chat_ids = self.storage.get_unpickle('chat_ids') or []
if chat_id not in chat_ids:
chat_ids.append(chat_id)
self.storage.put_pickle('chat_ids', chat_ids)
logger.info('User %s subscribed to notifications', chat_id)
def unsubscriteUser(self, chatId: int) -> None:
def unsubscrite_user(self, chatId: int) -> None:
# we do not expect to have a lot of users, so we will use a simple storage
# that holds a list of chatIds
chatIds = self.storage.get_unpickle('chatIds') or []
if chatId in chatIds:
chatIds.remove(chatId)
self.storage.put_pickle('chatIds', chatIds)
# that holds a list of chat_ids
chat_ids = self.storage.get_unpickle('chat_ids') or []
if chatId in chat_ids:
chat_ids.remove(chatId)
self.storage.put_pickle('chat_ids', chat_ids)
logger.info('User %s unsubscribed from notifications', chatId)
def retrieveMessages(self) -> None:
if not self.accessToken.value.strip():
def retrieve_messages(self) -> None:
if not self.access_token.value.strip():
return # no access token, no messages
# Time of last retrieve
lastCheck: typing.Optional[datetime.datetime] = self.storage.get_unpickle('lastCheck')
last_check: typing.Optional[datetime.datetime] = self.storage.get_unpickle('last_check')
now = sql_datetime()
# If last check is not set, we will set it to now
if lastCheck is None:
lastCheck = now - datetime.timedelta(seconds=self.checkDelay.as_int() + 1)
self.storage.put_pickle('lastCheck', lastCheck)
if last_check is None:
last_check = now - datetime.timedelta(seconds=self.check_delay.as_int() + 1)
self.storage.put_pickle('last_check', last_check)
# If not enough time has passed, we will not check
if lastCheck + datetime.timedelta(seconds=self.checkDelay.as_int()) > now:
if last_check + datetime.timedelta(seconds=self.check_delay.as_int()) > now:
return
# Update last check
self.storage.put_pickle('lastCheck', now)
self.storage.put_pickle('last_check', now)
lastOffset = self.storage.get_unpickle('lastOffset') or 0
t = telegram.Telegram(self.accessToken.value, last_offset=lastOffset)
last_offset = self.storage.get_unpickle('last_offset') or 0
t = telegram.Telegram(self.access_token.value, last_offset=last_offset)
with ignore_exceptions(): # In case getUpdates fails, ignore it
for update in t.get_updates():
# Process update
@ -202,9 +204,9 @@ class TelegramNotifier(messaging.Notifier):
'Invalid subscribe command received from telegram bot (invalid secret: %s)',
message,
)
self.subscribeUser(update.chat.id)
self.subscribe_user(update.chat.id)
t.send_message(update.chat.id, _('You have been subscribed to notifications'))
elif message in ('/leave', '/unsubscribe'):
self.unsubscriteUser(update.chat.id)
self.unsubscrite_user(update.chat.id)
t.send_message(update.chat.id, _('You have been unsubscribed from notifications'))
self.storage.put_pickle('lastOffset', t.lastOffset)
self.storage.put_pickle('last_offset', t.last_offset)

View File

@ -24,19 +24,19 @@ class From:
@dataclasses.dataclass
class Message:
chat: Chat
from_: From
src: From
date: int
text: str
@staticmethod
def from_dict(data: collections.abc.Mapping[str, typing.Any]) -> 'Message':
return Message(
Chat(
chat=Chat(
id=data['chat']['id'],
type=data['chat']['type'],
first_name=data['chat']['first_name'],
),
From(
src=From(
id=data['from']['id'],
is_bot=data['from']['is_bot'],
first_name=data['from']['first_name'],
@ -50,13 +50,13 @@ class Message:
class Telegram:
token: str
reqTimeout: int
lastOffset: int
req_timeout: int
last_offset: int
def __init__(self, token: str, last_offset: int = 0) -> None:
self.token = token
self.reqTimeout = 3 * 2 + 1
self.lastOffset = last_offset
self.req_timeout = 3 * 2 + 1
self.last_offset = last_offset
def request(
self,
@ -71,7 +71,7 @@ class Telegram:
if stream:
kwargs['stream'] = True
# If params has a timeout, use the max of that and our own timeout
timeout = max(params.get('timeout', 0), self.reqTimeout)
timeout = max(params.get('timeout', 0), self.req_timeout)
response = requests.get(
f'https://api.telegram.org/bot{self.token}/{method}',
timeout=timeout,
@ -83,10 +83,10 @@ class Telegram:
return self.request('send_message', {'chat_id': chat_id, 'text': text})
def get_updates(self, offset: int = 0, timeout: int = 0) -> collections.abc.Iterable[Message]:
self.lastOffset = offset or self.lastOffset
res = self.request('get_updates', {'offset': self.lastOffset, 'timeout': timeout}, stream=True)
self.last_offset = offset or self.last_offset
res = self.request('get_updates', {'offset': self.last_offset, 'timeout': timeout}, stream=True)
if res['ok'] and res['result']: # if ok and there are results
# Update the offset
self.lastOffset = res['result'][-1]['update_id'] + 1
self.last_offset = res['result'][-1]['update_id'] + 1
for update in res['result']:
yield Message.from_dict(update['message'])

View File

@ -88,7 +88,7 @@ class LinuxOsADManager(LinuxOsManager):
'Organizational unit where to add machines in domain (check it before using it). i.e.: ou=My Machines,dc=mydomain,dc=local'
),
)
clientSoftware = gui.ChoiceField(
client_software = gui.ChoiceField(
label=_('Client software'),
order=5,
tooltip=_('Use specific client software'),
@ -100,7 +100,7 @@ class LinuxOsADManager(LinuxOsManager):
tab=types.ui.Tab.ADVANCED,
default='automatically',
)
membershipSoftware = gui.ChoiceField(
membership_software = gui.ChoiceField(
label=_('Membership software'),
order=6,
tooltip=_('Use specific membership software'),
@ -112,7 +112,7 @@ class LinuxOsADManager(LinuxOsManager):
tab=types.ui.Tab.ADVANCED,
default='automatically',
)
removeOnExit = gui.CheckBoxField(
remove_on_exit = gui.CheckBoxField(
label=_('Machine clean'),
order=7,
tooltip=_(
@ -128,7 +128,7 @@ class LinuxOsADManager(LinuxOsManager):
tab=types.ui.Tab.ADVANCED,
default=True,
)
automaticIdMapping = gui.CheckBoxField(
automatic_id_mapping = gui.CheckBoxField(
label=_('Automatic ID mapping'),
order=9,
tooltip=_('If checked, automatic ID mapping'),
@ -136,10 +136,10 @@ class LinuxOsADManager(LinuxOsManager):
default=True,
)
# Inherits base "onLogout"
onLogout = LinuxOsManager.onLogout
# Inherits base "on_logout"
on_logout = LinuxOsManager.on_logout
idle = LinuxOsManager.idle
deadLine = LinuxOsManager.deadLine
deadline = LinuxOsManager.deadline
_domain: str
_ou: str
@ -154,6 +154,7 @@ class LinuxOsADManager(LinuxOsManager):
def __init__(self, environment: 'Environment', values: 'Module.ValuesType') -> None:
super().__init__(environment, values)
self._server_software = 'active-directory' # Currently, fixed value
if values:
if values['domain'] == '':
raise exceptions.validation.ValidationError(_('Must provide a domain!'))
@ -165,19 +166,17 @@ class LinuxOsADManager(LinuxOsManager):
self._account = values['account']
self._password = values['password']
self._ou = values['ou'].strip()
self._client_software = values['clientSoftware']
self._server_software = 'active-directory'
self._membership_software = values['membershipSoftware']
self._remove_on_exit = 'y' if values['removeOnExit'] else 'n'
self._client_software = values['client_software']
self._membership_software = values['membership_software']
self._remove_on_exit = 'y' if values['remove_on_exit'] else 'n'
self._ssl = 'y' if values['ssl'] else 'n'
self._automatic_id_mapping = 'y' if values['automaticIdMapping'] else 'n'
self._automatic_id_mapping = 'y' if values['automatic_id_mapping'] else 'n'
else:
self._domain = ''
self._account = ''
self._password = '' # nosec: no encoded password
self._ou = ''
self._client_software = ''
self._server_software = 'active-directory'
self._membership_software = ''
self._remove_on_exit = 'n'
self._ssl = 'n'
@ -238,16 +237,15 @@ class LinuxOsADManager(LinuxOsManager):
self._automatic_id_mapping = values[10]
super().unmarshal(codecs.decode(values[11].encode(), 'hex'))
def get_dict_of_values(self) -> gui.ValuesDictType:
dct = super().get_dict_of_values()
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
dct = super().get_dict_of_fields_values()
dct['domain'] = self._domain
dct['account'] = self._account
dct['password'] = self._password
dct['ou'] = self._ou
dct['clientSoftware'] = self._client_software
dct['serverSoftware'] = self._server_software
dct['membershipSoftware'] = self._membership_software
dct['removeOnExit'] = self._remove_on_exit == 'y'
dct['client_software'] = self._client_software
dct['membership_software'] = self._membership_software
dct['remove_on_exit'] = self._remove_on_exit == 'y'
dct['ssl'] = self._ssl == 'y'
dct['automaticIdMapping'] = self._automatic_id_mapping == 'y'
dct['automatic_id_mapping'] = self._automatic_id_mapping == 'y'
return dct

View File

@ -80,7 +80,7 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
tooltip=_('Password of the account'),
required=True,
)
clientSoftware = gui.ChoiceField(
client_software = gui.ChoiceField(
label=_('Client software'),
order=4,
tooltip=_('Use specific client software'),
@ -92,7 +92,7 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
tab=types.ui.Tab.ADVANCED,
default='automatically',
)
membershipSoftware = gui.ChoiceField(
membership_software = gui.ChoiceField(
label=_('Membership software'),
order=5,
tooltip=_('Use specific membership software'),
@ -104,7 +104,7 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
tab=types.ui.Tab.ADVANCED,
default='automatically',
)
removeOnExit = gui.CheckBoxField(
remove_on_exit = gui.CheckBoxField(
label=_('Machine clean'),
order=6,
tooltip=_(
@ -120,7 +120,7 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
tab=types.ui.Tab.ADVANCED,
default=True,
)
automaticIdMapping = gui.CheckBoxField(
automatic_id_mapping = gui.CheckBoxField(
label=_('Automatic ID mapping'),
order=8,
tooltip=_('If checked, automatic ID mapping'),
@ -129,9 +129,9 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
)
# Inherits base "fields"
onLogout = LinuxOsManager.onLogout
on_logout = LinuxOsManager.on_logout
idle = LinuxOsManager.idle
deadLine = LinuxOsManager.deadLine
deadline = LinuxOsManager.deadline
_domain: str
_account: str
@ -145,6 +145,7 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
def __init__(self, environment: 'Environment', values: 'Module.ValuesType') -> None:
super().__init__(environment, values)
self._server_software = 'ipa' # Currently fixed to IPA
if values:
if values['domain'] == '':
raise exceptions.validation.ValidationError(_('Must provide a domain!'))
@ -155,18 +156,16 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
self._domain = values['domain']
self._account = values['account']
self._password = values['password']
self._client_software = values['clientSoftware']
self._server_software = 'ipa'
self._membership_software = values['membershipSoftware']
self._remove_on_exit = 'y' if values['removeOnExit'] else 'n'
self._client_software = values['client_software']
self._membership_software = values['membership_software']
self._remove_on_exit = 'y' if values['remove_on_exit'] else 'n'
self._ssl = 'y' if values['ssl'] else 'n'
self._automatic_id_mapping = 'y' if values['automaticIdMapping'] else 'n'
self._automatic_id_mapping = 'y' if values['automatic_id_mapping'] else 'n'
else:
self._domain = ''
self._account = ''
self._password = '' # nosec: no encoded password
self._client_software = ''
self._server_software = 'ipa'
self._membership_software = ''
self._remove_on_exit = 'n'
self._ssl = 'n'
@ -224,15 +223,14 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
self._automatic_id_mapping = values[9]
super().unmarshal(codecs.decode(values[10].encode(), 'hex'))
def get_dict_of_values(self) -> gui.ValuesDictType:
dct = super().get_dict_of_values()
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
dct = super().get_dict_of_fields_values()
dct['domain'] = self._domain
dct['account'] = self._account
dct['password'] = self._password
dct['clientSoftware'] = self._client_software
dct['serverSoftware'] = self._server_software
dct['membershipSoftware'] = self._membership_software
dct['removeOnExit'] = self._remove_on_exit == 'y'
dct['client_software'] = self._client_software
dct['membership_software'] = self._membership_software
dct['remove_on_exit'] = self._remove_on_exit == 'y'
dct['ssl'] = self._ssl == 'y'
dct['automaticIdMapping'] = self._automatic_id_mapping == 'y'
dct['automatic_id_mapping'] = self._automatic_id_mapping == 'y'
return dct

View File

@ -59,7 +59,7 @@ class LinuxOsManager(osmanagers.OSManager):
servicesType = serviceTypes.VDI
onLogout = gui.ChoiceField(
on_logout = gui.ChoiceField(
label=_('Logout Action'),
order=10,
readonly=True,
@ -87,7 +87,7 @@ class LinuxOsManager(osmanagers.OSManager):
required=True,
)
deadLine = gui.CheckBoxField(
deadline = gui.CheckBoxField(
label=_('Calendar logout'),
order=90,
tooltip=_(
@ -99,29 +99,29 @@ class LinuxOsManager(osmanagers.OSManager):
_on_logout: str
_idle: int
_deadLine: bool
_deadline: bool
def _set_process_unused_machines(self) -> None:
self.processUnusedMachines = self._on_logout == 'remove'
def _flag_processes_unused_machines(self) -> None:
self.handles_unused_userservices = self._on_logout == 'remove'
def __init__(self, environment: 'Environment', values: 'Module.ValuesType') -> None:
super().__init__(environment, values)
if values is not None:
self._on_logout = values['onLogout']
self._on_logout = values['on_logout']
self._idle = int(values['idle'])
self._deadLine = gui.as_bool(values['deadLine'])
self._deadline = gui.as_bool(values['deadline'])
else:
self._on_logout = ''
self._idle = -1
self._deadLine = True
self._deadline = True
self._set_process_unused_machines()
self._flag_processes_unused_machines()
def release(self, userService: 'UserService') -> None:
pass
def ignore_deadline(self) -> bool:
return not self._deadLine
return not self._deadline
def is_removable_on_logout(self, userService: 'UserService') -> bool:
'''
@ -159,19 +159,19 @@ class LinuxOsManager(osmanagers.OSManager):
) -> collections.abc.MutableMapping[str, typing.Any]:
return {'action': 'rename', 'name': userService.get_name()} # No custom data
def process_unused(self, userService: 'UserService') -> None:
def handle_unused(self, userservice: 'UserService') -> None:
"""
This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME
This function can update userService values. Normal operation will be remove machines if this state is not valid
"""
if self.is_removable_on_logout(userService):
if self.is_removable_on_logout(userservice):
log.log(
userService,
userservice,
log.LogLevel.INFO,
'Unused user service for too long. Removing due to OS Manager parameters.',
log.LogSource.OSMANAGER,
)
userService.remove()
userservice.remove()
def is_persistent(self) -> bool:
return self._on_logout == 'keep-always'
@ -186,7 +186,7 @@ class LinuxOsManager(osmanagers.OSManager):
"""
if (
self._idle <= 0
): # or (settings.DEBUG is False and self._onLogout != 'remove'):
): # or (settings.DEBUG is False and self._on_logout != 'remove'):
return None
return self._idle
@ -196,29 +196,29 @@ class LinuxOsManager(osmanagers.OSManager):
Serializes the os manager data so we can store it in database
"""
return '\t'.join(
['v3', self._on_logout, str(self._idle), gui.from_bool(self._deadLine)]
['v3', self._on_logout, str(self._idle), gui.from_bool(self._deadline)]
).encode('utf8')
def unmarshal(self, data: bytes) -> None:
values = data.decode('utf8').split('\t')
self._idle = -1
self._deadLine = True
self._deadline = True
if values[0] == 'v1':
self._on_logout = values[1]
elif values[0] == 'v2':
self._on_logout, self._idle = values[1], int(values[2])
elif values[0] == 'v3':
self._on_logout, self._idle, self._deadLine = (
self._on_logout, self._idle, self._deadline = (
values[1],
int(values[2]),
gui.as_bool(values[3]),
)
self._set_process_unused_machines()
self._flag_processes_unused_machines()
def get_dict_of_values(self) -> gui.ValuesDictType:
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
return {
'onLogout': self._on_logout,
'on_logout': self._on_logout,
'idle': str(self._idle),
'deadLine': gui.from_bool(self._deadLine),
'deadline': gui.from_bool(self._deadline),
}

View File

@ -48,6 +48,8 @@ logger = logging.getLogger(__name__)
if typing.TYPE_CHECKING:
from uds.models.user_service import UserService
from uds.core.environment import Environment
from uds.core.module import Module
class LinuxRandomPassManager(LinuxOsManager):
@ -59,7 +61,7 @@ class LinuxRandomPassManager(LinuxOsManager):
icon_file = 'losmanager.png'
# Apart form data from linux os manager, we need also domain and credentials
userAccount = gui.TextField(
user_account = gui.TextField(
length=64,
label=_('Account'),
order=2,
@ -67,21 +69,21 @@ class LinuxRandomPassManager(LinuxOsManager):
required=True,
)
# Inherits base "onLogout"
onLogout = LinuxOsManager.onLogout
# Inherits base "on_logout"
on_logout = LinuxOsManager.on_logout
idle = LinuxOsManager.idle
deadLine = LinuxOsManager.deadLine
deadline = LinuxOsManager.deadline
_user_account: str
def __init__(self, environment, values):
def __init__(self, environment: 'Environment', values: 'Module.ValuesType') -> None:
super().__init__(environment, values)
if values is not None:
if values['userAccount'] == '':
if values['user_account'] == '':
raise exceptions.validation.ValidationError(
_('Must provide an user account!!!')
)
self._user_account = values['userAccount']
self._user_account = values['user_account']
else:
self._user_account = ''
@ -89,17 +91,17 @@ class LinuxRandomPassManager(LinuxOsManager):
self, userService: 'UserService', username: str, password: str
) -> tuple[str, str]:
if username == self._user_account:
return (username, userService.recoverValue('linOsRandomPass'))
return (username, userService.recover_value('linOsRandomPass'))
return username, password
def gen_random_password(self, service: 'UserService') -> str:
randomPass = service.recoverValue('linOsRandomPass')
randomPass = service.recover_value('linOsRandomPass')
if randomPass is None:
randomPass = ''.join(
random.SystemRandom().choice(string.ascii_letters + string.digits)
for _ in range(16)
)
service.storeValue('linOsRandomPass', randomPass)
service.store_value('linOsRandomPass', randomPass)
log.log(
service,
log.LogLevel.INFO,
@ -144,7 +146,7 @@ class LinuxRandomPassManager(LinuxOsManager):
self._user_account = values[1].decode()
LinuxOsManager.unmarshal(self, codecs.decode(values[2], 'hex'))
def get_dict_of_values(self) -> gui.ValuesDictType:
dic = LinuxOsManager.get_dict_of_values(self)
dic['userAccount'] = self._user_account
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
dic = LinuxOsManager.get_dict_of_fields_values(self)
dic['user_account'] = self._user_account
return dic

View File

@ -57,7 +57,7 @@ class TestOSManager(osmanagers.OSManager):
servicesType = types.services.ServiceType.VDI
onLogout = gui.ChoiceField(
on_logout = gui.ChoiceField(
label=_('Logout Action'),
order=10,
readonly=True,
@ -86,7 +86,7 @@ class TestOSManager(osmanagers.OSManager):
)
def initialize(self, values: 'Module.ValuesType'):
self.processUnusedMachines = True
self.handles_unused_userservices = True
def release(self, userService: 'UserService') -> None:
logger.debug('User service %s released', userService)
@ -96,8 +96,8 @@ class TestOSManager(osmanagers.OSManager):
Says if a machine is removable on logout
'''
if not userService.in_use:
if (self.onLogout.value == 'remove') or (
not userService.check_publication_validity() and self.onLogout.value == 'keep'
if (self.on_logout.value == 'remove') or (
not userService.check_publication_validity() and self.on_logout.value == 'keep'
):
return True
@ -127,22 +127,22 @@ class TestOSManager(osmanagers.OSManager):
) -> collections.abc.MutableMapping[str, typing.Any]:
return {'action': 'rename', 'name': userService.get_name()}
def process_unused(self, userService: 'UserService') -> None:
def handle_unused(self, userservice: 'UserService') -> None:
"""
This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME
This function can update userService values. Normal operation will be remove machines if this state is not valid
"""
if self.is_removable_on_logout(userService):
if self.is_removable_on_logout(userservice):
log.log(
userService,
userservice,
log.LogLevel.INFO,
'Unused user service for too long. Removing due to OS Manager parameters.',
log.LogSource.OSMANAGER,
)
userService.remove()
userservice.remove()
def is_persistent(self):
return self.onLogout.value == 'keep-always'
return self.on_logout.value == 'keep-always'
def check_state(self, userService: 'UserService') -> str:
logger.debug('Checking state for service %s', userService)
@ -154,7 +154,7 @@ class TestOSManager(osmanagers.OSManager):
"""
if (
self.idle.value <= 0
): # or (settings.DEBUG is False and self._onLogout != 'remove'):
): # or (settings.DEBUG is False and self.on_logout != 'remove'):
return None
return self.idle.value

View File

@ -50,7 +50,7 @@ class WindowsOsManager(osmanagers.OSManager):
icon_file = 'wosmanager.png'
servicesType = serviceTypes.VDI
onLogout = gui.ChoiceField(
on_logout = gui.ChoiceField(
label=_('Logout Action'),
order=10,
readonly=True,
@ -78,7 +78,7 @@ class WindowsOsManager(osmanagers.OSManager):
required=True,
)
deadLine = gui.CheckBoxField(
deadline = gui.CheckBoxField(
label=_('Calendar logout'),
order=90,
tooltip=_(
@ -106,21 +106,21 @@ class WindowsOsManager(osmanagers.OSManager):
)
return length
def __setProcessUnusedMachines(self):
self.processUnusedMachines = self._on_logout == 'remove'
def _set_handles_unused(self):
self.handles_unused_userservices = self._on_logout == 'remove'
def __init__(self, environment, values):
super().__init__(environment, values)
if values is not None:
self._on_logout = values['onLogout']
self._on_logout = values['on_logout']
self._idle = int(values['idle'])
self._deadline = gui.as_bool(values['deadLine'])
self._deadline = gui.as_bool(values['deadline'])
else:
self._on_logout = ''
self._idle = -1
self._deadline = True
self.__setProcessUnusedMachines()
self._set_handles_unused()
def is_removable_on_logout(self, userService: 'UserService') -> bool:
"""
@ -186,26 +186,26 @@ class WindowsOsManager(osmanagers.OSManager):
self, userService, username, password
)
def process_unused(self, userService: 'UserService') -> None:
def handle_unused(self, userservice: 'UserService') -> None:
"""
This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME
This function can update userService values. Normal operation will be remove machines if this state is not valid
"""
if self.is_removable_on_logout(userService):
if self.is_removable_on_logout(userservice):
log.log(
userService,
userservice,
log.LogLevel.INFO,
'Unused user service for too long. Removing due to OS Manager parameters.',
log.LogSource.OSMANAGER,
)
userService.remove()
userservice.remove()
def is_persistent(self):
return self._on_logout == 'keep-always'
def check_state(self, userService: 'UserService') -> str:
def check_state(self, userservice: 'UserService') -> str:
# will alway return true, because the check is done by an actor callback
logger.debug('Checking state for service %s', userService)
logger.debug('Checking state for service %s', userservice)
return State.RUNNING
def max_idle(self):
@ -214,7 +214,7 @@ class WindowsOsManager(osmanagers.OSManager):
"""
if (
self._idle <= 0
): # or (settings.DEBUG is False and self._onLogout != 'remove'):
): # or (settings.DEBUG is False and self._on_logout != 'remove'):
return None
return self._idle
@ -247,11 +247,11 @@ class WindowsOsManager(osmanagers.OSManager):
'Exception unmarshalling. Some values left as default ones'
)
self.__setProcessUnusedMachines()
self._set_handles_unused()
def get_dict_of_values(self) -> gui.ValuesDictType:
def get_dict_of_fields_values(self) -> 'gui.ValuesDictType':
return {
'onLogout': self._on_logout,
'on_logout': self._on_logout,
'idle': str(self._idle),
'deadLine': gui.from_bool(self._deadline),
'deadline': gui.from_bool(self._deadline),
}

View File

@ -101,7 +101,7 @@ class WinDomainOsManager(WindowsOsManager):
tooltip=_('Group to which add machines on creation. If empty, no group will be used.'),
tab=_('Advanced'),
)
removeOnExit = gui.CheckBoxField(
remove_on_exit = gui.CheckBoxField(
label=_('Machine clean'),
order=8,
tooltip=_(
@ -110,7 +110,7 @@ class WinDomainOsManager(WindowsOsManager):
tab=_('Advanced'),
default=True,
)
serverHint = gui.TextField(
server_hint = gui.TextField(
length=64,
label=_('Server Hint'),
order=9,
@ -125,10 +125,10 @@ class WinDomainOsManager(WindowsOsManager):
default=True,
)
# Inherits base "onLogout"
onLogout = WindowsOsManager.onLogout
# Inherits base "on_logout"
on_logout = WindowsOsManager.on_logout
idle = WindowsOsManager.idle
deadLine = WindowsOsManager.deadLine
deadline = WindowsOsManager.deadline
_domain: str
_ou: str
@ -157,9 +157,9 @@ class WinDomainOsManager(WindowsOsManager):
self._account = values['account']
self._password = values['password']
self._group = values['grp'].strip()
self._server_hint = values['serverHint'].strip()
self._server_hint = values['server_hint'].strip()
self._ssl = 'y' if values['ssl'] else 'n'
self._remove_on_exit = 'y' if values['removeOnExit'] else 'n'
self._remove_on_exit = 'y' if values['remove_on_exit'] else 'n'
else:
self._domain = ''
self._ou = ''
@ -176,7 +176,7 @@ class WinDomainOsManager(WindowsOsManager):
if self._ou.lower().find(lpath) == -1:
self._ou += ',' + lpath
def __getServerList(self) -> collections.abc.Iterable[tuple[str, int]]:
def _get_server_list(self) -> collections.abc.Iterable[tuple[str, int]]:
if self._server_hint != '':
yield (self._server_hint, 389)
@ -193,7 +193,7 @@ class WinDomainOsManager(WindowsOsManager):
):
yield (str(server.target)[:-1], server.port)
def __connectLdap(
def _connect_ldap(
self, servers: typing.Optional[collections.abc.Iterable[tuple[str, int]]] = None
) -> typing.Any:
"""
@ -203,7 +203,7 @@ class WinDomainOsManager(WindowsOsManager):
ldaputil.LDAPError
"""
if servers is None:
servers = self.__getServerList()
servers = self._get_server_list()
account = self._account
if account.find('@') == -1:
@ -229,7 +229,7 @@ class WinDomainOsManager(WindowsOsManager):
raise ldaputil.LDAPError(_str)
def __getGroup(self, ldapConnection: typing.Any) -> typing.Optional[str]:
def _get_group(self, ldapConnection: 'ldaputil.LDAPObject') -> typing.Optional[str]:
base = ','.join(['DC=' + i for i in self._domain.split('.')])
group = ldaputil.escape(self._group)
obj: typing.Optional[collections.abc.MutableMapping[str, typing.Any]]
@ -251,16 +251,16 @@ class WinDomainOsManager(WindowsOsManager):
return obj['dn'] # Returns the DN
def __getMachine(self, ldapConnection, machineName: str) -> typing.Optional[str]:
def _get_machine(self, ldap_connection: 'ldaputil.LDAPObject', machine_name: str) -> typing.Optional[str]:
# if self._ou:
# base = self._ou
# else:
base = ','.join(['DC=' + i for i in self._domain.split('.')])
fltr = f'(&(objectClass=computer)(sAMAccountName={ldaputil.escape(machineName)}$))'
fltr = f'(&(objectClass=computer)(sAMAccountName={ldaputil.escape(machine_name)}$))'
obj: typing.Optional[collections.abc.MutableMapping[str, typing.Any]]
try:
obj = next(ldaputil.as_dict(ldapConnection, base, fltr, ['dn'], sizeLimit=50))
obj = next(ldaputil.as_dict(ldap_connection, base, fltr, ['dn'], sizeLimit=50))
except StopIteration:
obj = None
@ -269,7 +269,7 @@ class WinDomainOsManager(WindowsOsManager):
return obj['dn'] # Returns the DN
def ready_notified(self, userService: 'UserService') -> None:
def ready_notified(self, userservice: 'UserService') -> None:
# No group to add
if self._group == '':
return
@ -280,16 +280,16 @@ class WinDomainOsManager(WindowsOsManager):
# The machine is on a AD for sure, and maybe they are not already sync
error: typing.Optional[str] = None
for s in self.__getServerList():
for s in self._get_server_list():
try:
ldapConnection = self.__connectLdap(servers=(s,))
ldap_connection = self._connect_ldap(servers=(s,))
machine = self.__getMachine(ldapConnection, userService.friendly_name)
group = self.__getGroup(ldapConnection)
machine = self._get_machine(ldap_connection, userservice.friendly_name)
group = self._get_group(ldap_connection)
# #
# Direct LDAP operation "modify", maybe this need to be added to ldaputil? :)
# #
ldapConnection.modify_s(
ldap_connection.modify_s(
group, ((ldap.MOD_ADD, 'member', [machine.encode()]),) # type: ignore # (valid)
) # @UndefinedVariable
error = None
@ -297,7 +297,7 @@ class WinDomainOsManager(WindowsOsManager):
except dns.resolver.NXDOMAIN: # No domain found, log it and pass
logger.warning('Could not find _ldap._tcp.%s', self._domain)
log.log(
userService,
userservice,
log.LogLevel.WARNING,
f'Could not remove machine from domain (_ldap._tcp.{self._domain} not found)',
log.LogSource.OSMANAGER,
@ -310,15 +310,15 @@ class WinDomainOsManager(WindowsOsManager):
logger.exception('Ldap Exception caught')
error = f'Could not add machine (invalid credentials? for {self._account})'
except Exception as e:
error = f'Could not add machine {userService.friendly_name} to group {self._group}: {e}'
error = f'Could not add machine {userservice.friendly_name} to group {self._group}: {e}'
# logger.exception('Ldap Exception caught')
if error:
log.log(userService, log.LogLevel.WARNING, error, log.LogSource.OSMANAGER)
log.log(userservice, log.LogLevel.WARNING, error, log.LogSource.OSMANAGER)
logger.error(error)
def release(self, userService: 'UserService') -> None:
super().release(userService)
def release(self, userservice: 'UserService') -> None:
super().release(userservice)
# If no removal requested, just return
if self._remove_on_exit != 'y':
@ -327,7 +327,7 @@ class WinDomainOsManager(WindowsOsManager):
if '.' not in self._domain:
# logger.info('Releasing from a not FQDN domain is not supported')
log.log(
userService,
userservice,
log.LogLevel.INFO,
"Removing a domain machine form a non FQDN domain is not supported.",
log.LogSource.OSMANAGER,
@ -335,11 +335,11 @@ class WinDomainOsManager(WindowsOsManager):
return
try:
ldapConnection = self.__connectLdap()
ldap_connection = self._connect_ldap()
except dns.resolver.NXDOMAIN: # No domain found, log it and pass
logger.warning('Could not find _ldap._tcp.%s', self._domain)
log.log(
userService,
userservice,
log.LogLevel.WARNING,
f'Could not remove machine from domain (_ldap._tcp.{self._domain} not found)',
log.LogSource.OSMANAGER,
@ -348,7 +348,7 @@ class WinDomainOsManager(WindowsOsManager):
except ldaputil.LDAPError as e:
# logger.exception('Ldap Exception caught')
log.log(
userService,
userservice,
log.LogLevel.WARNING,
f'Could not remove machine from domain ({e})',
log.LogSource.OSMANAGER,
@ -357,7 +357,7 @@ class WinDomainOsManager(WindowsOsManager):
except Exception as e:
# logger.exception('Exception caught')
log.log(
userService,
userservice,
log.LogLevel.WARNING,
f'Could not remove machine from domain ({e})',
log.LogSource.OSMANAGER,
@ -365,18 +365,18 @@ class WinDomainOsManager(WindowsOsManager):
return
try:
res = self.__getMachine(ldapConnection, userService.friendly_name)
res = self._get_machine(ldap_connection, userservice.friendly_name)
if res is None:
raise Exception(f'Machine {userService.friendly_name} not found on AD (permissions?)')
ldaputil.recursive_delete(ldapConnection, res)
raise Exception(f'Machine {userservice.friendly_name} not found on AD (permissions?)')
ldaputil.recursive_delete(ldap_connection, res)
except IndexError:
logger.error('Error deleting %s from BASE %s', userService.friendly_name, self._ou)
logger.error('Error deleting %s from BASE %s', userservice.friendly_name, self._ou)
except Exception:
logger.exception('Deleting from AD: ')
def check(self) -> str:
try:
ldapConnection = self.__connectLdap()
ldap_connection = self._connect_ldap()
except ldaputil.LDAPError as e:
return _('Check error: {}').format(e)
except dns.resolver.NXDOMAIN:
@ -388,13 +388,13 @@ class WinDomainOsManager(WindowsOsManager):
return str(e)
try:
ldapConnection.search_st(self._ou, ldap.SCOPE_BASE) # type: ignore # (valid)
ldap_connection.search_st(self._ou, ldap.SCOPE_BASE) # type: ignore # (valid)
except ldaputil.LDAPError as e:
return _('Check error: {}').format(e)
# Group
if self._group != '':
if self.__getGroup(ldapConnection) is None:
if self._get_group(ldap_connection) is None:
return _('Check Error: group "{}" not found (using "cn" to locate it)').format(self._group)
return _('Server check was successful')
@ -407,7 +407,7 @@ class WinDomainOsManager(WindowsOsManager):
logger.debug(wd)
try:
try:
ldapConnection = wd.__connectLdap()
ldap_connection = wd._connect_ldap()
except ldaputil.LDAPError as e:
return [False, _('Could not access AD using LDAP ({0})').format(e)]
@ -416,7 +416,7 @@ class WinDomainOsManager(WindowsOsManager):
ou = 'cn=Computers,dc=' + ',dc='.join(wd._domain.split('.'))
logger.info('Checking %s with ou %s', wd._domain, ou)
r = ldapConnection.search_st(ou, ldap.SCOPE_BASE) # type: ignore # (valid)
r = ldap_connection.search_st(ou, ldap.SCOPE_BASE) # type: ignore # (valid)
logger.info('Result of search: %s', r)
except ldaputil.LDAPError:
@ -437,10 +437,10 @@ class WinDomainOsManager(WindowsOsManager):
return [True, _("All parameters seem to work fine.")]
def actor_data(self, userService: 'UserService') -> collections.abc.MutableMapping[str, typing.Any]:
def actor_data(self, userservice: 'UserService') -> collections.abc.MutableMapping[str, typing.Any]:
return {
'action': 'rename_ad',
'name': userService.get_name(),
'name': userservice.get_name(),
# Repeat data, to keep compat with old versions of Actor
# Will be removed in a couple of versions
@ -503,14 +503,14 @@ class WinDomainOsManager(WindowsOsManager):
self._remove_on_exit = 'y'
super().unmarshal(codecs.decode(values[5].encode(), 'hex'))
def get_dict_of_values(self) -> gui.ValuesDictType:
dct = super().get_dict_of_values()
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
dct = super().get_dict_of_fields_values()
dct['domain'] = self._domain
dct['ou'] = self._ou
dct['account'] = self._account
dct['password'] = self._password
dct['grp'] = self._group
dct['serverHint'] = self._server_hint
dct['server_hint'] = self._server_hint
dct['ssl'] = self._ssl == 'y'
dct['removeOnExit'] = self._remove_on_exit == 'y'
dct['remove_on_exit'] = self._remove_on_exit == 'y'
return dct

View File

@ -63,7 +63,7 @@ class WinRandomPassManager(WindowsOsManager):
icon_file = 'wosmanager.png'
# Apart form data from windows os manager, we need also domain and credentials
userAccount = gui.TextField(
user_account = gui.TextField(
length=64,
label=_('Account'),
order=2,
@ -78,10 +78,10 @@ class WinRandomPassManager(WindowsOsManager):
required=True,
)
# Inherits base "onLogout"
onLogout = WindowsOsManager.onLogout
# Inherits base "on_logout"
on_logout = WindowsOsManager.on_logout
idle = WindowsOsManager.idle
deadLine = WindowsOsManager.deadLine
dead_line = WindowsOsManager.deadline
_user_account: str
_password: str
@ -103,12 +103,12 @@ class WinRandomPassManager(WindowsOsManager):
self, userService: 'UserService', username: str, password: str
) -> tuple[str, str]:
if username == self._user_account:
password = userService.recoverValue('winOsRandomPass')
password = userService.recover_value('winOsRandomPass')
return WindowsOsManager.process_user_password(self, userService, username, password)
def gen_random_password(self, userService: 'UserService'):
randomPass = userService.recoverValue('winOsRandomPass')
randomPass = userService.recover_value('winOsRandomPass')
if not randomPass:
# Generates a password that conforms to complexity
rnd = random.SystemRandom()
@ -118,7 +118,7 @@ class WinRandomPassManager(WindowsOsManager):
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)
userService.store_value('winOsRandomPass', randomPass)
log.log(
userService,
log.LogLevel.INFO,
@ -159,8 +159,8 @@ class WinRandomPassManager(WindowsOsManager):
self._password = CryptoManager().decrypt(values[2])
super().unmarshal(codecs.decode(values[3].encode(), 'hex'))
def get_dict_of_values(self) -> gui.ValuesDictType:
dic = super().get_dict_of_values()
dic['userAccount'] = self._user_account
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
dic = super().get_dict_of_fields_values()
dic['user_account'] = self._user_account
dic['password'] = self._password
return dic

View File

@ -189,7 +189,7 @@ class IPMachinesService(IPServiceBase):
def get_token(self):
return self._token or None
def get_dict_of_values(self) -> gui.ValuesDictType:
def get_dict_of_fields_values(self) -> gui.ValuesDictType:
ips = (i.split('~')[0] for i in self._ips)
return {
'ipList': ensure.is_list(ips),

View File

@ -70,7 +70,7 @@ class ServerEventsLoginLogoutTest(rest.test.RESTTestCase):
# {
# 'ip': src.ip,
# 'hostname': src.hostname,
# 'dead_line': deadLine,
# 'deadline': deadLine,
# 'max_idle': maxIdle,
# 'session_id': session_id,
# }

View File

@ -151,7 +151,7 @@ class UserinterfaceInternalTest(UDSTestCase):
def test_valuesDict(self):
ui = TestingUserInterface()
self.assertEqual(
ui.get_dict_of_values(),
ui.get_dict_of_fields_values(),
{
'str_field': DEFAULTS['str_field'],
'str_auto_field': DEFAULTS['str_auto_field'],

View File

@ -60,9 +60,9 @@ def createEmailNotifier(
)
instance.username.value = username or ''
instance.password.value = password or ''
instance.fromEmail.value = fromEmail or 'from@email.com'
instance.toEmail.value = toEmail or 'to@email.com'
instance.enableHTML.value = enableHtml
instance.from_email.value = fromEmail or 'from@email.com'
instance.to_email.value = toEmail or 'to@email.com'
instance.enable_html.value = enableHtml
instance.security.value = security or 'none'
# Save
notifier.data = instance.serialize()

View File

@ -90,7 +90,7 @@ def createOsManager() -> models.OSManager:
from uds.osmanagers.Test import TestOSManager
values: dict[str, typing.Any] = {
'onLogout': 'remove',
'on_logout': 'remove',
'idle': 300,
}
osmanager = models.OSManager.objects.create(