def validate(self, props): # validate arguments, can changes props # throws ArgumentError if invalid in total # throws MessageError if content invalid if not OPT_ADDRESS in props: raise MessageError('address is missing') if not OPT_CLUSTER in props: raise MessageError('cluster is missing') elif not isinstance(props[OPT_CLUSTER], list): raise MessageError('cluster malformed: list expected') elif len(props[OPT_CLUSTER]) == 0: raise MessageError('cluster is empty') if not OPT_IDENTIFIER in props: raise MessageError('identifier is missing')
def execute(self, arbiter, props): options = props.get('options', {}) # check for endpoint_owner uid restriction mode # it would be better to use some type of SO_PEERCRED lookup on the ipc # socket to get the uid of the client process and restrict on that, # but there's no good portable pythonic way of doing that right now # inside pyzmq or here. So we'll assume that the administrator has # set good rights on the ipc socket to help prevent privilege # escalation if arbiter.endpoint_owner_mode: cmd_uid = options.get('uid', None) if cmd_uid != arbiter.endpoint_owner: raise MessageError("uid does not match endpoint_owner") # convert all rlimit_* options into one rlimits dict which is required # by the watcher constructor (follows same pattern as config.py) rlimits = {} for key, val in options.items(): if key.startswith('rlimit_'): rlimits[key[7:]] = rlimit_value(val) if len(rlimits) > 0: options['rlimits'] = rlimits for key in rlimits.keys(): del options['rlimit_' + key] # now create and start the watcher watcher = arbiter.add_watcher(props['name'], props['cmd'], args=props.get('args'), **options) if props.get('start', False): return watcher.start()
def execute_watcher_start_stop_restart(arbiter, props, watcher_function_name, watchers_function, arbiter_function): """base function to handle start/stop/restart watcher requests. since this is always the same procedure except some function names this function handles all watcher start/stop commands """ if 'name' in props: name = re.compile(fnmatch.translate(props['name'])) watchers = [watcher for watcher in arbiter.iter_watchers() if name.match(watcher.name.lower())] if not watchers: raise MessageError("program %s not found" % props['name']) if len(watchers) == 1: if props.get('waiting'): resp = TransformableFuture() func = getattr(watchers[0], watcher_function_name) resp.set_upstream_future(func()) resp.set_transform_function(lambda x: {"info": x}) return resp return getattr(watchers[0], watcher_function_name)() def watcher_iter_func(reverse=True): return sorted(watchers, key=lambda a: a.priority, reverse=reverse) return watchers_function(watcher_iter_func=watcher_iter_func) else: return arbiter_function()
def validate(self, props): if not self.properties: return for propname in self.properties: if propname not in props: raise MessageError("message invalid %r is missing" % propname)
def execute(self, arbiter, props): if 'name' in props: watcher = self._get_watcher(arbiter, props['name']) if 'process' in props: try: return { "process": props['process'], "info": watcher.process_info(props['process'], props.get('extended')), } except KeyError: raise MessageError("process %r not found in %r" % (props['process'], props['name'])) else: return { "name": props['name'], "info": watcher.info(props.get('extended')) } else: infos = {} for watcher in arbiter.watchers: infos[watcher.name] = watcher.info() return {"infos": infos}
def validate_option(key, val): if key not in ('numprocesses', 'warmup_delay', 'working_dir', 'uid', 'gid', 'send_hup', 'shell', 'env', 'cmd', 'flapping_attempts', 'flapping_window', 'retry_in', 'max_retry', 'graceful_timeout', 'stdout_stream', 'stderr_stream', 'max_age', 'max_age_variance'): raise MessageError('unknown key %r' % key) if key in ( 'numprocesses', 'flapping_attempts', 'max_retry', 'max_age', 'max_age_variance', ): if not isinstance(val, int): raise MessageError("%r isn't an integer" % key) if key in ( 'warmup_delay', 'flapping_window', 'retry_in', 'graceful_timeout', ): if not isinstance(val, ( int, float, )): raise MessageError("%r isn't a number" % key) if key in ( 'uid', 'gid', ): if not isinstance(val, int) or not isinstance(val, string_types): raise MessageError("%r isn't an integer or string" % key) if key in ( 'send_hup', 'shell', ): if not isinstance(val, bool): raise MessageError("%r isn't a valid boolean" % key) if key in ('env', ): if not isinstance(val, dict): raise MessageError("%r isn't a valid object" % key) for k, v in val.items(): if not isinstance(v, string_types): raise MessageError("%r isn't a string" % k) if key in ('stderr_stream', 'stdout_stream'): for k, v in val.items(): if not k in ('class', 'filename', 'refresh_time'): raise MessageError("%r is an invalid option for %r" % \ (k, key))
def validate(self, props): super(Set, self).validate(props) options = props['options'] if not isinstance(options, dict): raise MessageError("'options' property should be an object") for key, val in options.items(): validate_option(key, val)
def validate(self, props): super(AddWatcher, self).validate(props) if 'options' in props: options = props.get('options') if not isinstance(options, dict): raise MessageError("'options' property should be an object") for key, val in props['options'].items(): validate_option(key, val)
def validate(self, props): super(Signal, self).validate(props) if 'childpid' in props and not 'pid' in props: raise ArgumentError('cannot specify childpid without pid') try: props['signum'] = to_signum(props['signum']) except ValueError: raise MessageError('signal invalid')
def validate(self, props): super(Kill, self).validate(props) if 'pid' in props: props['pid'] = int(props['pid']) try: if 'signum' in props: props['signum'] = to_signum(props['signum']) except ValueError: raise MessageError('signal invalid')
def validate(self, props): super(Signal, self).validate(props) signum = props.get('signum') if 'statspid' in props and not 'pid' in props: raise ArgumentError('cannot specify childpid without pid') if 'children' in props and not 'pid' in props: raise ArgumentError('cannot specify children without pid') if isinstance(signum, int): if signum not in (signal.SIGQUIT, signal.SIGHUP, signal.SIGKILL, signal.SIGTERM, signal.SIGTTIN, signal.SIGTTOU, signal.SIGUSR1, signal.SIGUSR2): raise MessageError('signal invalid') elif isinstance(signum, string_types): if signum.lower() in ('quit', 'hup', 'kill', 'term', 'ttin', 'ttou', 'usr1', 'usr2'): props['signum'] = getattr(signal, "SIG%s" % signum.upper()) else: raise MessageError('signal invalid')
def execute(self, arbiter, props): watcher = self._get_watcher(arbiter, props.get('name')) # get options values. It return an error if one of the asked # options isn't found options = {} for name in props.get('keys', []): if name in watcher.optnames: options[name] = getattr(watcher, name) else: raise MessageError("%r option not found" % name) return {"options": options}
def execute(self, arbiter, props): wanted = props.get('option') if wanted: if wanted not in _OPTIONS: raise MessageError('%r not an existing option' % wanted) options = (wanted,) else: options = _OPTIONS res = {} for option in options: res[option] = getattr(arbiter, option) return {"options": res}
def validate(self, props): super(Signal, self).validate(props) if 'pid' in props and not 'process' in props: raise MessageError('process ID is missing') if props.get('children', False) and not 'process': raise MessageError('process ID is missing') signum = props.get('signum') if isinstance(signum, int): if signum not in (signal.SIGQUIT, signal.SIGHUP, signal.SIGKILL, signal.SIGTERM, signal.SIGTTIN, signal.SIGTTOU, signal.SIGUSR1, signal.SIGUSR2): raise MessageError('signal invalid') elif isinstance(signum, string_types): if signum.lower() in ('quit', 'hup', 'kill', 'term', 'ttin', 'ttou', 'usr1', 'usr2'): props['signum'] = getattr(signal, "SIG%s" % signum.upper()) else: raise MessageError('signal invalid') else: raise MessageError('signal invalid')
def validate_option(key, val): if key not in ('numprocesses', 'warmup_delay', 'working_dir', 'uid', 'gid', 'send_hup', 'shell', 'env', 'cmd', 'flapping_attempts', 'flapping_window', 'retry_in', 'max_retry', 'graceful_timeout'): raise MessageError('unkown key %r' % key) if key in ( 'numprocesses', 'flapping_attempts', 'max_retry', ): if not isinstance(val, int): raise MessageError("%r isn't an integer" % key) if key in ( 'warmup_delay', 'flapping_window', 'retry_in', 'graceful_timeout', ): if not isinstance(val, ( int, float, )): raise MessageError("%r isn't a number" % key) if key in ( 'uid', 'gid', ): if not isinstance(val, int) or not isinstance(val, string_types): raise MessageError("%r isn't an integer or string" % key) if key in ( 'send_hup', 'shell', ): if not isinstance(val, bool): raise MessageError("%r isn't a valid boolean" % key) if key == "env": if not isinstance(val, dict): raise MessageError("%r isn't a valid object" % key) for k, v in val.items(): if not isinstance(v, string_types): raise MessageError("%r isn't a string" % k)
def execute(self, arbiter, props): options = props.get('options', {}) # check for endpoint_owner uid restriction mode # it would be better to use some type of SO_PEERCRED lookup on the ipc # socket to get the uid of the client process and restrict on that, # but there's no good portable pythonic way of doing that right now # inside pyzmq or here. So we'll assume that the administrator has # set good rights on the ipc socket to help prevent privilege # escalation if arbiter.endpoint_owner_mode: cmd_uid = options.get('uid', None) if cmd_uid != arbiter.endpoint_owner: raise MessageError("uid does not match endpoint_owner") watcher = arbiter.add_watcher(props['name'], props['cmd'], args=props.get('args'), **options) if props.get('start', False): return watcher.start()
def execute(self, arbiter, props): wanted = props.get('option') available = ('endpoint', 'pubsub_endpoint', 'check_delay') if wanted: if wanted not in available: raise MessageError('%r not an existing option' % wanted) options = (wanted, ) else: options = ('endpoint', 'pubsub_endpoint', 'stats_endpoint', 'check_delay') res = {} for option in options: res[option] = getattr(arbiter, option) return {"options": res}
def validate_option(key, val): valid_keys = ('numprocesses', 'warmup_delay', 'working_dir', 'uid', 'gid', 'send_hup', 'stop_signal', 'stop_children', 'shell', 'env', 'cmd', 'args', 'copy_env', 'retry_in', 'max_retry', 'graceful_timeout', 'stdout_stream', 'stderr_stream', 'max_age', 'max_age_variance', 'respawn', 'singleton', 'hooks', 'close_child_stdin', 'close_child_stdout', 'close_child_stderr', 'use_papa') valid_prefixes = ('stdout_stream.', 'stderr_stream.', 'hooks.', 'rlimit_') def _valid_prefix(): for prefix in valid_prefixes: if key.startswith('%s' % prefix): return True return False if key not in valid_keys and not _valid_prefix(): raise MessageError('unknown key %r' % key) if key in ('numprocesses', 'max_retry', 'max_age', 'max_age_variance', 'stop_signal'): if not isinstance(val, int): raise MessageError("%r isn't an integer" % key) elif key in ('warmup_delay', 'retry_in', 'graceful_timeout',): if not isinstance(val, (int, float)): raise MessageError("%r isn't a number" % key) elif key in ('uid', 'gid',): if not isinstance(val, int) and not isinstance(val, string_types): raise MessageError("%r isn't an integer or string" % key) elif key in ('send_hup', 'shell', 'copy_env', 'respawn', 'stop_children', 'close_child_stdin', 'close_child_stdout', 'close_child_stderr'): if not isinstance(val, bool): raise MessageError("%r isn't a valid boolean" % key) elif key in ('env', ): if not isinstance(val, dict): raise MessageError("%r isn't a valid object" % key) for k, v in val.items(): if not isinstance(v, string_types): raise MessageError("%r isn't a string" % k) elif key == 'hooks': if not isinstance(val, dict): raise MessageError("%r isn't a valid hook dict" % val) for key in val: if key not in _HOOKS: raise MessageError("Unknown hook %r" % val) elif key in ('stderr_stream', 'stdout_stream'): if not isinstance(val, dict): raise MessageError("%r isn't a valid object" % key) if 'class' not in val: raise MessageError("%r must have a 'class' key" % key) if 'refresh_time' in val: warnings.warn("'refresh_time' is deprecated and not useful " "anymore for %r" % key) elif key.startswith('rlimit_'): if resource: rlimit_key = key[7:] rlimit_int = getattr( resource, 'RLIMIT_' + rlimit_key.upper(), None ) if rlimit_int is None: raise MessageError("%r isn't a valid rlimit setting" % key) else: raise MessageError("rlimit options are not supported on this" " platform") # note that a null val means RLIM_INFINITY if val is not None and not isinstance(val, int): raise MessageError("%r rlimit value isn't a valid int" % val)
def execute(self, arbiter, args): raise MessageError("invalid message. use a pub/sub socket")
def validate_option(key, val): valid_keys = ('numprocesses', 'warmup_delay', 'working_dir', 'uid', 'gid', 'send_hup', 'shell', 'env', 'cmd', 'copy_env', 'flapping_attempts', 'flapping_window', 'retry_in', 'max_retry', 'graceful_timeout', 'stdout_stream', 'stderr_stream', 'max_age', 'max_age_variance', 'respawn', 'hooks') valid_prefixes = ('stdout_stream', 'stderr_stream') def _valid_prefix(): for prefix in valid_prefixes: if key.startswith('%s.' % prefix): return True return False if key not in valid_keys and not _valid_prefix(): raise MessageError('unknown key %r' % key) if key in ('numprocesses', 'flapping_attempts', 'max_retry', 'max_age', 'max_age_variance'): if not isinstance(val, int): raise MessageError("%r isn't an integer" % key) if key in ('warmup_delay', 'flapping_window', 'retry_in', 'graceful_timeout',): if not isinstance(val, (int, float,)): raise MessageError("%r isn't a number" % key) if key in ('uid', 'gid',): if not isinstance(val, int) and not isinstance(val, string_types): raise MessageError("%r isn't an integer or string" % key) if key in ('send_hup', 'shell', 'copy_env', 'respawn'): if not isinstance(val, bool): raise MessageError("%r isn't a valid boolean" % key) if key in ('env', ): if not isinstance(val, dict): raise MessageError("%r isn't a valid object" % key) for k, v in val.items(): if not isinstance(v, string_types): raise MessageError("%r isn't a string" % k) if key == 'hooks': if not isinstance(val, dict): raise MessageError("%r isn't a valid hook dict" % val) for key in val: if key not in _HOOKS: raise MessageError("Unknown hook %r" % val) if key in ('stderr_stream', 'stdout_stream'): if not isinstance(val, dict): raise MessageError("%r isn't a valid object" % key) if not 'class' in val: raise MessageError("%r must have a 'class' key" % key) if 'refresh_time' in val: warnings.warn(u"'refresh_time' is deprecated and not useful " u"anymore for %r" % key)
def _get_watcher(self, arbiter, watcher_name): """Get watcher from the arbiter if any.""" try: return arbiter.get_watcher(watcher_name.lower()) except KeyError: raise MessageError("program %s not found" % watcher_name)