def do_trace(self, context, rsc_id, op, interval=None): 'usage: trace <rsc> <op> [<interval>]' rsc = self._get_trace_rsc(rsc_id) if not rsc: return False if not interval: interval = op == "monitor" and "non-0" or "0" if op == "probe": op = "monitor" op_node = xmlutil.find_operation(rsc.node, op, interval) if op_node is None and utils.crm_msec(interval) != 0: common_err("not allowed to create non-0 interval operation %s" % op) return False if op_node is None: head_pl = ["op", []] head_pl[1].append(["name", op]) head_pl[1].append(["interval", interval]) head_pl[1].append([vars.trace_ra_attr, "1"]) cli_list = [] cli_list.append(head_pl) if not rsc.add_operation(cli_list): return False else: op_node = rsc.set_op_attr(op_node, vars.trace_ra_attr, "1") if not cib_factory.commit(): return False if op == "monitor" and utils.crm_msec(interval) != 0: common_warn("please CLEANUP the RA trace directory %s regularly!" % config.path.heartbeat_dir) else: common_info("restart %s to get the trace" % rsc_id) return True
def examine_outcome(l, opts, statuses): ''' A custom function to show stderr in case there were issues. Not suited for callers who want better control of output or per-host processing. ''' hosts = [x[0] for x in l] if min(statuses) < 0: # At least one process was killed. common_err("ssh process was killed") show_output(opts.errdir, hosts, "stderr") return False # The any builtin was introduced in Python 2.5 (so we can't use it yet): #elif any(x==255 for x in statuses): for status in statuses: if status == 255: common_warn("ssh processes failed") show_output(opts.errdir, hosts, "stderr") return False for status in statuses: if status not in (0, _EC_LOGROT): common_warn("some ssh processes failed") show_output(opts.errdir, hosts, "stderr") return False return True
def save(self, dest=None): ''' Save the modified status section to a file/shadow. If the file exists, then it must be a cib file and the status section is replaced with our status section. If the file doesn't exist, then our section and some (?) configuration is saved. ''' if not self.modified: common_info("apparently you didn't modify status") return False if (not dest and self.origin == "live") or dest == "live": common_warn("cannot save status to the cluster") return False cib = self.cib if dest: dest_path = cib_path(dest) if os.path.isfile(dest_path): cib = self._load_cib(dest) if cib is None: common_err("%s exists, but no cib inside" % dest) return False else: dest_path = cib_path(self.origin) if cib != self.cib: status = cib.find("status") xmlutil.rmnode(status) cib.append(self.status_node) xml = etree.tostring(cib) try: f = open(dest_path, "w") except IOError, msg: common_err(msg) return False
def _call_delnode(self, node): "Remove node (how depends on cluster stack)" rc = True if utils.cluster_stack() == "heartbeat": cmd = (self.hb_delnode % node) else: ec, s = utils.get_stdout("%s -p" % self.crm_node) if not s: common_err('%s -p could not list any nodes (rc=%d)' % (self.crm_node, ec)) rc = False else: partition_l = s.split() if node in partition_l: common_err("according to %s, node %s is still active" % (self.crm_node, node)) rc = False cmd = "%s --force -R %s" % (self.crm_node, node) if not rc: if config.core.force: common_info('proceeding with node %s removal' % node) else: return False ec = utils.ext_cmd(cmd) if ec != 0: common_warn('"%s" failed, rc=%d' % (cmd, ec)) return False return True
def check_test_support(resources): rc = True for r in resources: ra_class = r.get("class") if not ra_class: common_warn("class attribute not found in %s" % r.get('id')) rc = False elif ra_class not in ra_driver: common_warn("testing of class %s resources not supported" % ra_class) rc = False return rc
def requires(self): # see the configure ptest/simulate command has_ptest = utils.is_program('ptest') has_simulate = utils.is_program('crm_simulate') if not has_ptest: vars.simulate_programs["ptest"] = "crm_simulate" if not has_simulate: vars.simulate_programs["simulate"] = "ptest" if not (has_ptest or has_simulate): common_warn("neither ptest nor crm_simulate exist, check your installation") vars.simulate_programs["ptest"] = "" vars.simulate_programs["simulate"] = "" return True
def requires(self): if not cib_factory.initialize(): return False # see the configure ptest/simulate command has_ptest = utils.is_program('ptest') has_simulate = utils.is_program('crm_simulate') if not has_ptest: constants.simulate_programs["ptest"] = "crm_simulate" if not has_simulate: constants.simulate_programs["simulate"] = "ptest" if not (has_ptest or has_simulate): common_warn("neither ptest nor crm_simulate exist, check your installation") constants.simulate_programs["ptest"] = "" constants.simulate_programs["simulate"] = "" return True
def ra_type_validate(s, ra_class, provider, rsc_type): ''' Only ocf ra class supports providers. ''' if not rsc_type: common_err("bad resource type specification %s" % s) return False if ra_class == "ocf": if not provider: common_err("provider could not be determined for %s" % s) return False else: if provider: common_warn("ra class %s does not support providers" % ra_class) return True return True
def check_locker(dir): if not os.path.isdir(os.path.join(dir, _LOCKDIR)): return s = file2str(os.path.join(dir, _LOCKDIR, _PIDF)) pid = convert2ints(s) if not isinstance(pid, int): common_warn("history: removing malformed lock") rmdir_r(os.path.join(dir, _LOCKDIR)) return try: os.kill(pid, 0) except OSError, (errno, strerror): if errno == os.errno.ESRCH: common_info("history: removing stale lock") rmdir_r(os.path.join(dir, _LOCKDIR)) else: common_err("%s: %s" % (_LOCKDIR, strerror))
def _xdg_file(name, xdg_name, chk_fun, directory): from msg import common_warn, common_info, common_debug if not name: return name if not os.path.isdir(directory): os.makedirs(directory, 0700) new = os.path.join(directory, xdg_name) if directory == CONFIG_HOME and chk_fun(new) and chk_fun(name): common_warn("both %s and %s exist, please cleanup" % (name, new)) return name if chk_fun(name): if directory == CONFIG_HOME: common_info("moving %s to %s" % (name, new)) else: common_debug("moving %s to %s" % (name, new)) os.rename(name, new) return new
def requires(self): if not cib_factory.initialize(): return False # see the configure ptest/simulate command has_ptest = utils.is_program('ptest') has_simulate = utils.is_program('crm_simulate') if not has_ptest: constants.simulate_programs["ptest"] = "crm_simulate" if not has_simulate: constants.simulate_programs["simulate"] = "ptest" if not (has_ptest or has_simulate): common_warn( "neither ptest nor crm_simulate exist, check your installation" ) constants.simulate_programs["ptest"] = "" constants.simulate_programs["simulate"] = "" return True
def sanity_check_ops(self, id, ops, default_timeout): ''' ops is a list of operations - do all operations exist - are timeouts sensible ''' rc = 0 n_ops = {} for op in ops: n_op = op[0] == "monitor" and monitor_name_pl(op[1]) or op[0] n_ops[n_op] = {} for p, v in op[1]: if p in self.skip_op_attr: continue n_ops[n_op][p] = v for req_op in self.required_ops: if req_op not in n_ops: if not (self.ra_class == "stonith" and req_op in ("start", "stop")): n_ops[req_op] = {} intervals = {} for op in n_ops: if self.ra_class == "stonith" and op in ("start", "stop"): continue if op not in self.actions(): common_warn("%s: action %s not advertised in meta-data, it may not be supported by the RA" % (id, op)) rc |= 1 if "interval" in n_ops[op]: v = n_ops[op]["interval"] v_msec = crm_msec(v) if op in ("start", "stop") and v_msec != 0: common_warn("%s: Specified interval for %s is %s, it must be 0" % (id, op, v)) rc |= 1 if op.startswith("monitor") and v_msec != 0: if v_msec not in intervals: intervals[v_msec] = 1 else: common_warn("%s: interval in %s must be unique" % (id, op)) rc |= 1 try: adv_timeout = self.actions()[op]["timeout"] except: continue if "timeout" in n_ops[op]: v = n_ops[op]["timeout"] timeout_string = "specified timeout" else: v = default_timeout timeout_string = "default timeout" if crm_msec(v) < 0: continue if crm_time_cmp(adv_timeout, v) > 0: common_warn("%s: %s %s for %s is smaller than the advised %s" % (id, timeout_string, v, op, adv_timeout)) rc |= 1 return rc
def get_pcmk_version(dflt): version = dflt crmd = is_program('crmd') if crmd: cmd = crmd else: return version try: rc, s = get_stdout("%s version" % (cmd)) if rc != 0: common_err("%s exited with %d" % (cmd, rc)) else: version = s.split()[2] common_debug("found pacemaker version: %s" % version) except Exception, msg: common_warn("could not get the pacemaker version, bad installation?") common_warn(msg)
def get_pcmk_version(dflt): version = dflt if is_program('crmd'): cmd = 'crmd' elif os.path.isfile(os.path.join(config.path.crm_daemon_dir, 'crmd')): cmd = os.path.join(config.path.crm_daemon_dir, 'crmd') else: return version try: rc, s = get_stdout("%s version" % (cmd)) if rc != 0: common_err("%s exited with %d" % (cmd, rc)) else: version = s.split()[2] common_debug("found pacemaker version: %s" % version) except Exception, msg: common_warn("could not get the pacemaker version, bad installation?") common_warn(msg)
def run_ptest(graph_s, nograph, scores, utilization, actions, verbosity): ''' Pipe graph_s thru ptest(8). Show graph using dotty if requested. ''' actions_filter = "grep LogActions: | grep -vw Leave" ptest = "2>&1 %s -x -" % config.core.ptest if re.search("simulate", ptest) and \ not re.search("-[RS]", ptest): ptest = "%s -S" % ptest if verbosity: if actions: verbosity = 'v' * max(3, len(verbosity)) ptest = "%s -%s" % (ptest, verbosity.upper()) if scores: ptest = "%s -s" % ptest if utilization: ptest = "%s -U" % ptest if config.core.dotty and not nograph: fd, dotfile = mkstemp() ptest = "%s -D %s" % (ptest, dotfile) else: dotfile = None # ptest prints to stderr if actions: ptest = "%s | %s" % (ptest, actions_filter) if options.regression_tests: ptest = ">/dev/null %s" % ptest common_debug("invoke: %s" % ptest) rc, s = get_stdout(ptest, input_s=graph_s) if rc != 0: common_debug("%s exited with %d" % (ptest, rc)) if actions and rc == 1: common_warn("No actions found.") else: common_warn("Simulation was unsuccessful (RC=%d)." % (rc)) if dotfile: if os.path.getsize(dotfile) > 0: show_dot_graph(dotfile) else: common_warn("ptest produced empty dot file") else: if not nograph: common_info("install graphviz to see a transition graph") if s: page_string(s) return True
def wait4dc(what="", show_progress=True): ''' Wait for the DC to get into the S_IDLE state. This should be invoked only after a CIB modification which would exercise the PE. Parameter "what" is whatever the caller wants to be printed if showing progress. It is assumed that the DC is already in a different state, usually it should be either PENGINE or TRANSITION. This assumption may not be true, but there's a high chance that it is since crmd should be faster to move through states than this shell. Further, it may also be that crmd already calculated the new graph, did transition, and went back to the idle state. This may in particular be the case if the transition turned out to be empty. Tricky. Though in practice it shouldn't be an issue. There's no timeout, as we expect the DC to eventually becomes idle. ''' dc = get_dc() if not dc: common_warn("can't find DC") return False cmd = "crm_attribute -Gq -t crm_config -n crmd-transition-delay 2> /dev/null" delay = get_stdout(add_sudo(cmd))[1] if delay: delaymsec = crm_msec(delay) if 0 < delaymsec: common_info( "The crmd-transition-delay is configured. Waiting %d msec before check DC status." % delaymsec) time.sleep(delaymsec / 1000) cmd = "crmadmin -S %s" % dc cnt = 0 output_started = 0 init_sleep = 0.25 max_sleep = 1.00 sleep_time = init_sleep while True: rc, s = get_stdout(add_sudo(cmd)) if not s.startswith("Status"): common_warn("%s unexpected output: %s (exit code: %d)" % (cmd, s, rc)) return False try: dc_status = s.split()[-2] except: common_warn("%s unexpected output: %s" % (cmd, s)) return False if dc_status == "S_IDLE": if output_started: sys.stderr.write(" done\n") return True time.sleep(sleep_time) if sleep_time < max_sleep: sleep_time *= 2 if show_progress: if not output_started: output_started = 1 sys.stderr.write("waiting for %s to finish ." % what) cnt += 1 if cnt % 5 == 0: sys.stderr.write(".")
def warn(self, s): common_warn("%s: %s" % (self.ra_string(), s))
def warn(self, s): common_warn("%s: %s" % (self.id_str(), s))
def warning(self, msg): common_warn("%s: %s" % (self.get_qualified_name(), msg))
continue elif s[0] == "%pfx": if check_transition(inp, state, (START, DATA)) and len(s) == 2: pfx = s[1] state = PFX elif s[0] == "%required": if check_transition(inp, state, (PFX,)): state = DATA data_reqd = True elif s[0] == "%optional": if check_transition(inp, state, (PFX, DATA)): state = DATA data_reqd = False elif s[0] == "%%": if state != DATA: common_warn("user data in wrong state %s" % state) if len(s) < 2: common_warn("parameter name missing") elif len(s) == 2: if data_reqd: common_err("required parameter %s not set" % s[1]) rc = False elif len(s) == 3: user_data["%s:%s" % (pfx, s[1])] = s[2] else: common_err("%s: syntax error" % inp) elif s[0] == "%generate": if check_transition(inp, state, (DATA,)): state = GENERATE piece = [] elif state == GENERATE:
except IOError, msg: common_err("open: %s" % msg) return '' l = (''.join(f)).split('\n') if not validate_template(l): return '' common_info("pulling in template %s" % tmpl) g = l.index('%generate') pre_gen = l[0:g] post_gen = l[g+1:] name = get_var(pre_gen, '%name') for s in l[0:g]: if s.startswith('%depends_on'): a = s.split() if len(a) != 2: common_warn("%s: wrong usage" % s) continue tmpl_id = a[1] tmpl_pfx = self.load_template(a[1]) if tmpl_pfx: fix_tmpl_refs(post_gen, '%'+tmpl_id, '%'+tmpl_pfx) pfx = self.new_pfx(name) fix_tmpl_refs(post_gen, '%_:', '%'+pfx+':') # replace remaining %_, it may be useful at times fix_tmpl_refs(post_gen, '%_', pfx) v_idx = pre_gen.index('%required') or pre_gen.index('%optional') pre_gen.insert(v_idx, '%pfx ' + pfx) self.all_pre_gen += pre_gen self.all_post_gen += post_gen return pfx
continue elif s[0] == "%pfx": if check_transition(inp, state, (START, DATA)) and len(s) == 2: pfx = s[1] state = PFX elif s[0] == "%required": if check_transition(inp, state, (PFX, )): state = DATA data_reqd = True elif s[0] == "%optional": if check_transition(inp, state, (PFX, DATA)): state = DATA data_reqd = False elif s[0] == "%%": if state != DATA: common_warn("user data in wrong state %s" % state) if len(s) < 2: common_warn("parameter name missing") elif len(s) == 2: if data_reqd: common_err("required parameter %s not set" % s[1]) rc = False elif len(s) == 3: user_data["%s:%s" % (pfx, s[1])] = s[2] else: common_err("%s: syntax error" % inp) elif s[0] == "%generate": if check_transition(inp, state, (DATA, )): state = GENERATE piece = [] elif state == GENERATE:
def wait4dc(what="", show_progress=True): ''' Wait for the DC to get into the S_IDLE state. This should be invoked only after a CIB modification which would exercise the PE. Parameter "what" is whatever the caller wants to be printed if showing progress. It is assumed that the DC is already in a different state, usually it should be either PENGINE or TRANSITION. This assumption may not be true, but there's a high chance that it is since crmd should be faster to move through states than this shell. Further, it may also be that crmd already calculated the new graph, did transition, and went back to the idle state. This may in particular be the case if the transition turned out to be empty. Tricky. Though in practice it shouldn't be an issue. There's no timeout, as we expect the DC to eventually becomes idle. ''' dc = get_dc() if not dc: common_warn("can't find DC") return False cmd = "crm_attribute -Gq -t crm_config -n crmd-transition-delay 2> /dev/null" delay = get_stdout(add_sudo(cmd))[1] if delay: delaymsec = crm_msec(delay) if 0 < delaymsec: common_info("The crmd-transition-delay is configured. Waiting %d msec before check DC status." % delaymsec) time.sleep(delaymsec / 1000) cmd = "crmadmin -S %s" % dc cnt = 0 output_started = 0 init_sleep = 0.25 max_sleep = 1.00 sleep_time = init_sleep while True: rc, s = get_stdout(add_sudo(cmd)) if not s.startswith("Status"): common_warn("%s unexpected output: %s (exit code: %d)" % (cmd, s, rc)) return False try: dc_status = s.split()[-2] except: common_warn("%s unexpected output: %s" % (cmd, s)) return False if dc_status == "S_IDLE": if output_started: sys.stderr.write(" done\n") return True time.sleep(sleep_time) if sleep_time < max_sleep: sleep_time *= 2 if show_progress: if not output_started: output_started = 1 sys.stderr.write("waiting for %s to finish ." % what) cnt += 1 if cnt % 5 == 0: sys.stderr.write(".")
tmpl)).read().split('\n') except IOError, msg: common_err("open: %s" % msg) return '' if not validate_template(l): return '' common_info("pulling in template %s" % tmpl) g = l.index('%generate') pre_gen = l[0:g] post_gen = l[g + 1:] name = get_var(pre_gen, '%name') for s in l[0:g]: if s.startswith('%depends_on'): a = s.split() if len(a) != 2: common_warn("%s: wrong usage" % s) continue tmpl_id = a[1] tmpl_pfx = self.load_template(a[1]) if tmpl_pfx: fix_tmpl_refs(post_gen, '%' + tmpl_id, '%' + tmpl_pfx) pfx = self.new_pfx(name) fix_tmpl_refs(post_gen, '%_:', '%' + pfx + ':') # replace remaining %_, it may be useful at times fix_tmpl_refs(post_gen, '%_', pfx) v_idx = pre_gen.index('%required') or pre_gen.index('%optional') pre_gen.insert(v_idx, '%pfx ' + pfx) self.all_pre_gen += pre_gen self.all_post_gen += post_gen return pfx