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 process_mgmt_task(self, msg): """ Processes a message for the management interface Example client message to shutdown the vPoller Worker would be: { "method": "shutdown" } Args: msg (dict): The client message for processing """ logger.debug('Processing management message: %s', msg) if 'method' not in msg: return {'success': 1, 'msg': 'Missing method name'} if msg['method'] not in self.mgmt_methods: return {'success': 1, 'msg': 'Unknown method name received'} method = msg['method'] result = self.mgmt_methods[method]() return result
def status(self): """ Get status information about the vPoller Worker """ logger.debug('Getting Worker status') result = { 'success': 0, 'msg': 'vPoller Worker status', 'result': { 'status': 'running', 'hostname': self.node, 'proxy': self.config.get('proxy'), 'mgmt': self.config.get('mgmt'), 'db': self.config.get('db'), 'concurrency': self.num_workers, 'helpers': self.config.get('helpers'), 'tasks': self.config.get('tasks'), } } logger.debug('Returning result to client: %s', result) return result
def load_config(self): """ Loads the vPoller Worker Manager configuration settings """ logger.debug('Loading config file %s', self.config_file) parser = ConfigParser(self.config_defaults) parser.read(self.config_file) self.config['mgmt'] = parser.get('worker', 'mgmt') self.config['db'] = parser.get('worker', 'db') self.config['proxy'] = parser.get('worker', 'proxy') self.config['helpers'] = parser.get('worker', 'helpers') self.config['tasks'] = parser.get('worker', 'tasks') self.config['cache_enabled'] = parser.getboolean('cache', 'enabled') self.config['cache_maxsize'] = parser.getint('cache', 'maxsize') self.config['cache_ttl'] = parser.getint('cache', 'ttl') self.config['cache_housekeeping'] = parser.getint('cache', 'housekeeping') if self.config['helpers']: self.config['helpers'] = self.config['helpers'].split(',') if self.config['tasks']: self.config['tasks'] = self.config['tasks'].split(',') logger.debug( 'Worker Manager configuration: %s', self.config )
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 load_config(self): """ Loads the vPoller Worker Manager configuration settings """ logger.debug('Loading config file %s', self.config_file) parser = ConfigParser(self.config_defaults) parser.read(self.config_file) self.config['mgmt'] = parser.get('worker', 'mgmt') self.config['db'] = parser.get('worker', 'db') self.config['proxy'] = parser.get('worker', 'proxy') self.config['helpers'] = parser.get('worker', 'helpers') self.config['tasks'] = parser.get('worker', 'tasks') self.config['cache_enabled'] = parser.getboolean('cache', 'enabled') self.config['cache_maxsize'] = parser.getint('cache', 'maxsize') self.config['cache_ttl'] = parser.getint('cache', 'ttl') self.config['cache_housekeeping'] = parser.getint( 'cache', 'housekeeping') if self.config['helpers']: self.config['helpers'] = self.config['helpers'].split(',') if self.config['tasks']: self.config['tasks'] = self.config['tasks'].split(',') logger.debug('Worker Manager configuration: %s', self.config)
def stop_agents(self): """ Disconnects all vPoller Agents """ logger.debug('Shutting down vSphere Agents') for agent in self.agents: self.agents[agent].disconnect()
def close_sockets(self): """ Closes the ZeroMQ sockets used by the Manager """ logger.debug('Closing Worker Manager sockets') self.zpoller.unregister(self.mgmt_socket) self.mgmt_socket.close() self.zcontext.term()
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 create_sockets(self): """ Creates the ZeroMQ sockets used by the vPoller Worker Manager """ logger.debug('Creating Worker Manager sockets') self.zcontext = zmq.Context() self.mgmt_socket = self.zcontext.socket(zmq.REP) self.mgmt_socket.bind(self.config.get('mgmt')) self.zpoller = zmq.Poller() self.zpoller.register(self.mgmt_socket, zmq.POLLIN)
def process_client_msg(self, msg): """ Processes a client message received on the vPoller Worker socket The message is passed to the VSphereAgent object of the respective vSphere host in order to do the actual polling. Args: msg (dict): Client message for processing An example message for discovering the hosts could be: { "method": "host.discover", "hostname": "vc01.example.org", } An example message for polling a datastore property could be: { "method": "datastore.poll", "hostname": "vc01.example.org", "info.url": "ds:///vmfs/volumes/5190e2a7-d2b7c58e-b1e2/", "property": "summary.capacity" } """ logger.debug('Processing client message: %s', msg) if not isinstance(msg, dict): return { 'success': 1, 'msg': 'Expected a JSON message, received {}'.format(msg.__class__) } task = registry.get(msg.get('method')) agent = self.agents.get(msg.get('hostname')) if not task: return {'success': 1, 'msg': 'Unknown or missing task/method name'} if not agent: return {'success': 1, 'msg': 'Unknown or missing agent name'} if not validate_message(msg=msg, required=task.required): return {'success': 1, 'msg': 'Invalid task request'} result = task.function(agent, msg) return result
def distribute_tasks(self): """ Distributes tasks from clients to workers for processing """ socks = dict(self.zpoller.poll(1000)) # Forward task from frontend to backend socket if socks.get(self.frontend) == zmq.POLLIN: logger.debug('Message received on frontend socket') task = self.frontend.recv() more = self.frontend.getsockopt(zmq.RCVMORE) if more: self.backend.send(task, zmq.SNDMORE) else: self.backend.send(task) logger.debug( 'Sending message to backend socket: %s', task ) # Forward result from backend to frontend socket if socks.get(self.backend) == zmq.POLLIN: logger.debug('Message received on backend socket') result = self.backend.recv() more = self.backend.getsockopt(zmq.RCVMORE) if more: self.frontend.send(result, zmq.SNDMORE) else: self.frontend.send(result) logger.debug( 'Sending message to frontend socket: %s', result )
def distribute_tasks(self): """ Distributes tasks from clients to workers for processing """ socks = dict(self.zpoller.poll(1000)) # Forward task from frontend to backend socket if socks.get(self.frontend) == zmq.POLLIN: logger.debug('Message received on frontend socket') task = self.frontend.recv() more = self.frontend.getsockopt(zmq.RCVMORE) if more: self.backend.send(task, zmq.SNDMORE) else: self.backend.send(task) logger.debug('Sending message to backend socket: %s', task) # Forward result from backend to frontend socket if socks.get(self.backend) == zmq.POLLIN: logger.debug('Message received on backend socket') result = self.backend.recv() more = self.backend.getsockopt(zmq.RCVMORE) if more: self.frontend.send(result, zmq.SNDMORE) else: self.frontend.send(result) logger.debug('Sending message to frontend socket: %s', 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 load_config(self): """ Load the vPoller Proxy Manager configuration settings """ logger.debug('Loading config file %s', self.config_file) parser = ConfigParser(self.config_defaults) parser.read(self.config_file) self.config['mgmt'] = parser.get('proxy', 'mgmt') self.config['frontend'] = parser.get('proxy', 'frontend') self.config['backend'] = parser.get('proxy', 'backend') logger.debug('Proxy Manager configuration: %s', self.config)
def load_config(self): """ Load the vPoller Proxy Manager configuration settings """ logger.debug('Loading config file %s', self.config_file) parser = ConfigParser(self.config_defaults) parser.read(self.config_file) self.config['mgmt'] = parser.get('proxy', 'mgmt') self.config['frontend'] = parser.get('proxy', 'frontend') self.config['backend'] = parser.get('proxy', 'backend') logger.debug( 'Proxy Manager configuration: %s', self.config )
def validate_message(msg, required): """ Helper method for validating a client message Returns: bool: True if message has been successfully validated """ if not required: return True logger.debug('Validating client message, required to have: %s', required) # Check if we have the required message attributes if not all(k in msg for k in required): logger.debug('Required message keys are missing') return False logger.debug('Client message successfully validated') return True
def validate_message(msg, required): """ Helper method for validating a client message Returns: bool: True if message has been successfully validated """ if not required: return True logger.debug( 'Validating client message, required to have: %s', required ) # Check if we have the required message attributes if not all(k in msg for k in required): logger.debug('Required message keys are missing') return False logger.debug('Client message successfully validated') return True
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 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