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

Added functionalty so Fixed Services (at least those derived from Generic one), overrides the max_countent.... because must be always CONSERVATIVE in order to work correctly

This commit is contained in:
Adolfo Gómez García 2024-10-16 18:04:06 +02:00
parent 418e1f7c0b
commit a318e8ca2b
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
7 changed files with 89 additions and 46 deletions

View File

@ -68,12 +68,13 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
@staticmethod @staticmethod
def service_info(item: models.Service) -> dict[str, typing.Any]: def service_info(item: models.Service) -> dict[str, typing.Any]:
info = item.get_type() info = item.get_type()
overrided_fields = info.overrided_pools_fields or {}
return { return {
'icon': info.icon64().replace('\n', ''), 'icon': info.icon64().replace('\n', ''),
'needs_publication': info.publication_type is not None, 'needs_publication': info.publication_type is not None,
'max_deployed': info.userservices_limit, 'max_deployed': info.userservices_limit,
'uses_cache': info.uses_cache and info.overrided_fields is None, 'uses_cache': info.uses_cache and overrided_fields.get('uses_cache', True),
'uses_cache_l2': info.uses_cache_l2, 'uses_cache_l2': info.uses_cache_l2,
'cache_tooltip': _(info.cache_tooltip), 'cache_tooltip': _(info.cache_tooltip),
'cache_tooltip_l2': _(info.cache_tooltip_l2), 'cache_tooltip_l2': _(info.cache_tooltip_l2),
@ -144,7 +145,16 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
# Extract item db fields # Extract item db fields
# We need this fields for all # We need this fields for all
logger.debug('Saving service for %s / %s', parent, item) logger.debug('Saving service for %s / %s', parent, item)
fields = self.fields_from_params(['name', 'comments', 'data_type', 'tags', 'max_services_count_type'])
# Get the sevice type as first step, to obtain "overrided_fields" and other info
service_type = parent.get_instance().get_service_by_type(self._params['data_type'])
if not service_type:
raise exceptions.rest.RequestError('Service type not found')
fields = self.fields_from_params(
['name', 'comments', 'data_type', 'tags', 'max_services_count_type'],
defaults=service_type.overrided_fields,
)
# Fix max_services_count_type to ServicesCountingType enum or ServicesCountingType.STANDARD if not found # Fix max_services_count_type to ServicesCountingType enum or ServicesCountingType.STANDARD if not found
try: try:
fields['max_services_count_type'] = types.services.ServicesCountingType.from_int( fields['max_services_count_type'] = types.services.ServicesCountingType.from_int(
@ -304,10 +314,14 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
}, },
) )
# Remove all overrided fields from editables
overrided_fields = service.overrided_fields or {}
local_gui = [field_gui for field_gui in local_gui if field_gui['name'] not in overrided_fields]
return local_gui return local_gui
except Exception as e: except Exception as e:
logger.exception('getGui') logger.exception('get_gui')
raise exceptions.rest.ResponseError(str(e)) from e raise exceptions.rest.ResponseError(str(e)) from e
def get_logs(self, parent: 'Model', item: str) -> list[typing.Any]: def get_logs(self, parent: 'Model', item: str) -> list[typing.Any]:

View File

@ -511,8 +511,8 @@ class ServicesPools(ModelHandler):
del fields['osmanager_id'] del fields['osmanager_id']
# If service has "overrided fields", overwrite received ones now # If service has "overrided fields", overwrite received ones now
if service_type.overrided_fields: if service_type.overrided_pools_fields:
for k, v in service_type.overrided_fields.items(): for k, v in service_type.overrided_pools_fields.items():
fields[k] = v fields[k] = v
if service_type.uses_cache_l2 is False: if service_type.uses_cache_l2 is False:

View File

@ -294,7 +294,9 @@ class BaseModelHandler(Handler):
'subtitle': subtitle or '', 'subtitle': subtitle or '',
} }
def fields_from_params(self, fields_list: list[str]) -> dict[str, typing.Any]: def fields_from_params(
self, fields_list: list[str], *, defaults: 'dict[str, typing.Any]|None' = None
) -> dict[str, typing.Any]:
""" """
Reads the indicated fields from the parameters received, and if Reads the indicated fields from the parameters received, and if
:param fields_list: List of required fields :param fields_list: List of required fields
@ -313,7 +315,14 @@ class BaseModelHandler(Handler):
continue continue
args[k] = self._params.get(k, default) args[k] = self._params.get(k, default)
else: else:
try:
args[key] = self._params[key] args[key] = self._params[key]
except KeyError:
if defaults is not None and key in defaults:
args[key] = defaults[key]
else:
raise
# del self._params[key] # del self._params[key]
except KeyError as e: except KeyError as e:
raise exceptions.rest.RequestError(f'needed parameter not found in data {e}') raise exceptions.rest.RequestError(f'needed parameter not found in data {e}')

