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

Adding support for returning back to cache

This commit is contained in:
Adolfo Gómez García 2024-09-02 18:55:12 +02:00
parent 0a39939659
commit 7c2a8168fa
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
5 changed files with 43 additions and 28 deletions

View File

@ -670,12 +670,9 @@ class Logout(ActorV3Action):
if userservice.in_use: # If already logged out, do not add a second logout (windows does this i.e.) 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) osmanagers.OSManager.logged_out(userservice, username)
if osmanager: # If does not have osmanager, or has osmanager and is removable, release it
if osmanager.is_removable_on_logout(userservice): if not osmanager or osmanager.is_removable_on_logout(userservice):
logger.debug('Removable on logout: %s', osmanager) UserServiceManager.manager().release_on_logout(userservice)
userservice.release()
else:
userservice.release()
def action(self) -> dict[str, typing.Any]: def action(self) -> dict[str, typing.Any]:
is_managed = self._params.get('type') != consts.actor.UNMANAGED is_managed = self._params.get('type') != consts.actor.UNMANAGED

View File

@ -302,24 +302,29 @@ class UserServiceManager(metaclass=singleton.Singleton):
# Data will be serialized on makeUnique process # Data will be serialized on makeUnique process
UserServiceOpChecker.make_unique(cache, cache_instance, state) UserServiceOpChecker.make_unique(cache, cache_instance, state)
def clone_userservice_as_cache(self, user_service: UserService) -> UserService: def forced_move_assigned_to_cache_l1(self, user_service: UserService) -> None:
""" """
Clones the record of a user service, cleaning up some fields so it's a cache element Clones the record of a user serviceself.
The uuid will be regenerated, and the pk will be set to None For this, the original userservice will ve moved to cache, and a new one will be created
to mark it as "REMOVED"
""" """
# Load as new variable to avoid modifying original # Load as new variable to avoid modifying original
user_service = UserService.objects.get(id=user_service.id) user_service_copy = UserService.objects.get(id=user_service.id)
user_service.pk = None user_service_copy.pk = None
user_service.uuid = generate_uuid() user_service_copy.uuid = generate_uuid()
user_service_copy.in_use = False
user_service_copy.state = State.REMOVED
user_service_copy.os_state = State.USABLE
# Save the new element, for reference
user_service_copy.save()
# Now, move the original to cache, but do it "hard" way, so we do not need to check for state
user_service.state = State.USABLE
user_service.os_state = State.USABLE
user_service.user = None user_service.user = None
user_service.cache_level = types.services.CacheLevel.L1 user_service.cache_level = types.services.CacheLevel.L1
user_service.in_use = False user_service.in_use = False
user_service.state = State.USABLE # We set it to usable so it can be used directly...
user_service.os_state = State.USABLE
# Save the new cache element
user_service.save()
return user_service
def get_cache_servicepool_stats(self, servicepool: ServicePool) -> 'types.services.ServicePoolStats': def get_cache_servicepool_stats(self, servicepool: ServicePool) -> 'types.services.ServicePoolStats':
""" """
@ -484,7 +489,7 @@ class UserServiceManager(metaclass=singleton.Singleton):
_('Can\'t remove nor cancel {} cause its state don\'t allow it').format(user_service.name) _('Can\'t remove nor cancel {} cause its state don\'t allow it').format(user_service.name)
) )
def release_on_logout(self, user_service: UserService) -> None: def release_on_logout(self, userservice: UserService) -> None:
""" """
In case of logout, this method will take care of removing the service In case of logout, this method will take care of removing the service
This is so because on logout, may the userservice returns back to cache if ower service This is so because on logout, may the userservice returns back to cache if ower service
@ -492,15 +497,19 @@ class UserServiceManager(metaclass=singleton.Singleton):
This method will take care of removing the service if no cache is desired of cache already full (on servicepool) This method will take care of removing the service if no cache is desired of cache already full (on servicepool)
""" """
stats = self.get_cache_servicepool_stats(user_service.deployed_service) if userservice.deployed_service.service.get_instance().allows_put_back_to_cache() is False:
userservice.release()
return
stats = self.get_cache_servicepool_stats(userservice.deployed_service)
# Note that only moves to cache L1 # Note that only moves to cache L1
# Also, we can get values for L2 cache, thats why we check L1 for overflow and needed # Also, we can get values for L2 cache, thats why we check L1 for overflow and needed
if stats.has_l1_cache_overflow(): if stats.has_l1_cache_overflow():
user_service.release() # Mark as removable userservice.release() # Mark as removable
elif stats.is_l1_cache_growth_required(): elif stats.is_l1_cache_growth_required():
# Move the clone of the user service to cache, and set our as REMOVED # Move the clone of the user service to cache, and set our as REMOVED
_cache = self.clone_userservice_as_cache(user_service) self.forced_move_assigned_to_cache_l1(userservice)
user_service.set_state(State.REMOVED) userservice.release(immediate=True)
def get_existing_assignation_for_user( def get_existing_assignation_for_user(
self, service_pool: ServicePool, user: User self, service_pool: ServicePool, user: User

View File

@ -252,7 +252,7 @@ class OSManager(Module):
This method: This method:
- Add log in event to stats - Add log in event to stats
- Sets service in use - Sets service in use
- Invokes userLoggedIn for user service instance - Invokes user_logged_in for user service instance
""" """
unique_id = userservice.unique_id unique_id = userservice.unique_id
userservice.set_in_use(True) userservice.set_in_use(True)
@ -308,7 +308,6 @@ class OSManager(Module):
This method: This method:
- Add log in event to stats - Add log in event to stats
- Sets service in use - 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 counter = int(typing.cast(str, p.get('logins_counter', 0))) - 1

View File

@ -269,6 +269,13 @@ class Service(Module):
""" """
return True return True
def allows_put_back_to_cache(self) -> bool:
"""
Returns if this service can be put back to cache. This is used to check if a service can be put back to cache
when the user logouts instead of being removed. By default, this method returns False.
"""
return False
def unmarshal(self, data: bytes) -> None: def unmarshal(self, data: bytes) -> None:
# In fact, we will not unmarshal anything here, but setup maxDeployed # In fact, we will not unmarshal anything here, but setup maxDeployed
# if services_limit exists and it is a gui.NumericField # if services_limit exists and it is a gui.NumericField

View File

@ -532,11 +532,14 @@ class UserService(UUIDModel, properties.PropertiesMixin):
def is_in_maintenance(self) -> bool: def is_in_maintenance(self) -> bool:
return self.deployed_service.is_in_maintenance() return self.deployed_service.is_in_maintenance()
def release(self) -> None: def release(self, immediate: bool = False) -> None:
""" """
Mark this user deployed service for removal. Mark this user deployed service for removal.
If from_logout is true, maybe the service can return to cache, else, it will be removed If from_logout is true, maybe the service can return to cache, else, it will be removed
""" """
if immediate:
self.set_state(State.REMOVED)
else:
self.set_state(State.REMOVABLE) self.set_state(State.REMOVABLE)
def cancel(self) -> None: def cancel(self) -> None: