mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-24 21:34:41 +03:00
* Explained why stop shuld be ignored if no user service is found
* Small type checking addons * Added method to allow "check" the availability of a service, currently used before removal * Fixed removal so concurrent removal refers to real removals, not to marked for removal
This commit is contained in:
parent
6d873ceccd
commit
12e74c16b5
@ -80,7 +80,10 @@ class TunnelTicket(Handler):
|
||||
token = self._args[2][:48]
|
||||
if not models.TunnelToken.validateToken(token):
|
||||
if self._args[1][:4] == 'stop':
|
||||
# "Eat" invalid stop requests, because Applications does not like them
|
||||
# "Discard" invalid stop requests, because Applications does not like them.
|
||||
# RDS connections keep alive for a while after the application is finished,
|
||||
# Also, same tunnel can be used for multiple applications, so we need to
|
||||
# discard invalid stop requests. (because the data provided is also for "several" applications)")
|
||||
return {}
|
||||
logger.error('Invalid token %s from %s', token, self._request.ip)
|
||||
raise AccessDenied()
|
||||
|
@ -562,6 +562,7 @@ class UserServiceManager(metaclass=singleton.Singleton):
|
||||
)
|
||||
serviceInstance = servicePool.service.getInstance()
|
||||
if (
|
||||
serviceInstance.isAvailable() and
|
||||
removing >= serviceInstance.parent().getMaxRemovingServices()
|
||||
and serviceInstance.parent().getIgnoreLimits() is False
|
||||
):
|
||||
|
@ -243,6 +243,14 @@ class Service(Module):
|
||||
"""
|
||||
return self._provider
|
||||
|
||||
def isAvailable(self) -> bool:
|
||||
"""
|
||||
Returns if this service is reachable (that is, we can operate with it). This is used, for example, to check
|
||||
if a service is "operable" before removing an user service (that is, pass from "waiting for remove" to "removing")
|
||||
By default, this method returns True.
|
||||
"""
|
||||
return True
|
||||
|
||||
def requestServicesForAssignation(
|
||||
self, **kwargs
|
||||
) -> typing.Iterable[UserDeployment]:
|
||||
|
@ -93,4 +93,4 @@ class AssignedAndUnused(Job):
|
||||
logger.debug(
|
||||
'Found unused assigned service with no OS Manager %s', us
|
||||
)
|
||||
us.remove()
|
||||
us.release()
|
||||
|
@ -47,7 +47,7 @@ class HangedCleaner(Job):
|
||||
frecuency_cfg = GlobalConfig.MAX_INITIALIZING_TIME
|
||||
friendly_name = 'Hanged services checker'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
now = getSqlDatetime()
|
||||
since_state = now - timedelta(
|
||||
seconds=GlobalConfig.MAX_INITIALIZING_TIME.getInt()
|
||||
@ -111,7 +111,7 @@ class HangedCleaner(Job):
|
||||
us.friendly_name
|
||||
),
|
||||
)
|
||||
us.remove() # Mark it again as removable, and let's see
|
||||
us.release() # Mark it again as removable, and let's see
|
||||
else:
|
||||
log.doLog(
|
||||
us,
|
||||
@ -126,4 +126,4 @@ class HangedCleaner(Job):
|
||||
us.friendly_name
|
||||
),
|
||||
)
|
||||
us.removeOrCancel()
|
||||
us.releaseOrCancel()
|
||||
|
@ -50,7 +50,7 @@ class PublicationInfoItemsCleaner(Job):
|
||||
) # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
|
||||
friendly_name = 'Publications Info Cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
removeFrom = getSqlDatetime() - timedelta(
|
||||
seconds=GlobalConfig.KEEP_INFO_TIME.getInt(True)
|
||||
)
|
||||
@ -66,7 +66,7 @@ class PublicationCleaner(Job):
|
||||
) # Request run publication "removal" every configued seconds. If config value is changed, it will be used at next reload
|
||||
friendly_name = 'Publication Cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
removables: typing.Iterable[
|
||||
ServicePoolPublication
|
||||
] = ServicePoolPublication.objects.filter(
|
||||
|
@ -43,7 +43,7 @@ class ScheduledAction(Job):
|
||||
frecuency = 29 # Frecuncy for this job
|
||||
friendly_name = 'Scheduled action runner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
configuredAction: CalendarAction
|
||||
for configuredAction in CalendarAction.objects.filter(
|
||||
service_pool__service__provider__maintenance_mode=False, # Avoid maintenance
|
||||
|
@ -52,7 +52,7 @@ class SchedulerHousekeeping(Job):
|
||||
frecuency = 301 # Frecuncy for this job
|
||||
friendly_name = 'Scheduler house keeping'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Look for "hanged" scheduler tasks and reschedule them
|
||||
"""
|
||||
|
@ -49,7 +49,7 @@ class DeployedServiceInfoItemsCleaner(Job):
|
||||
) # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
|
||||
friendly_name = 'Deployed Service Info Cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
removeFrom = getSqlDatetime() - timedelta(
|
||||
seconds=GlobalConfig.KEEP_INFO_TIME.getInt()
|
||||
)
|
||||
@ -65,10 +65,10 @@ class DeployedServiceRemover(Job):
|
||||
) # Request run publication "removal" every configued seconds. If config value is changed, it will be used at next reload
|
||||
friendly_name = 'Deployed Service Cleaner'
|
||||
|
||||
def startRemovalOf(self, servicePool: ServicePool):
|
||||
def startRemovalOf(self, servicePool: ServicePool) -> None:
|
||||
if (
|
||||
servicePool.service is None
|
||||
): # Maybe an inconsistent value? (must not, but if no ref integrity in db, maybe someone "touched.. ;)")
|
||||
): # Maybe an inconsistent value? (must not, but if no ref integrity in db, maybe someone hand-changed something.. ;)")
|
||||
logger.error('Found service pool %s without service', servicePool.name)
|
||||
servicePool.delete() # Just remove it "a las bravas", the best we can do
|
||||
return
|
||||
@ -91,8 +91,11 @@ class DeployedServiceRemover(Job):
|
||||
servicePool.name += ' (removed)'
|
||||
servicePool.save()
|
||||
|
||||
def continueRemovalOf(self, servicePool: ServicePool):
|
||||
# Recheck that there is no publication created in "bad moment"
|
||||
def continueRemovalOf(self, servicePool: ServicePool) -> None:
|
||||
# get current time
|
||||
now = getSqlDatetime()
|
||||
|
||||
# Recheck that there is no publication created just after "startRemovalOf"
|
||||
try:
|
||||
for pub in servicePool.publications.filter(state=State.PREPARING):
|
||||
pub.cancel()
|
||||
@ -116,9 +119,7 @@ class DeployedServiceRemover(Job):
|
||||
state__in=State.INFO_STATES
|
||||
).delete()
|
||||
|
||||
# Mark usable user services as removable
|
||||
now = getSqlDatetime()
|
||||
|
||||
# Mark usable user services as removable, as batch
|
||||
with transaction.atomic():
|
||||
servicePool.userServices.select_for_update().filter(
|
||||
state=State.USABLE
|
||||
@ -143,7 +144,7 @@ class DeployedServiceRemover(Job):
|
||||
except Exception:
|
||||
logger.exception('Cought unexpected exception at continueRemovalOf: ')
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
# First check if there is someone in "removable" estate
|
||||
removableServicePools: typing.Iterable[
|
||||
ServicePool
|
||||
|
@ -360,7 +360,7 @@ class ServiceCacheUpdater(Job):
|
||||
cache: UserService = cacheItems[0] # type: ignore # Slicing is not supported by pylance right now
|
||||
cache.removeOrCancel()
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
logger.debug('Starting cache checking')
|
||||
# We need to get
|
||||
servicesThatNeedsUpdate = self.servicesPoolsNeedingCacheUpdate()
|
||||
|
@ -50,7 +50,7 @@ class DeployedServiceStatsCollector(Job):
|
||||
frecuency = 599 # Once every ten minutes, 601 is prime, 599 also is prime, i like primes... :)
|
||||
friendly_name = 'Deployed Service Stats'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
logger.debug('Starting Deployed service stats collector')
|
||||
|
||||
servicePoolsToCheck: typing.Iterable[ServicePool] = ServicePool.objects.filter(
|
||||
|
@ -56,7 +56,7 @@ class StuckCleaner(Job):
|
||||
frecuency = 3601 * 8 # Executes Once a day
|
||||
friendly_name = 'Stuck States cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
since_state: datetime = getSqlDatetime() - timedelta(seconds=MAX_STUCK_TIME)
|
||||
# Filter for locating machine stuck on removing, cancelling, etc..
|
||||
# Locate service pools with pending assigned service in use
|
||||
|
@ -47,7 +47,7 @@ class CacheCleaner(Job):
|
||||
frecuency = 3600 * 24 # Once a day
|
||||
friendly_name = 'Utility Cache Cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
logger.debug('Starting cache cleanup')
|
||||
Cache.cleanUp()
|
||||
logger.debug('Done cache cleanup')
|
||||
@ -58,7 +58,7 @@ class TicketStoreCleaner(Job):
|
||||
frecuency = 60 # every minute (60 seconds)
|
||||
friendly_name = 'Ticket Storage Cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
logger.debug('Starting ticket storage cleanup')
|
||||
TicketStore.cleanup()
|
||||
logger.debug('Done ticket storage cleanup')
|
||||
@ -69,7 +69,7 @@ class SessionsCleaner(Job):
|
||||
frecuency = 3600 * 24 * 7 # Once a week will be enough
|
||||
friendly_name = 'User Sessions cleaner'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
logger.debug('Starting session cleanup')
|
||||
try:
|
||||
engine: typing.Any = import_module(settings.SESSION_ENGINE)
|
||||
|
@ -43,7 +43,7 @@ class UsageAccounting(Job):
|
||||
frecuency = 60
|
||||
friendly_name = 'Usage Accounting update'
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
with transaction.atomic():
|
||||
AccountUsage.objects.select_for_update().filter(
|
||||
user_service__in_use=True
|
||||
|
@ -88,12 +88,16 @@ class UserServiceRemover(Job):
|
||||
state=State.REMOVABLE,
|
||||
state_date__lt=removeFrom,
|
||||
deployed_service__service__provider__maintenance_mode=False,
|
||||
)[
|
||||
0:removeAtOnce # type: ignore # Slicing is not supported by pylance right now
|
||||
].iterator()
|
||||
).iterator(chunk_size=removeAtOnce)
|
||||
|
||||
manager = managers.userServiceManager()
|
||||
for removableUserService in removableUserServices:
|
||||
# if removal limit is reached, we stop
|
||||
if removeAtOnce <= 0:
|
||||
break
|
||||
# decrease how many we can remove
|
||||
removeAtOnce -= 1
|
||||
|
||||
logger.debug('Checking removal of %s', removableUserService.name)
|
||||
try:
|
||||
if manager.canRemoveServiceFromDeployedService(
|
||||
|
@ -506,6 +506,12 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
|
||||
else:
|
||||
self.cancel()
|
||||
|
||||
def releaseOrCancel(self) -> None:
|
||||
"""
|
||||
A much more convenient method name that "removeOrCancel" (i think :) )
|
||||
"""
|
||||
self.removeOrCancel()
|
||||
|
||||
def moveToLevel(self, cacheLevel: int) -> None:
|
||||
"""
|
||||
Moves cache items betwen levels, managed directly
|
||||
|
Loading…
Reference in New Issue
Block a user