View File

@ -146,33 +146,29 @@ class DetailHandler(BaseModelHandler):
return r return r
if num_args == 1: if num_args == 1:
if self._args[0] == consts.rest.OVERVIEW: match self._args[0]:
case consts.rest.OVERVIEW:
return self.get_items(parent, None) return self.get_items(parent, None)
# if self._args[0] == GUI: case consts.rest.TYPES:
# gui = self.get_gui(parent, None)
# return sorted(gui, key=lambda f: f['gui']['order'])
if self._args[0] == consts.rest.TYPES:
types_ = self.get_types(parent, None) types_ = self.get_types(parent, None)
logger.debug('Types: %s', types_) logger.debug('Types: %s', types_)
return types_ return types_
if self._args[0] == consts.rest.GUI: case consts.rest.TABLEINFO:
# Gui without type, valid
gui = self.get_gui(parent, '') # No type
return sorted(gui, key=lambda f: f['gui']['order'])
if self._args[0] == consts.rest.TABLEINFO:
return self.process_table_fields( return self.process_table_fields(
self.get_title(parent), self.get_title(parent),
self.get_fields(parent), self.get_fields(parent),
self.get_row_style(parent), self.get_row_style(parent),
) )
case consts.rest.GUI: # Used on some cases to get the gui for a detail with no subtypes
gui = self.get_processed_gui(parent, '')
return sorted(gui, key=lambda f: f['gui']['order'])
case _:
# try to get id # try to get id
return self.get_items(parent, process_uuid(self._args[0])) return self.get_items(parent, process_uuid(self._args[0]))
if num_args == 2: if num_args == 2:
if self._args[0] == consts.rest.GUI: if self._args[0] == consts.rest.GUI:
gui = self.get_gui(parent, self._args[1]) return self.get_processed_gui(parent, self._args[1])
return sorted(gui, key=lambda f: f['gui']['order'])
if self._args[0] == consts.rest.TYPES: if self._args[0] == consts.rest.TYPES:
types_ = self.get_types(parent, self._args[1]) types_ = self.get_types(parent, self._args[1])
logger.debug('Types: %s', types_) logger.debug('Types: %s', types_)
@ -180,10 +176,12 @@ class DetailHandler(BaseModelHandler):
if self._args[1] == consts.rest.LOG: if self._args[1] == consts.rest.LOG:
return self.get_logs(parent, self._args[0]) return self.get_logs(parent, self._args[0])
# Maybe a custom method?
r = self._check_is_custom_method(self._args[1], parent, self._args[0]) r = self._check_is_custom_method(self._args[1], parent, self._args[0])
if r is not None: if r is not None:
return r return r
# Not understood, fallback, maybe the derived class can understand it
return self.fallback_get() return self.fallback_get()
def put(self) -> typing.Any: def put(self) -> typing.Any:
@ -330,6 +328,10 @@ class DetailHandler(BaseModelHandler):
# raise RequestError('Gui not provided for this type of object') # raise RequestError('Gui not provided for this type of object')
return [] return []
def get_processed_gui(self, parent: models.Model, for_type: str) -> collections.abc.Iterable[typing.Any]:
gui = self.get_gui(parent, for_type)
return sorted(gui, key=lambda f: f['gui']['order'])
def get_types( def get_types(
self, parent: models.Model, for_type: typing.Optional[str] self, parent: models.Model, for_type: typing.Optional[str]
) -> collections.abc.Iterable[types.rest.TypeInfoDict]: ) -> collections.abc.Iterable[types.rest.TypeInfoDict]:

View File

