def getAssignationForUser( self, servicePool: ServicePool, user: User ) -> typing.Optional[UserService]: # pylint: disable=too-many-branches if servicePool.service.getInstance().spawnsNew is False: assignedUserService = self.getExistingAssignationForUser( servicePool, user) else: assignedUserService = None # If has an assigned user service, returns this without any more work if assignedUserService: return assignedUserService if servicePool.isRestrained(): raise InvalidServiceException( _('The requested service is restrained')) cache: typing.Optional[UserService] = None # Now try to locate 1 from cache already "ready" (must be usable and at level 1) with transaction.atomic(): caches = typing.cast( typing.List[UserService], servicePool.cachedUserServices().select_for_update().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE, os_state=State.USABLE)[:1]) if caches: cache = caches[0] # Ensure element is reserved correctly on DB if servicePool.cachedUserServices().select_for_update().filter( user=None, uuid=typing.cast( UserService, cache).uuid).update( user=user, cache_level=0) != 1: cache = None else: cache = None # Out of previous atomic if not cache: with transaction.atomic(): caches = typing.cast( typing.List[UserService], servicePool.cachedUserServices().select_for_update(). filter(cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE)[:1]) if cache: cache = caches[0] if servicePool.cachedUserServices().select_for_update( ).filter(user=None, uuid=typing.cast(UserService, cache).uuid).update( user=user, cache_level=0) != 1: cache = None else: cache = None # Out of atomic transaction if cache: # Early assign cache.assignToUser(user) logger.debug( 'Found a cached-ready service from %s for user %s, item %s', servicePool, user, cache) events.addEvent(servicePool, events.ET_CACHE_HIT, fld1=servicePool.cachedUserServices().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE).count()) return cache # Cache missed # Now find if there is a preparing one with transaction.atomic(): caches = servicePool.cachedUserServices().select_for_update( ).filter(cache_level=services.UserDeployment.L1_CACHE, state=State.PREPARING)[:1] if caches: cache = caches[0] if servicePool.cachedUserServices().select_for_update().filter( user=None, uuid=typing.cast( UserService, cache).uuid).update( user=user, cache_level=0) != 1: cache = None else: cache = None # Out of atomic transaction if cache: cache.assignToUser(user) logger.debug( 'Found a cached-preparing service from %s for user %s, item %s', servicePool, user, cache) events.addEvent(servicePool, events.ET_CACHE_MISS, fld1=servicePool.cachedUserServices().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.PREPARING).count()) return cache # Can't assign directly from L2 cache... so we check if we can create e new service in the limits requested serviceType = servicePool.service.getType() if serviceType.usesCache: # inCacheL1 = ds.cachedUserServices().filter(UserServiceManager.getCacheStateFilter(services.UserDeployment.L1_CACHE)).count() inAssigned = servicePool.assignedUserServices().filter( UserServiceManager.getStateFilter()).count() # totalL1Assigned = inCacheL1 + inAssigned if inAssigned >= servicePool.max_srvs: # cacheUpdater will drop unnecesary L1 machines, so it's not neccesary to check against inCacheL1 log.doLog( servicePool, log.WARN, 'Max number of services reached: {}'.format( servicePool.max_srvs), log.INTERNAL) raise MaxServicesReachedError() # Can create new service, create it events.addEvent(servicePool, events.ET_CACHE_MISS, fld1=0) return self.createAssignedFor(servicePool, user)
def item_as_dict(self, item: ServicePool) -> typing.Dict[str, typing.Any]: summary = 'summarize' in self._params # if item does not have an associated service, hide it (the case, for example, for a removed service) # Access from dict will raise an exception, and item will be skipped poolGroupId: typing.Optional[str] = None poolGroupName: str = _('Default') poolGroupThumb: str = DEFAULT_THUMB_BASE64 if item.servicesPoolGroup: poolGroupId = item.servicesPoolGroup.uuid poolGroupName = item.servicesPoolGroup.name if item.servicesPoolGroup.image: poolGroupThumb = item.servicesPoolGroup.image.thumb64 state = item.state if item.isInMaintenance(): state = State.MAINTENANCE elif userServiceManager().canInitiateServiceFromDeployedService( item) is False: state = State.SLOWED_DOWN val = { 'id': item.uuid, 'name': item.name, 'short_name': item.short_name, 'tags': [tag.tag for tag in item.tags.all()], 'parent': item.service.name, 'parent_type': item.service.data_type, 'comments': item.comments, 'state': state, 'thumb': item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64, 'account': item.account.name if item.account is not None else '', 'account_id': item.account.uuid if item.account is not None else None, 'service_id': item.service.uuid, 'provider_id': item.service.provider.uuid, 'image_id': item.image.uuid if item.image is not None else None, 'initial_srvs': item.initial_srvs, 'cache_l1_srvs': item.cache_l1_srvs, 'cache_l2_srvs': item.cache_l2_srvs, 'max_srvs': item.max_srvs, 'show_transports': item.show_transports, 'visible': item.visible, 'allow_users_remove': item.allow_users_remove, 'allow_users_reset': item.allow_users_reset, 'ignores_unused': item.ignores_unused, 'fallbackAccess': item.fallbackAccess, 'meta_member': [{ 'id': i.uuid, 'name': i.name } for i in item.meta.all()], } # Extended info if not summary: state = item.state if item.isInMaintenance(): state = State.MAINTENANCE elif userServiceManager().canInitiateServiceFromDeployedService( item) is False: state = State.SLOWED_DOWN poolGroupId = None poolGroupName = _('Default') poolGroupThumb = DEFAULT_THUMB_BASE64 if item.servicesPoolGroup is not None: poolGroupId = item.servicesPoolGroup.uuid poolGroupName = item.servicesPoolGroup.name if item.servicesPoolGroup.image is not None: poolGroupThumb = item.servicesPoolGroup.image.thumb64 val['state'] = state val['thumb'] = item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64 val['user_services_count'] = item.userServices.exclude( state__in=State.INFO_STATES).count() val['user_services_in_preparation'] = item.userServices.filter( state=State.PREPARING).count() val['tags'] = [tag.tag for tag in item.tags.all()] val['restrained'] = item.isRestrained() val['permission'] = permissions.getEffectivePermission( self._user, item) val['info'] = Services.serviceInfo(item.service) val['pool_group_id'] = poolGroupId val['pool_group_name'] = poolGroupName val['pool_group_thumb'] = poolGroupThumb val['usage'] = item.usage() if item.osmanager: val['osmanager_id'] = item.osmanager.uuid return val