def test_resources(resources, nodes, all_nodes): def test_node(node): started = [] sys.stderr.write("testing on %s:" % node) for r in resources: id = r.get("id") ra_class = r.get("class") drv = ra_driver[ra_class](r, (node, )) sys.stderr.write(" %s" % id) if drv.test_resource(node): started.append(drv) else: sys.stderr.write("\n") drv.show_log(node) stop_all(started, node) return False sys.stderr.write("\n") stop_all(started, node) return True try: import crm_pssh except ImportError: common_err("pssh not installed, rsctest can not be executed") return False if not check_test_support(resources): return False if not are_all_stopped(resources, all_nodes): sys.stderr.write("Stop all resources before testing!\n") return False rc = True for node in nodes: rc |= test_node(node) return rc
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 next_peinputs(node_pe_l, outdir, errdir): ''' pssh to nodes to collect new logs. ''' l = [] for node, pe_l in node_pe_l: r = re.search("(.*)/pengine/", pe_l[0]) if not r: common_err("strange, %s doesn't contain string pengine" % pe_l[0]) continue dir = "/%s" % r.group(1) red_pe_l = [x.replace("%s/" % r.group(1), "") for x in pe_l] common_debug("getting new PE inputs %s from %s" % (red_pe_l, node)) cmdline = "tar -C %s -cf - %s" % (dir, ' '.join(red_pe_l)) myopts = ["-q", "-o", outdir, "-e", errdir] opts, args = parse_args(myopts) l.append([node, cmdline]) if not l: # is this a failure? return True statuses = do_pssh(l, opts) if statuses: return examine_outcome(l, opts, statuses) else: return False
def sanity_check_params(self, id, nvpairs, existence_only=False): ''' nvpairs is a list of <nvpair> tags. - are all required parameters defined - do all parameters exist ''' rc = 0 d = {} for nvp in nvpairs: if 'name' in nvp.attrib and 'value' in nvp.attrib: d[nvp.get('name')] = nvp.get('value') if not existence_only: for p in self.reqd_params_list(): if self.unreq_param(p): continue if p not in d: common_err("%s: required parameter %s not defined" % (id, p)) rc |= utils.get_check_rc() for p in d: if p.startswith("$"): # these are special, non-RA parameters continue if p not in self.params(): common_err("%s: parameter %s does not exist" % (id, p)) rc |= utils.get_check_rc() return rc
def __conf_object(self, cmd, *args): "The configure object command." if cmd in constants.cib_cli_map.values() and \ not cib_factory.is_elem_supported(cmd): common_err("%s not supported by the RNG schema" % cmd) return False return cib_factory.create_object(cmd, *args)
def do_new(self, context, name, *args): "usage: new <config> <template> [<template> ...] [params name=value ...]" if not utils.is_filename_sane(name): return False if os.path.isfile("%s/%s" % (userdir.CRMCONF_DIR, name)): common_err("config %s exists; delete it first" % name) return False lt = LoadTemplate(name) rc = True mode = 0 params = {} for s in args: if mode == 0 and s == "params": params["id"] = name mode = 1 elif mode == 1: a = s.split('=') if len(a) != 2: syntax_err(args, context='new') rc = False else: params[a[0]] = a[1] elif not lt.load_template(s): rc = False if rc: lt.post_process(params) if not rc or not lt.write_config(name): return False self.curr_conf = name
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 _get_diff_pe_input(self, t): if t != "live": return self._get_pe_input(t) if not utils.get_dc(): common_err("cluster not running") return None return "live"
def ptest(self, nograph, scores, utilization, actions, verbosity): 'Send a decompressed self.pe_file to ptest' try: s = bz2.decompress(open(self.pe_file).read()) except IOError, msg: common_err("open: %s" % msg) return False
def load_template(self, tmpl): try: l = open(os.path.join(config.path.sharedir, 'templates', tmpl)).read().split('\n') except IOError, msg: common_err("open: %s" % msg) return ''
def _check_source(self, src): 'a (very) quick source check' if src == "live" or os.path.isfile(src) or os.path.isdir(src): return True else: common_err("source %s doesn't exist" % src) return False
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 do_rsctest(self, context, *args): "usage: rsctest <rsc_id> [<rsc_id> ...] [<node_id> ...]" if not cib_factory.is_cib_sane(): return False rc = True rsc_l = [] node_l = [] current = "r" for ident in args: el = cib_factory.find_object(ident) if not el: common_err("element %s does not exist" % ident) rc = False elif current == "r" and xmlutil.is_resource(el.node): if xmlutil.is_container(el.node): rsc_l += el.node.findall("primitive") else: rsc_l.append(el.node) elif xmlutil.is_normal_node(el.node): current = "n" node_l.append(el.node.get("uname")) else: syntax_err((context.get_command_name(), ident), context='rsctest') return False if not rc: return False if not rsc_l: common_err("specify at least one resource") return False all_nodes = cib_factory.node_id_list() if not node_l: node_l = all_nodes return rsctest.test_resources(rsc_l, node_l, all_nodes)
def do_work(context, user_args): compatibility_setup() if options.shadow: if not context.run("cib use " + options.shadow): return 1 # this special case is silly, but we have to keep it to # preserve the backward compatibility if len(user_args) == 1 and user_args[0].startswith("conf"): if not context.run("configure"): return 1 elif len(user_args) > 0: # we're not sure yet whether it's an interactive session or not # (single-shot commands aren't) err_buf.reset_lineno() options.interactive = False l = add_quotes(user_args) if context.run(' '.join(l)): # if the user entered a level, then just continue if not context.previous_level(): return 0 set_interactive() if options.interactive: err_buf.reset_lineno(-1) else: return 1 if options.input_file and options.input_file != "-": try: sys.stdin = open(options.input_file) except IOError, msg: common_err(msg) usage(2)
def graph_args(args): ''' Common parameters for two graph commands: configure graph [<gtype> [<file> [<img_format>]]] history graph <pe> [<gtype> [<file> [<img_format>]]] ''' from crm_gv import gv_types gtype, outf, ftype = None, None, None try: gtype = args[0] if gtype not in gv_types: common_err("graph type %s is not supported" % gtype) return False, gtype, outf, ftype except: gtype = "dot" try: outf = args[1] if not utils.is_path_sane(outf): return False, gtype, outf, ftype except: outf = None try: ftype = args[2] except: ftype = gtype return True, gtype, outf, ftype
def do_work(context, user_args): compatibility_setup() rc = handle_noninteractive_use(context, user_args) if rc is not None: return rc setup_context(context) rc = 0 while True: try: inp = utils.multi_input(render_prompt(context)) if inp is None: if options.interactive: rc = 0 context.quit(rc) try: if not context.run(inp): rc = 1 except ValueError, msg: rc = 1 common_err(msg) except KeyboardInterrupt: if options.interactive and not options.batch: print "Ctrl-C, leaving" context.quit(1) return rc
def run(): try: if len(sys.argv) >= 2 and sys.argv[1] == '--compgen': compgen() return 0 envsetup() userdir.mv_user_files() ui = ui_root.Root() context = ui_context.Context(ui) load_rc(context, userdir.RC_FILE) atexit.register(exit_handler) options.interactive = utils.can_ask() if not options.interactive: err_buf.reset_lineno() options.batch = True user_args = parse_options() term._init() if options.profile: return profile_run(context, user_args) else: return do_work(context, user_args) except KeyboardInterrupt: print "Ctrl-C, leaving" sys.exit(1) except ValueError, e: common_err(str(e))
def setup_context(context): if options.input_file and options.input_file != "-": try: sys.stdin = open(options.input_file) except IOError, msg: common_err(msg) usage(2)
def run(self, line): ''' Execute the given command line. ''' line = line.strip() if not line or line.startswith('#'): return True self._mark = len(self.stack) self._in_transit = False rv = True cmd = False try: tokens = shlex.split(line) while tokens: token, tokens = tokens[0], tokens[1:] self.command_name = token self.command_args = tokens self.command_info = self.current_level().get_child(token) if not self.command_info: self.fatal_error("No such command") if self.command_info.type == 'level': self.enter_level(self.command_info.level) else: cmd = True break if cmd: rv = self.execute_command() is not False except ValueError, msg: common_err("%s: %s" % (self.get_qualified_name(), msg)) rv = False
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 test_resources(resources, nodes, all_nodes): def test_node(node): started = [] sys.stderr.write("testing on %s:" % node) for r in resources: id = r.get("id") ra_class = r.get("class") drv = ra_driver[ra_class](r, (node,)) sys.stderr.write(" %s" % id) if drv.test_resource(node): started.append(drv) else: sys.stderr.write("\n") drv.show_log(node) stop_all(started, node) return False sys.stderr.write("\n") stop_all(started, node) return True try: import crm_pssh except ImportError: common_err("Parallax SSH not installed, rsctest can not be executed") return False if not check_test_support(resources): return False if not are_all_stopped(resources, all_nodes): sys.stderr.write("Stop all resources before testing!\n") return False rc = True for node in nodes: rc |= test_node(node) return rc
def sanity_check_params(self, id, pl, existence_only=False): ''' pl is a list of (attribute, value) pairs. - are all required parameters defined - do all parameters exist ''' rc = 0 d = {} for p, v in pl: d[p] = v if not existence_only: for p in self.reqd_params_list(): if self.unreq_param(p): continue if p not in d: common_err("%s: required parameter %s not defined" % (id, p)) rc |= utils.get_check_rc() for p in d: if p.startswith("$"): # these are special, non-RA parameters continue if p not in self.params(): common_err("%s: parameter %s does not exist" % (id, p)) rc |= utils.get_check_rc() return rc
def append_file(dest, src): 'Append src to dest' try: dest_f = open(dest, "a") except IOError, msg: common_err("open %s: %s" % (dest, msg)) return False
def config_exists(self, name): if not utils.is_filename_sane(name): return False if not os.path.isfile("%s/%s" % (userdir.CRMCONF_DIR, name)): common_err("%s: no such config" % name) return False return True
def init_dir(self): '''Create the conf directory, link to templates''' if not os.path.isdir(userdir.CRMCONF_DIR): try: os.makedirs(userdir.CRMCONF_DIR) except os.error, msg: common_err("makedirs: %s" % msg)
def pe2shadow(pe_file, name): '''Copy a PE file (or any CIB file) to a shadow.''' try: s = open(pe_file).read() except IOError, msg: common_err("open: %s" % msg) return False
def cibdump2tmp(): try: _, outp, _ = sudocall(cib_dump) if outp is not None: return str2tmp(outp) except IOError, msg: common_err(msg)
def process(self, config=''): '''Create a cli configuration from the current config''' try: f = open("%s/%s" % (userdir.CRMCONF_DIR, config or self.curr_conf), 'r') except IOError, msg: common_err("open: %s" % msg) return ''
def sanity_check_nvpairs(id, node, attr_list): rc = 0 for nvpair in node.iterchildren("nvpair"): n = nvpair.get("name") if n and not n in attr_list: common_err("%s: attribute %s does not exist" % (id, n)) rc |= utils.get_check_rc() return rc
def do_demote(self, context, rsc): "usage: demote <rsc>" if not utils.is_name_sane(rsc): return False if not xmlutil.RscState().is_ms(rsc): common_err("%s is not a master-slave resource" % rsc) return False return utils.ext_cmd(self.rsc_setrole % (rsc, "Slave")) == 0
def op_instattr(node): pl = [] for c in node.iterchildren(): if c.tag != "instance_attributes": common_err("only instance_attributes are supported in operations") else: pl += nvpairs2list(c) return pl
def append_file(dest, src): 'Append src to dest' try: open(dest, "a").write(open(src).read()) return True except IOError, msg: common_err("append %s to %s: %s" % (src, dest, msg)) return False