@ -72,9 +72,6 @@ class UserServiceManager(metaclass=singleton.Singleton):
def manager() -> 'UserServiceManager': def manager() -> 'UserServiceManager':
return UserServiceManager() # Singleton pattern will return always the same instance return UserServiceManager() # Singleton pattern will return always the same instance
def get_cache_state_filter(self, service_pool: ServicePool, level: types.services.CacheLevel) -> Q:
return Q(cache_level=level) & self.get_state_filter(service_pool.service)
@staticmethod @staticmethod
def get_state_filter(service: 'models.Service') -> Q: def get_state_filter(service: 'models.Service') -> Q:
""" """
@ -97,6 +94,9 @@ class UserServiceManager(metaclass=singleton.Singleton):
_('Maximum number of user services reached for this {}').format(service_pool) _('Maximum number of user services reached for this {}').format(service_pool)
) )
def get_cache_state_filter(self, servicepool: ServicePool, level: types.services.CacheLevel) -> Q:
return Q(cache_level=level) & self.get_state_filter(servicepool.service)
def get_existing_user_services(self, service: 'models.Service') -> int: def get_existing_user_services(self, service: 'models.Service') -> int:
""" """
Returns the number of running user services for this service Returns the number of running user services for this service

View File

@ -60,6 +60,10 @@ class FixedService(services.Service, abc.ABC): # pylint: disable=too-many-publi
needs_osmanager = False # If the service needs a s.o. manager (managers are related to agents provided by services, i.e. virtual machines with agent) needs_osmanager = False # If the service needs a s.o. manager (managers are related to agents provided by services, i.e. virtual machines with agent)
# can_reset = True # can_reset = True
# Override the counting type to conservative on Fixed Services by default, that
# is the desired behaviour for fixed services
overrided_fields = {'max_services_count_type': types.services.ServicesCountingType.CONSERVATIVE}
# If machines has an alternate field with it, it will be used instead of "machines" field # If machines has an alternate field with it, it will be used instead of "machines" field
alternate_machines_field: typing.Optional[str] = None alternate_machines_field: typing.Optional[str] = None

View File

@ -127,6 +127,17 @@ class Service(Module):
# : - If userservices_limit_field is None, userservices_limit will be set to consts.UNLIMITED (as default) # : - If userservices_limit_field is None, userservices_limit will be set to consts.UNLIMITED (as default)
userservices_limit: int = consts.UNLIMITED userservices_limit: int = consts.UNLIMITED
# : Overrided fields for service edition
# : This is a dictionary that will be used to override fields on service on its edition
# : This is useful for example to set the max_services_count_type for a service
# : or whatever field is needed to be overrided on service edition
# : Example:
# : overrided_fields = {
# : 'max_services_count_type': ServicesCountingType.STANDARD,
# : Note that overrided_fields will made the field not to be shown on service edition, so it will be "fixed" to the value provided
overrided_fields: typing.Optional[dict[str, typing.Any]] = None
# : If this item "has overrided fields", on deployed service edition, defined keys will overwrite defined ones # : If this item "has overrided fields", on deployed service edition, defined keys will overwrite defined ones
# : That is, this Dicionary will OVERWRITE fields ON ServicePool (normally cache related ones) dictionary from a REST api save invocation!! # : That is, this Dicionary will OVERWRITE fields ON ServicePool (normally cache related ones) dictionary from a REST api save invocation!!
# : Example: # : Example:
@ -136,7 +147,8 @@ class Service(Module):
# : } # : }
# : This means that service pool will have cache_l2_srvs = 10 and cache_l1_srvs = 20, no matter what the user has provided # : This means that service pool will have cache_l2_srvs = 10 and cache_l1_srvs = 20, no matter what the user has provided
# : on a save invocation to REST api for ServicePool # : on a save invocation to REST api for ServicePool
overrided_fields: typing.Optional[dict[str, typing.Any]] = None # : Note that max_services_count_type is one of the variables of ServicesCountingType in this example
overrided_pools_fields: typing.Optional[dict[str, typing.Any]] = None
# : If this class uses cache or not. If uses cache is true, means that the # : If this class uses cache or not. If uses cache is true, means that the
# : service can "prepare" some user deployments to allow quicker user access # : service can "prepare" some user deployments to allow quicker user access
@ -294,7 +306,9 @@ class Service(Module):
if self.userservices_limit == 0: if self.userservices_limit == 0:
self.userservices_limit = consts.UNLIMITED self.userservices_limit = consts.UNLIMITED
elif callable(userservices_limit_field): elif callable(userservices_limit_field):
self.userservices_limit = typing.cast(collections.abc.Callable[..., int], userservices_limit_field)() self.userservices_limit = typing.cast(
collections.abc.Callable[..., int], userservices_limit_field
)()
else: else:
self.userservices_limit = consts.UNLIMITED self.userservices_limit = consts.UNLIMITED
except Exception: except Exception: