def create_agents(self): """ Prepares the vSphere Agents used by the vPoller Worker Raises: VPollerException """ logger.debug('Creating vSphere Agents') db = VConnectorDatabase(self.config.get('db')) agents = db.get_agents(only_enabled=True) if not agents: logger.warning('No registered or enabled vSphere Agents found') raise VPollerException( 'No registered or enabled vSphere Agents found') for agent in agents: a = VConnector( user=agent['user'], pwd=agent['pwd'], host=agent['host'], cache_enabled=self.config.get('cache_enabled'), cache_maxsize=self.config.get('cache_maxsize'), cache_ttl=self.config.get('cache_ttl'), cache_housekeeping=self.config.get('cache_housekeeping')) self.agents[a.host] = a logger.info('Created vSphere Agent for %s', agent['host'])
def run_helper(self, helper, msg, data): """ Run a helper to post-process result data Args: helper (str): Name of the helper to run msg (dict): The original message request data (dict): The data to be processed """ logger.debug( 'Invoking helper module %s for processing of data', helper ) module = self.helper_modules[helper] h = module.HelperAgent(msg=msg, data=data) try: result = h.run() except Exception as e: logger.warning('Helper module raised an exception: %s', e) return data return result
def create_agents(self): """ Prepares the vSphere Agents used by the vPoller Worker Raises: VPollerException """ logger.debug('Creating vSphere Agents') db = VConnectorDatabase(self.config.get('db')) agents = db.get_agents(only_enabled=True) if not agents: logger.warning('No registered or enabled vSphere Agents found') raise VPollerException( 'No registered or enabled vSphere Agents found' ) for agent in agents: a = VConnector( user=agent['user'], pwd=agent['pwd'], host=agent['host'], cache_enabled=self.config.get('cache_enabled'), cache_maxsize=self.config.get('cache_maxsize'), cache_ttl=self.config.get('cache_ttl'), cache_housekeeping=self.config.get('cache_housekeeping') ) self.agents[a.host] = a logger.info('Created vSphere Agent for %s', agent['host'])
def wrapper(*args, **kwargs): logger.debug("Executing task %s", name) try: result = fn(*args, **kwargs) except Exception as e: tb = format_exc() result = {"success": 1, "msg": "Task {} failed".format(name), "traceback": tb} logger.warning("Task %s failed: %s", name, tb) finally: logger.debug("Returning result from task %s: %s", name, result) return result
def wrapper(*args, **kwargs): logger.debug('Executing task %s', name) try: result = fn(*args, **kwargs) except Exception as e: tb = format_exc() result = { 'success': 1, 'msg': 'Task {} failed'.format(name), 'traceback': tb } logger.warning('Task %s failed: %s', name, tb) finally: logger.debug('Returning result from task %s: %s', name, result) return result
def wait_for_mgmt_task(self): """ Poll the management socket for management tasks """ socks = dict(self.zpoller.poll()) if socks.get(self.mgmt_socket) == zmq.POLLIN: try: msg = self.mgmt_socket.recv_json() except TypeError: logger.warning('Invalid management message received', ) self.mgmt_socket.send('Invalid message received') return result = self.process_mgmt_task(msg) self.mgmt_socket.send_json(result)
def wait_for_mgmt_task(self): """ Poll the management socket for management tasks """ socks = dict(self.zpoller.poll()) if socks.get(self.mgmt_socket) == zmq.POLLIN: try: msg = self.mgmt_socket.recv_json() except TypeError: logger.warning( 'Invalid message received on management interface', ) self.mgmt_socket.send('Invalid message received') return result = self.process_mgmt_task(msg) self.mgmt_socket.send_json(result)
def load_task_modules(self): """ Loads the task modules """ if not self.config.get('tasks'): raise VPollerException('No task modules provided') for task in self.config.get('tasks'): task = task.strip() logger.info('Loading task module %s', task) try: module = importlib.import_module(task) except ImportError as e: logger.warning('Cannot import task module: %s', e.message) continue self.task_modules[task] = module if not self.task_modules: raise VPollerException('No task modules loaded')
def load_helper_modules(self): """ Loads helper modules for post-processing of results """ if not self.config.get('helpers'): return for helper in self.config.get('helpers'): helper = helper.strip() logger.info('Loading helper module %s', helper) try: module = importlib.import_module(helper) except ImportError as e: logger.warning('Cannot import helper module: %s', e) continue if not hasattr(module, 'HelperAgent'): logger.warning( 'Module %s does not provide a HelperAgent interface', helper) continue if not hasattr(module.HelperAgent, 'run'): logger.warning( 'In module %s HelperAgent class does not provide a run() method', helper) continue self.helper_modules[helper] = module
def load_helper_modules(self): """ Loads helper modules for post-processing of results """ if not self.config.get('helpers'): return for helper in self.config.get('helpers'): helper = helper.strip() logger.info('Loading helper module %s', helper) try: module = importlib.import_module(helper) except ImportError as e: logger.warning( 'Cannot import helper module: %s', e ) continue if not hasattr(module, 'HelperAgent'): logger.warning( 'Module %s does not provide a HelperAgent interface', helper ) continue if not hasattr(module.HelperAgent, 'run'): logger.warning( 'In module %s HelperAgent class does not provide a run() method', helper ) continue self.helper_modules[helper] = module
def wait_for_tasks(self): """ Poll the worker socket for new tasks """ socks = dict(self.zpoller.poll(1000)) # The routing envelope of the message on the worker socket is this: # # Frame 1: [ N ][...] <- Identity of connection # Frame 2: [ 0 ][] <- Empty delimiter frame # Frame 3: [ N ][...] <- Data frame if socks.get(self.worker_socket) == zmq.POLLIN: # TODO: Use recv_multipart() _id = self.worker_socket.recv() _empty = self.worker_socket.recv() try: msg = self.worker_socket.recv_json() except Exception as e: logger.warning( 'Invalid client message received, will be ignored', ) self.worker_socket.send(_id, zmq.SNDMORE) self.worker_socket.send(_empty, zmq.SNDMORE) self.worker_socket.send_json({ 'success': 1, 'msg': 'Invalid message received' }) return # Process task and return result to client result = self.process_client_msg(msg) # Process data using a helper before sending it to client? if 'helper' in msg and msg['helper'] in self.helper_modules: data = self.run_helper(helper=msg['helper'], msg=msg, data=result) else: # No helper specified, dump data to JSON try: data = json.dumps(result, ensure_ascii=False) except (ValueError, TypeError) as e: logger.warning('Cannot serialize result: %s', e) r = { 'success': 1, 'msg': 'Cannot serialize result: %s' % e } data = json.dumps(r) # Send data to client self.worker_socket.send(_id, zmq.SNDMORE) self.worker_socket.send(_empty, zmq.SNDMORE) try: self.worker_socket.send_unicode(data) except TypeError as e: logger.warning('Cannot send result: %s', e) r = {'success': 1, 'msg': 'Cannot send result: %s' % e} self.worker_socket.send_unicode(json.dumps(r))
def load_task_modules(self): """ Loads the task modules """ if not self.config.get('tasks'): raise VPollerException('No task modules provided') for task in self.config.get('tasks'): task = task.strip() logger.info('Loading task module %s', task) try: module = importlib.import_module(task) except ImportError as e: logger.warning( 'Cannot import task module: %s', e.message ) continue self.task_modules[task] = module if not self.task_modules: raise VPollerException('No task modules loaded')
def run(self, msg): """ Main vPoller Client method Partially based on the Lazy Pirate Pattern: http://zguide.zeromq.org/py:all#Client-Side-Reliability-Lazy-Pirate-Pattern Args: msg (dict): The client message to send """ logger.debug('Endpoint to connect to: %s', self.endpoint) logger.debug('Timeout of request: %s ms', self.timeout) logger.debug('Number of retries: %d', self.retries) logger.debug('Message to be sent: %s', msg) self.zcontext = zmq.Context() self.zclient = self.zcontext.socket(zmq.REQ) self.zclient.connect(self.endpoint) self.zclient.setsockopt(zmq.LINGER, 0) self.zpoller = zmq.Poller() self.zpoller.register(self.zclient, zmq.POLLIN) result = None while self.retries > 0: logger.debug('Sending client message...') # Send our message out self.zclient.send_json(msg) socks = dict(self.zpoller.poll(self.timeout)) # Do we have a reply? if socks.get(self.zclient) == zmq.POLLIN: logger.debug('Received response on client socket') result = self.zclient.recv_unicode() logger.debug('Received message was: %s', result) break else: # We didn't get a reply back from the server, let's retry self.retries -= 1 logger.warning('Did not receive response, retrying...') # Socket is confused. Close and remove it. logger.debug( 'Closing sockets and re-establishing connection...') self.zclient.close() self.zpoller.unregister(self.zclient) # Re-establish the connection logger.debug('Re-establishing connection to endpoint: %s', self.endpoint) self.zclient = self.zcontext.socket(zmq.REQ) self.zclient.connect(self.endpoint) self.zclient.setsockopt(zmq.LINGER, 0) self.zpoller.register(self.zclient, zmq.POLLIN) # Close the socket and terminate the context logger.debug('Closing sockets and exiting') self.zclient.close() self.zpoller.unregister(self.zclient) self.zcontext.term() # Did we have any result reply at all? if result is None: logger.error('Did not receive response, aborting...') r = {'success': 1, 'msg': 'Did not receive response, aborting...'} return json.dumps(r, ensure_ascii=False) return result
def wait_for_tasks(self): """ Poll the worker socket for new tasks """ socks = dict(self.zpoller.poll(1000)) # The routing envelope of the message on the worker socket is this: # # Frame 1: [ N ][...] <- Identity of connection # Frame 2: [ 0 ][] <- Empty delimiter frame # Frame 3: [ N ][...] <- Data frame if socks.get(self.worker_socket) == zmq.POLLIN: # TODO: Use recv_multipart() _id = self.worker_socket.recv() _empty = self.worker_socket.recv() try: msg = self.worker_socket.recv_json() except Exception as e: logger.warning( 'Invalid client message received, will be ignored', ) self.worker_socket.send(_id, zmq.SNDMORE) self.worker_socket.send(_empty, zmq.SNDMORE) self.worker_socket.send_json( {'success': 1, 'msg': 'Invalid message received'} ) return # Process task and return result to client result = self.process_client_msg(msg) # Process data using a helper before sending it to client? if 'helper' in msg and msg['helper'] in self.helper_modules: data = self.run_helper( helper=msg['helper'], msg=msg, data=result ) else: # No helper specified, dump data to JSON try: data = json.dumps(result, cls=DefaultJSONEncoder, ensure_ascii=False) except (ValueError, TypeError) as e: logger.warning('Cannot serialize result: %s', e) r = { 'success': 1, 'msg': 'Cannot serialize result: %s' % e } data = json.dumps(r) # Send data to client self.worker_socket.send(_id, zmq.SNDMORE) self.worker_socket.send(_empty, zmq.SNDMORE) try: self.worker_socket.send_unicode(data) except TypeError as e: logger.warning('Cannot send result: %s', e) r = {'success': 1, 'msg': 'Cannot send result: %s' % e} self.worker_socket.send_unicode(json.dumps(r))
def run(self, msg): """ Main vPoller Client method Partially based on the Lazy Pirate Pattern: http://zguide.zeromq.org/py:all#Client-Side-Reliability-Lazy-Pirate-Pattern Args: msg (dict): The client message to send """ logger.debug('Endpoint to connect to: %s', self.endpoint) logger.debug('Timeout of request: %s ms', self.timeout) logger.debug('Number of retries: %d', self.retries) logger.debug('Message to be sent: %s', msg) self.zcontext = zmq.Context() self.zclient = self.zcontext.socket(zmq.REQ) self.zclient.connect(self.endpoint) self.zclient.setsockopt(zmq.LINGER, 0) self.zpoller = zmq.Poller() self.zpoller.register(self.zclient, zmq.POLLIN) result = None while self.retries > 0: logger.debug('Sending client message...') # Send our message out self.zclient.send_json(msg) socks = dict(self.zpoller.poll(self.timeout)) # Do we have a reply? if socks.get(self.zclient) == zmq.POLLIN: logger.debug('Received response on client socket') result = self.zclient.recv_unicode() logger.debug('Received message was: %s', result) break else: # We didn't get a reply back from the server, let's retry self.retries -= 1 logger.warning( 'Did not receive response, retrying...' ) # Socket is confused. Close and remove it. logger.debug('Closing sockets and re-establishing connection...') self.zclient.close() self.zpoller.unregister(self.zclient) # Re-establish the connection logger.debug( 'Re-establishing connection to endpoint: %s', self.endpoint ) self.zclient = self.zcontext.socket(zmq.REQ) self.zclient.connect(self.endpoint) self.zclient.setsockopt(zmq.LINGER, 0) self.zpoller.register(self.zclient, zmq.POLLIN) # Close the socket and terminate the context logger.debug('Closing sockets and exiting') self.zclient.close() self.zpoller.unregister(self.zclient) self.zcontext.term() # Did we have any result reply at all? if result is None: logger.error( 'Did not receive response, aborting...' ) r = { 'success': 1, 'msg': 'Did not receive response, aborting...' } return json.dumps(r, ensure_ascii=False) return result