def __exit__(self, type, value, traceback): ''' Kill the minion and master processes ''' try: if hasattr(self.sub_minion_process, 'terminate'): self.sub_minion_process.terminate() else: log.error('self.sub_minion_process can\'t be terminate.') except AttributeError: pass try: if hasattr(self.minion_process, 'terminate'): self.minion_process.terminate() else: log.error('self.minion_process can\'t be terminate.') except AttributeError: pass try: if hasattr(self.sub_master_process, 'terminate'): self.sub_master_process.terminate() else: log.error('self.sub_master_process can\'t be terminate.') except AttributeError: pass try: if hasattr(self.master_process, 'terminate'): self.master_process.terminate() else: log.error('self.master_process can\'t be terminate.') except AttributeError: pass self._exit_mockbin() self._exit_ssh() # Shutdown the multiprocessing logging queue listener salt_log_setup.shutdown_multiprocessing_logging() salt_log_setup.shutdown_multiprocessing_logging_listener( daemonizing=True) # Shutdown the log server self.log_server.shutdown() self.log_server.server_close() self.log_server_process.join()
def __exit__(self, type, value, traceback): ''' Kill the minion and master processes ''' self.sub_minion_process.terminate() self.minion_process.terminate() if hasattr(self, 'proxy_process'): self.proxy_process.terminate() self.master_process.terminate() try: self.syndic_process.terminate() except AttributeError: pass try: self.smaster_process.terminate() except AttributeError: pass #salt.utils.process.clean_proc(self.sub_minion_process, wait_for_kill=50) #self.sub_minion_process.join() #salt.utils.process.clean_proc(self.minion_process, wait_for_kill=50) #self.minion_process.join() #salt.utils.process.clean_proc(self.master_process, wait_for_kill=50) #self.master_process.join() #try: # salt.utils.process.clean_proc(self.syndic_process, wait_for_kill=50) # self.syndic_process.join() #except AttributeError: # pass #try: # salt.utils.process.clean_proc(self.smaster_process, wait_for_kill=50) # self.smaster_process.join() #except AttributeError: # pass self.log_server.server_close() self.log_server.shutdown() self._exit_mockbin() self._exit_ssh() self.log_server_process.join() # Shutdown the multiprocessing logging queue listener salt_log_setup.shutdown_multiprocessing_logging() salt_log_setup.shutdown_multiprocessing_logging_listener(daemonizing=True)
def handle_func(self, multiprocessing_enabled, func, data): ''' Execute this method in a multiprocess or thread ''' if salt.utils.is_windows(): # Since function references can't be pickled and pickling # is required when spawning new processes on Windows, regenerate # the functions and returners. self.functions = salt.loader.minion_mods(self.opts) self.returners = salt.loader.returners(self.opts, self.functions) ret = {'id': self.opts.get('id', 'master'), 'fun': func, 'schedule': data['name'], 'jid': salt.utils.jid.gen_jid()} if 'metadata' in data: if isinstance(data['metadata'], dict): ret['metadata'] = data['metadata'] ret['metadata']['_TOS'] = self.time_offset ret['metadata']['_TS'] = time.ctime() ret['metadata']['_TT'] = time.strftime('%Y %B %d %a %H %m', time.gmtime()) else: log.warning('schedule: The metadata parameter must be ' 'specified as a dictionary. Ignoring.') salt.utils.appendproctitle('{0} {1}'.format(self.__class__.__name__, ret['jid'])) proc_fn = os.path.join( salt.minion.get_proc_dir(self.opts['cachedir']), ret['jid'] ) # Check to see if there are other jobs with this # signature running. If there are more than maxrunning # jobs present then don't start another. # If jid_include is False for this job we can ignore all this # NOTE--jid_include defaults to True, thus if it is missing from the data # dict we treat it like it was there and is True if 'jid_include' not in data or data['jid_include']: jobcount = 0 for basefilename in os.listdir(salt.minion.get_proc_dir(self.opts['cachedir'])): fn_ = os.path.join(salt.minion.get_proc_dir(self.opts['cachedir']), basefilename) if not os.path.exists(fn_): log.debug('schedule.handle_func: {0} was processed ' 'in another thread, skipping.'.format( basefilename)) continue with salt.utils.fopen(fn_, 'rb') as fp_: job = salt.payload.Serial(self.opts).load(fp_) if job: if 'schedule' in job: log.debug('schedule.handle_func: Checking job against ' 'fun {0}: {1}'.format(ret['fun'], job)) if ret['schedule'] == job['schedule'] and os_is_running(job['pid']): jobcount += 1 log.debug( 'schedule.handle_func: Incrementing jobcount, now ' '{0}, maxrunning is {1}'.format( jobcount, data['maxrunning'])) if jobcount >= data['maxrunning']: log.debug( 'schedule.handle_func: The scheduled job {0} ' 'was not started, {1} already running'.format( ret['schedule'], data['maxrunning'])) return False else: try: log.info('Invalid job file found. Removing.') os.remove(fn_) except OSError: log.info('Unable to remove file: {0}.'.format(fn_)) if multiprocessing_enabled and not salt.utils.is_windows(): # Shutdown the multiprocessing before daemonizing log_setup.shutdown_multiprocessing_logging() salt.utils.daemonize_if(self.opts) if multiprocessing_enabled and not salt.utils.is_windows(): # Reconfigure multiprocessing logging after daemonizing log_setup.setup_multiprocessing_logging() ret['pid'] = os.getpid() if 'jid_include' not in data or data['jid_include']: log.debug('schedule.handle_func: adding this job to the jobcache ' 'with data {0}'.format(ret)) # write this to /var/cache/salt/minion/proc with salt.utils.fopen(proc_fn, 'w+b') as fp_: fp_.write(salt.payload.Serial(self.opts).dumps(ret)) args = tuple() if 'args' in data: args = data['args'] kwargs = {} if 'kwargs' in data: kwargs = data['kwargs'] # if the func support **kwargs, lets pack in the pub data we have # TODO: pack the *same* pub data as a minion? argspec = salt.utils.args.get_function_argspec(self.functions[func]) if argspec.keywords: # this function accepts **kwargs, pack in the publish data for key, val in six.iteritems(ret): kwargs['__pub_{0}'.format(key)] = val try: ret['return'] = self.functions[func](*args, **kwargs) data_returner = data.get('returner', None) if data_returner or self.schedule_returner: if 'returner_config' in data: ret['ret_config'] = data['returner_config'] if 'returner_kwargs' in data: ret['ret_kwargs'] = data['returner_kwargs'] rets = [] for returner in [data_returner, self.schedule_returner]: if isinstance(returner, str): rets.append(returner) elif isinstance(returner, list): rets.extend(returner) # simple de-duplication with order retained for returner in OrderedDict.fromkeys(rets): ret_str = '{0}.returner'.format(returner) if ret_str in self.returners: ret['success'] = True self.returners[ret_str](ret) else: log.info( 'Job {0} using invalid returner: {1}. Ignoring.'.format( func, returner ) ) # Only attempt to return data to the master # if the scheduled job is running on a minion. if '__role' in self.opts and self.opts['__role'] == 'minion': if 'return_job' in data and not data['return_job']: pass else: # Send back to master so the job is included in the job list mret = ret.copy() mret['jid'] = 'req' channel = salt.transport.Channel.factory(self.opts, usage='salt_schedule') load = {'cmd': '_return', 'id': self.opts['id']} for key, value in six.iteritems(mret): load[key] = value try: channel.send(load) except salt.exceptions.SaltReqTimeoutError: log.error('Timeout error during scheduled job: {0}. Salt master could not be reached.'.format(ret['fun'])) except Exception: log.exception("Unhandled exception running {0}".format(ret['fun'])) # Although catch-all exception handlers are bad, the exception here # is to let the exception bubble up to the top of the thread context, # where the thread will die silently, which is worse. finally: try: log.debug('schedule.handle_func: Removing {0}'.format(proc_fn)) os.unlink(proc_fn) except OSError as exc: if exc.errno == errno.EEXIST or exc.errno == errno.ENOENT: # EEXIST and ENOENT are OK because the file is gone and that's what # we wanted pass else: log.error("Failed to delete '{0}': {1}".format(proc_fn, exc.errno)) # Otherwise, failing to delete this file is not something # we can cleanly handle. raise finally: if multiprocessing_enabled: # Let's make sure we exit the process! exit(salt.defaults.exitcodes.EX_GENERIC)