PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/extras-3.10/pyroute2/ndb/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/extras-3.10/pyroute2/ndb/task_manager.py |
import inspect import logging import queue import threading import time import traceback from functools import partial from pyroute2 import config from . import schema from .events import ( DBMExitException, InvalidateHandlerException, RescheduleException, ShutdownException, ) from .messages import cmsg, cmsg_event, cmsg_failed, cmsg_sstart log = logging.getLogger(__name__) def Events(*argv): for sequence in argv: if sequence is not None: for item in sequence: yield item class NDBConfig(dict): def __init__(self, task_manager): self.task_manager = task_manager def __getitem__(self, key): return self.task_manager.config_get(key) def __setitem__(self, key, value): return self.task_manager.config_set(key, value) def __delitem__(self, key): return self.task_manager.config_del(key) def keys(self): return self.task_manager.config_keys() def items(self): return self.task_manager.config_items() def values(self): return self.task_manager.config_values() class TaskManager: def __init__(self, ndb): self.ndb = ndb self.log = ndb.log self.event_map = {} self.event_queue = ndb._event_queue self.thread = None self.ctime = self.gctime = time.time() def register_handler(self, event, handler): if event not in self.event_map: self.event_map[event] = [] self.event_map[event].append(handler) def unregister_handler(self, event, handler): self.event_map[event].remove(handler) def default_handler(self, target, event): if isinstance(getattr(event, 'payload', None), Exception): raise event.payload log.debug('unsupported event ignored: %s' % type(event)) def check_sources_started(self, _locals, target, event): _locals['countdown'] -= 1 if _locals['countdown'] == 0: self.ndb._dbm_ready.set() def wrap_method(self, method): # # this wrapper will be published in the DBM thread # def _do_local_generator(target, request): try: for item in method(*request.argv, **request.kwarg): request.response.put(item) request.response.put(StopIteration()) except Exception as e: request.response.put(e) def _do_local_single(target, request): try: (request.response.put(method(*request.argv, **request.kwarg))) except Exception as e: (request.response.put(e)) # # this class will be used to map the requests # class cmsg_req(cmsg): def __init__(self, response, *argv, **kwarg): self['header'] = {'target': None} self.response = response self.argv = argv self.kwarg = kwarg # # this method will proxy the original one # def _do_dispatch_generator(self, *argv, **kwarg): if self.thread == id(threading.current_thread()): # same thread, run method locally for item in method(*argv, **kwarg): yield item else: # another thread, run via message bus response = queue.Queue() request = cmsg_req(response, *argv, **kwarg) self.event_queue.put((request,)) while True: item = response.get() if isinstance(item, StopIteration): return elif isinstance(item, Exception): raise item else: yield item def _do_dispatch_single(self, *argv, **kwarg): if self.thread == id(threading.current_thread()): # same thread, run method locally return method(*argv, **kwarg) else: # another thread, run via message bus response = queue.Queue(maxsize=1) request = cmsg_req(response, *argv, **kwarg) self.event_queue.put((request,)) ret = response.get() if isinstance(ret, Exception): raise ret else: return ret # # return the method spec to be announced # handler = _do_local_single proxy = _do_dispatch_single if inspect.isgeneratorfunction(method): handler = _do_local_generator proxy = _do_dispatch_generator return (cmsg_req, handler, proxy) def register_api(self, api_obj, prefix=''): for name in dir(api_obj): method = getattr(api_obj, name, None) if hasattr(method, 'publish'): if isinstance(method.publish, str): name = method.publish name = f'{prefix}{name}' event, handler, proxy = self.wrap_method(method) setattr(self, name, partial(proxy, self)) self.event_map[event] = [handler] def run(self): _locals = {'countdown': len(self.ndb._nl)} self.thread = id(threading.current_thread()) # init the events map event_map = { cmsg_event: [lambda t, x: x.payload.set()], cmsg_failed: [lambda t, x: (self.ndb.schema.mark(t, 1))], cmsg_sstart: [partial(self.check_sources_started, _locals)], } self.event_map = event_map try: self.ndb.schema = schema.DBSchema( self.ndb.config, self.ndb.sources, self.event_map, self.log.channel('schema'), ) self.register_api(self.ndb.schema, 'db_') self.register_api(self.ndb.schema.config, 'config_') self.ndb.bonfig = NDBConfig(self) except Exception as e: self.ndb._dbm_error = e self.ndb._dbm_ready.set() return for spec in self.ndb._nl: spec['event'] = None self.ndb.sources.add(**spec) for event, handlers in self.ndb.schema.event_map.items(): for handler in handlers: self.register_handler(event, handler) stop = False source = None reschedule = [] while not stop: source, events = self.event_queue.get() events = Events(events, reschedule) reschedule = [] try: for event in events: handlers = event_map.get( event.__class__, [self.default_handler] ) for handler in tuple(handlers): try: target = event['header']['target'] handler(target, event) except RescheduleException: if 'rcounter' not in event['header']: event['header']['rcounter'] = 0 if event['header']['rcounter'] < 3: event['header']['rcounter'] += 1 self.log.debug('reschedule %s' % (event,)) reschedule.append(event) else: self.log.error('drop %s' % (event,)) except InvalidateHandlerException: try: handlers.remove(handler) except Exception: self.log.error( 'could not invalidate ' 'event handler:\n%s' % traceback.format_exc() ) except ShutdownException: stop = True break except DBMExitException: return except Exception: self.log.error( 'could not load event:\n%s\n%s' % (event, traceback.format_exc()) ) if time.time() - self.gctime > config.gc_timeout: self.gctime = time.time() except Exception as e: self.log.error(f'exception <{e}> in source {source}') # restart the target try: self.log.debug(f'requesting source {source} restart') self.ndb.sources[source].state.set('restart') except KeyError: self.log.debug(f'key error for {source}') pass # release all the sources for target in tuple(self.ndb.sources.cache): source = self.ndb.sources.remove(target, sync=False) if source is not None and source.th is not None: self.log.debug(f'closing source {source}') source.close() if self.ndb.schema.config['db_cleanup']: self.log.debug('flush DB for the target %s' % target) self.ndb.schema.flush(target) else: self.log.debug('leave DB for debug') # close the database self.ndb.schema.commit() self.ndb.schema.close() # close the logging for handler in self.log.logger.handlers: handler.close()