Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2012-12-19 10:49:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh", Maintainer is "dmuhameda...@suse.com" Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2012-10-18 15:54:35.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2012-12-19 10:50:40.000000000 +0100 @@ -1,0 +2,16 @@ +Tue Dec 11 17:22:00 UTC 2012 - dmuhameda...@suse.com + +- cibconfig: improve id management on element update +- cibconfig: don't bail out if filter fails +- ui: improve quotes insertion +- history: optimize source refreshing +- history: fix setting up the timeframe alias for limit +- history: fix unpacking reports specified without directory +- history: add log subcommand to transition +- ra: add support for nagios plugins +- ra: don't print duplicate RAs in the list command (bnc#793585) +- utils: make sure that there's at least one column (savannah#37658) +- build: pcmk.pc renamed to pacemaker.pc in pacemaker v1.1.8 +- upstream cs: fe29639e39eb (v1.2.3) + +------------------------------------------------------------------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.PvgYRl/_old 2012-12-19 10:50:42.000000000 +0100 +++ /var/tmp/diff_new_pack.PvgYRl/_new 2012-12-19 10:50:42.000000000 +0100 @@ -45,7 +45,7 @@ Summary: Pacemaker command line interface License: GPL-2.0 Group: %{pkg_group} -Version: 1.2.1 +Version: 1.2.3 Release: 0 Url: http://savannah.nongnu.org/projects/crmsh Source0: crmsh.tar.bz2 ++++++ crmsh.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/.hg_archival.txt new/crmsh/.hg_archival.txt --- old/crmsh/.hg_archival.txt 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/.hg_archival.txt 2012-12-11 18:29:34.000000000 +0100 @@ -1,5 +1,5 @@ repo: 13c3bd69e935090cd25213c474cafc3f01b5910b -node: b6bb311c7bd36c05206f3a1cd98193ccf46d8da0 +node: 355467d3974841ba2f0400ffe6cb251d88185786 branch: default -latesttag: crmsh-1.2.0 -latesttagdistance: 25 +latesttag: crmsh-1.2.3 +latesttagdistance: 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/.hgtags new/crmsh/.hgtags --- old/crmsh/.hgtags 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/.hgtags 2012-12-11 18:29:34.000000000 +0100 @@ -18,3 +18,6 @@ f731b72e3c82226b22c133a27462a019055f39e7 SLE11-HAE-GMC fd6bd4648675c2be80c7bed2d8f8d3e5a5074c59 Pacemaker-1.0.5 45886ac2c124ce49fc004dbc080974dc76dea605 crmsh-1.2.0 +b6bb311c7bd36c05206f3a1cd98193ccf46d8da0 crmsh-1.2.1 +4ca0d2abf345d207a5fbdbc444d70d8b18b0cc6a crmsh-1.2.2 +fe29639e39eb95b2d806f0567e6e0b6cf1070e96 crmsh-1.2.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/ChangeLog new/crmsh/ChangeLog --- old/crmsh/ChangeLog 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/ChangeLog 2012-12-11 18:29:34.000000000 +0100 @@ -1,3 +1,21 @@ +* Tue Dec 11 2012 Dejan Muhamedagic <de...@suse.de> and many others +- stable release 1.2.3 +- ra: don't print duplicate RAs in the list command (bnc#793585) +- history: optimize source refreshing + +* Thu Dec 6 2012 Dejan Muhamedagic <de...@suse.de> and many others +- stable release 1.2.2 +- cibconfig: don't bail out if filter fails +- cibconfig: improve id management on element update +- ra: add support for nagios plugins +- utils: make sure that there's at least one column (savannah#37658) +- ui: improve quotes insertion (possible regression) +- history: adjust log patterns for pacemaker v1.1.8 +- history: fix setting up the timeframe alias for limit +- history: fix unpacking reports specified without directory +- history: add log subcommand to transition +- build: pcmk.pc renamed to pacemaker.pc in pacemaker v1.1.8 + * Mon Oct 15 2012 Dejan Muhamedagic <de...@suse.de> and many others - stable release 1.2.1 - cibconfig: show error message on id in use diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/configure.ac new/crmsh/configure.ac --- old/crmsh/configure.ac 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/configure.ac 2012-12-11 18:29:34.000000000 +0100 @@ -21,7 +21,7 @@ dnl checks for library functions dnl checks for system services -AC_INIT(crmsh, 1.2.1, linux-ha@linux...@lists.linux-ha.org) +AC_INIT(crmsh, 1.2.3, linux...@lists.linux-ha.org) AC_ARG_WITH(version, [ --with-version=version Override package version (if you're a packager needing to pretend) ], @@ -197,6 +197,9 @@ CRM_DAEMON_DIR=`$PKGCONFIG pcmk --variable=daemondir` if test "X$CRM_DAEMON_DIR" = X; then + CRM_DAEMON_DIR=`$PKGCONFIG pacemaker --variable=daemondir` +fi +if test "X$CRM_DAEMON_DIR" = X; then CRM_DAEMON_DIR=`extract_header_define $GLUE_HEADER GLUE_DAEMON_DIR` fi AC_DEFINE_UNQUOTED(CRM_DAEMON_DIR,"$CRM_DAEMON_DIR", Location for Pacemaker daemons) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/crmsh.spec new/crmsh/crmsh.spec --- old/crmsh/crmsh.spec 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/crmsh.spec 2012-12-11 18:29:34.000000000 +0100 @@ -17,7 +17,7 @@ Name: crmsh Summary: Pacemaker command line interface -Version: 1.2.1 +Version: 1.2.3 Release: %{crmsh_release}%{?dist} License: GPLv2+ Url: http://www.clusterlabs.org diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/doc/crm.8.txt new/crmsh/doc/crm.8.txt --- old/crmsh/doc/crm.8.txt 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/doc/crm.8.txt 2012-12-11 18:29:34.000000000 +0100 @@ -1406,6 +1406,31 @@ See <<topics_Checks,Configuration semantic checks>> for more details. +[[cmdhelp_options_add-quotes,add quotes around parameters containing spaces]] +==== `add-quotes` + +The shell (as in `/bin/sh`) parser strips quotes from the command +line. This may sometimes make it really difficult to type values +which contain white space. One typical example is the configure +filter command. The crm shell will supply extra quotes around +arguments which contain white space. The default is `yes`. + +.Note on quotes use +**************************** +Adding quotes around arguments automatically has been introduced +with version 1.2.2 and it is technically a regression. Being a +regression is the only reason the `add-quotes` option exists. If +you have custom shell scripts which would break, just set the +`add-quotes` option to `no`. + +For instance, with adding quotes enabled, it is possible to do +the following: +............... + # crm configure primitive d1 ocf:heartbeat:Dummy meta description="some description here" + # crm configure filter 'sed "s/hostlist=./&node-c /"' fencing +............... +**************************** + [[cmdhelp_options_show,show current user preference]] ==== `show` @@ -2088,13 +2113,11 @@ It is possible to filter the XML representation of objects, but probably not as useful as the configuration language. The presentation is somewhat different from what would be displayed -by the `show` command---each element is shown on a single, i.e. -there are no backslashes and no other embelishments. +by the `show` command---each element is shown on a single line, +i.e. there are no backslashes and no other embelishments. Don't forget to put quotes around the filter if it contains -spaces. Further, if you use this in a single-shot mode (from the -`sh` command line), protect all quotes with a backslash. -Otherwise, they won't reach the `crm` shell parser. +spaces. Usage: ............... @@ -2104,7 +2127,7 @@ Examples: ............... filter "sed '/^primitive/s/target-role=[^ ]*//'" - # crm configure filter \"sed \'/^primitive/s/target-role=[^ ]*//\'\" + # crm configure filter "sed '/^primitive/s/target-role=[^ ]*//'" ............... [[cmdhelp_configure_delete,delete CIB objects]] @@ -3008,6 +3031,9 @@ report was produced. In optimal case this output should not differ from the one produced by the locally installed `pengine`. +The `log` subcommand shows the full log for the duration of the +transition. + If the PE input file number is not provided, it defaults to the last one, i.e. the last transition. If the number is negative, then the corresponding transition relative to the last one is @@ -3025,6 +3051,7 @@ ............... transition [<number>|<index>|<file>] [nograph] [v...] [scores] [actions] [utilization] transition showdot [<number>|<index>|<file>] + transition log [<number>|<index>|<file>] ............... Examples: ............... @@ -3034,6 +3061,7 @@ transition pe-error-3.bz2 transition node-a/pengine/pe-input-2.bz2 transition showdot 444 + transition log ............... [[cmdhelp_history_session,manage history sessions]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/Makefile.am new/crmsh/modules/Makefile.am --- old/crmsh/modules/Makefile.am 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/Makefile.am 2012-12-11 18:29:34.000000000 +0100 @@ -36,6 +36,7 @@ report.py \ rsctest.py \ log_patterns.py \ + log_patterns_118.py \ crm_pssh.py \ singletonmixin.py \ template.py \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/cibconfig.py new/crmsh/modules/cibconfig.py --- old/crmsh/modules/cibconfig.py 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/cibconfig.py 2012-12-11 18:29:34.000000000 +0100 @@ -2318,8 +2318,8 @@ the new properties should be merged with the old. Otherwise, users may be surprised. ''' - id_store.remove_xml(obj.node) if len(cli_list) >= 2 and cli_list[1][0] == "raw": + id_store.remove_xml(obj.node) doc = xml.dom.minidom.parseString(cli_list[1][1]) id_store.store_xml(doc.childNodes[0]) return self.update_element(obj,doc.childNodes[0]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/log_patterns_118.py new/crmsh/modules/log_patterns_118.py --- old/crmsh/modules/log_patterns_118.py 1970-01-01 01:00:00.000000000 +0100 +++ new/crmsh/modules/log_patterns_118.py 2012-12-11 18:29:34.000000000 +0100 @@ -0,0 +1,74 @@ +# Copyright (C) 2012 Dejan Muhamedagic <dmuhameda...@suse.de> +# +# log pattern specification (for pacemaker v1.1.8) +# +# patterns are grouped one of several classes: +# - resource: pertaining to a resource +# - node: pertaining to a node +# - quorum: quorum changes +# - events: other interesting events (core dumps, etc) +# +# paterns are grouped based on a detail level +# detail level 0 is the lowest, i.e. should match the least +# number of relevant messages + +# NB: +# %% stands for whatever user input we get, for instance a +# resource name or node name or just some regular expression +# in optimal case, it should be surrounded by literals +# +# [Note that resources may contain clone numbers!] + +log_patterns = { + "resource": ( + ( # detail 0 + "crmd.*Initiating.*%%_(start|stop|promote|demote|migrate)_", + "lrmd.*operation_finished: %%_", + "crmd.*process_lrm_event: LRM operation %%_(start|stop|promote|demote|migrate)_.*confirmed=true", + "crmd.*process_lrm_event: LRM operation %%_.*Timed Out", + "[(]%%[)][[]", + ), + ( # detail 1 + "crmd.*Initiating%%_(monitor_0|notify)", + ), + ), + "node": ( + ( # detail 0 + " %% .*Corosync.Cluster.Engine", + " %% .*Executive.Service.RELEASE", + " %% .*crm_shutdown:.Requesting.shutdown", + " %% .*pcmk_shutdown:.Shutdown.complete", + " %% .*Configuration.validated..Starting.heartbeat", + "pengine.*Scheduling Node %% for STONITH", + "pengine.*pe_fence_node: Node %% will be fenced", + "crmd.* tengine_stonith_callback: .* for %% failed", + "stonith-ng.*log_operation:.*host '%%'", + "te_fence_node: Exec.*on %% ", + "pe_fence_node: Node %% will be fenced", + "stonith-ng.*remote_op_timeout.*on %% for.*timed out", + "stonith-ng.*can_fence_host_with_device:.*can not fence %%:", + "stonithd.*Succeeded.*node %%:", + "pcmk_peer_update.*(lost|memb): %% ", + "crmd.*ccm_event.*(NEW|LOST):.* %% ", + ), + ( # detail 1 + ), + ), + "quorum": ( + ( # detail 0 + "crmd.*crm_update_quorum:.Updating.quorum.status", + "crmd.*ais.disp.*quorum.(lost|ac?quir)", + ), + ( # detail 1 + ), + ), + "events": ( + ( # detail 0 + "CRIT:", + "ERROR:", + ), + ( # detail 1 + "WARN:", + ), + ), +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/main.py new/crmsh/modules/main.py --- old/crmsh/modules/main.py 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/main.py 2012-12-11 18:29:34.000000000 +0100 @@ -290,23 +290,15 @@ vars.tmpl_conf_dir = xdg_file(vars.tmpl_conf_dir, \ vars.xdg_map["crmconf"], "d", "config") -def compatibility(): - from distutils.version import LooseVersion - try: - vars.pcmk_version = get_stdout("crmd version").split()[2] - if LooseVersion(vars.pcmk_version) >= LooseVersion("1.1.8"): - vars.node_type_opt = True - vars.attr_defaults["node"] = {"type": "normal"} - vars.cib_no_section_rc = 6 - vars.transition_patt[0] = "pengine.* process_pe_message: Calculated Transition ([0-9]+): (.*/pe-[^-]+-(%%)[.]bz2)" # transition start - except Exception,msg: - vars.pcmk_version = "1.1.1" - common_warn(msg) - common_warn("could not get the pacemaker version, bad installation?") +def compatibility_setup(): + if is_pcmk_118(): + vars.node_type_opt = True + vars.attr_defaults["node"] = {"type": "normal"} + vars.cib_no_section_rc = 6 def do_work(): global user_args - compatibility() + compatibility_setup() # 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"): @@ -325,9 +317,10 @@ # '...\'...\'' do work l = [] for s in user_args: - if ' ' in s and not ('"' in s or "'" in s): - q = '"' - s = "%s%s%s" % (q,s,q) + if user_prefs.get_add_quotes() and ' ' in s: + q = '"' in s and "'" or '"' + if not q in s: + s = "%s%s%s" % (q,s,q) l.append(s) if parse_line(levels,shlex.split(' '.join(l))): # if the user entered a level, then just continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/ra.py new/crmsh/modules/ra.py --- old/crmsh/modules/ra.py 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/ra.py 2012-12-11 18:29:34.000000000 +0100 @@ -80,6 +80,9 @@ l = stdout2list("/usr/sbin/%s -o metadata" % ra_type) else: l = stdout2list("stonith -m -t %s" % ra_type) + elif ra_class == "nagios": + l = stdout2list("%s/check_%s --metadata" % \ + (vars.nagios_dir, ra_type)) return l def providers(self, ra_type,ra_class = "ocf"): 'List of providers for a class:type.' @@ -92,7 +95,7 @@ return l def classes(self): 'List of classes.' - return "heartbeat lsb ocf stonith".split() + return "heartbeat lsb nagios ocf stonith".split() def types(self, ra_class = "ocf", ra_provider = ""): 'List of types for a class.' l = [] @@ -104,6 +107,9 @@ elif ra_class == "stonith": l = stdout2list("stonith -L") l.extend(os_types_list("/usr/sbin/fence_*")) + elif ra_class == "nagios": + l = os_types_list("%s/check_*" % vars.nagios_dir) + l = [x.replace("check_","") for x in l] l = list(set(l)) l.sort() if ra_class == "stonith": @@ -208,13 +214,12 @@ id = "ra_types-%s-%s" % (ra_class,ra_provider) if wcache.is_cached(id): return wcache.retrieve(id) - if ra_provider: - list = [] - for ra in ra_if().types(ra_class): - if ra_provider in ra_providers(ra,ra_class): - list.append(ra) - else: - list = ra_if().types(ra_class) + list = [] + for ra in ra_if().types(ra_class): + if (not ra_provider or \ + ra_provider in ra_providers(ra,ra_class)) \ + and ra not in list: + list.append(ra) list.sort() return wcache.store(id,list) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/report.py new/crmsh/modules/report.py --- old/crmsh/modules/report.py 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/report.py 2012-12-11 18:29:34.000000000 +0100 @@ -31,7 +31,6 @@ from xmlutil import * from utils import * from msg import * -from log_patterns import log_patterns _NO_PSSH = False try: from crm_pssh import next_loglines, next_peinputs @@ -370,6 +369,7 @@ crmd: [13667]: info: run_graph: Transition 399 (Complete=5, Pending=1, Fired=1, Skipped=0, Incomplete=3, Source=... + Returns dict: d[Pending]=np, d[Fired]=nf, ... ''' d = {} s = msg @@ -379,30 +379,73 @@ return d d[r.group(1)] = int(r.group(2)) s = s[r.end():] -def transition_actions(msg_l, te_invoke_msg, pe_file): - ''' - Get the number of actions for the transition. - ''' - # check if there were any actions in this transition + +def extract_pe_file(msg): + msg_a = msg.split() + if len(msg_a) < 8: + # this looks too short + common_warn("log message <%s> unexpected format, please report a bug" % msg) + return "" + return msg_a[-1] +def extract_node(msg): + msg_a = msg.split() + if len(msg_a) < 8: + # this looks too short + common_warn("log message <%s> unexpected format, please report a bug" % msg) + return "" + return msg_a[3] + +def get_matching_run_msg(te_invoke_msg, trans_msg_l): + run_msg = "" + pe_file = extract_pe_file(te_invoke_msg) pe_num = get_pe_num(pe_file) if pe_num == "-1": - common_debug("no PE number for file: %s" % pe_file) - return -1 - te_invoke_patt = vars.transition_patt[0].replace("%%", pe_num) + common_warn("%s: strange, transition number not found" % pe_file) + return "" run_patt = vars.transition_patt[1].replace("%%", pe_num) - r = re.search(te_invoke_patt, te_invoke_msg) - if not r: - return -1 - trans_num = r.group(1) - unpack_patt = vars.transition_patt[2].replace("%%", trans_num) - for msg in msg_l: - try: - return int(re.search(unpack_patt, msg).group(2)) - except: - if re.search(run_patt, msg): - act_d = run_graph_msg_actions(msg) - return sum(act_d.values()) - return -1 + for msg in trans_msg_l: + if re.search(run_patt, msg): + run_msg = msg + break + return run_msg + +class Transition(object): + ''' + Capture transition related information. + ''' + def __init__(self, te_invoke_msg, run_msg): + self.te_invoke_msg = te_invoke_msg + self.run_msg = run_msg + self.parse_msgs() + def __str__(self): + return "%s:%s" % (self.dc, \ + os.path.basename(self.pe_file).replace(".bz2","").replace("pe-","").replace("input-","")) + def parse_msgs(self): + self.pe_file = extract_pe_file(self.te_invoke_msg) + self.pe_num = get_pe_num(self.pe_file) + self.dc = extract_node(self.te_invoke_msg) + self.start_ts = syslog_ts(self.te_invoke_msg) + if self.run_msg: + self.end_ts = syslog_ts(self.run_msg) + else: + common_warn("end of transition %s not found in logs (transition not complete yet?)" % self) + self.end_ts = time.time() + def total_actions(self): + if self.run_msg: + act_d = run_graph_msg_actions(self.run_msg) + return sum(act_d.values()) + else: + return -1 + def transition_info(self): + print "Transition %s (%s -" % (self, shorttime(self.start_ts)), + if self.run_msg: + print "%s):" % shorttime(self.end_ts) + act_d = run_graph_msg_actions(self.run_msg) + total = sum(act_d.values()) + s = ", ".join(["%d %s" % (act_d[x], x) for x in act_d if act_d[x]]) + print "\ttotal %d actions: %s" % (total, s) + else: + print "[unfinished])" def mkarchive(dir): "Create an archive from a directory" @@ -420,6 +463,7 @@ print "Report saved in '%s'" % archive return True +CH_SRC, CH_TIME, CH_UPD = range(1,4) class Report(Singleton): ''' A hb_report class. @@ -430,18 +474,22 @@ "NORMAL", "GREEN", "CYAN", "MAGENTA", "YELLOW", "WHITE", "BLUE", "RED" ) session_sub = "session" + outdir = os.path.join(vars.report_cache, "psshout") + errdir = os.path.join(vars.report_cache, "pssherr") def __init__(self): + # main source attributes self.source = None - self.loc = None - self.ready = False self.from_dt = None self.to_dt = None - self.detail = 0 + self.log_l = [] + self.central_log = None + self.setnodes = [] # optional + # derived + self.loc = None + self.ready = False self.nodecolor = {} self.logobj = None self.desc = None - self.log_l = [] - self.central_log = None self.peinputs_l = [] self.cibgrp_d = {} self.cibcln_d = {} @@ -449,12 +497,13 @@ self.cibnotcloned_l = [] self.cibcloned_l = [] self.cibnode_l = [] - self.setnodes = [] - self.outdir = os.path.join(vars.report_cache,"psshout") - self.errdir = os.path.join(vars.report_cache,"pssherr") self.last_live_update = 0 + self.detail = 0 self.log_filter_out = [] self.log_filter_out_re = [] + # change_origin may be CH_SRC, CH_TIME, CH_UPD + # depending on the change_origin, we update our attributes + self.change_origin = CH_SRC def error(self, s): common_err("%s: %s" % (self.source, s)) def warn(self, s): @@ -464,7 +513,7 @@ def node_list(self): return self.cibnode_l def peinputs_list(self): - return [get_pe_num(x) for x in self.peinputs_l] + return [x.pe_num for x in self.peinputs_l] def session_subcmd_list(self): return ["save", "load", "pack", "delete", "list", "update"] def session_list(self): @@ -488,14 +537,16 @@ else: self.error("this doesn't look like a report tarball") return None + self.change_origin = CH_SRC if os.path.isdir(loc): return loc cwd = os.getcwd() - try: - os.chdir(parentdir) - except OSError,msg: - self.error(msg) - return None + if parentdir: + try: + os.chdir(parentdir) + except OSError,msg: + self.error(msg) + return None import tarfile try: tf = tarfile.open(bfname) @@ -514,6 +565,11 @@ if rc != 0: return None return loc + def pe_report_path(self, t_obj): + pe_base = os.path.basename(t_obj.pe_file) + return os.path.join(self.loc, t_obj.dc, "pengine", pe_base) + def short_pe_path(self, pe_file): + return pe_file.replace("%s/" % self.loc,"") def get_nodes(self): return [ os.path.basename(p) for p in os.listdir(self.loc) @@ -548,7 +604,7 @@ return True def _live_loc(self): return os.path.join(vars.report_cache,"live") - def is_last_live_recent(self): + def is_live_recent(self): ''' Look at the last live hb_report. If it's recent enough, return True. @@ -558,6 +614,12 @@ return (time.time() - last_ts <= self.live_recent) except: return False + def is_live_very_recent(self): + ''' + Look at the last live hb_report. If it's recent enough, + return True. + ''' + return (time.time() - self.last_live_update) <= self.short_live_recent def find_node_log(self, node): p = os.path.join(self.loc, node) for lf in ("ha-log.txt", "messages"): @@ -583,7 +645,7 @@ l.append(log) else: self.warn("no log found for node %s" % node) - self.log_l = l + return l def append_newlogs(self, a): ''' Append new logs fetched from nodes. @@ -596,51 +658,41 @@ continue append_file(rptlog,fl[0]) update_loginfo(rptlog, logfile, nextpos, fl[0]) - def unpack_new_peinputs(self, a): + def unpack_new_peinputs(self, node, pe_l): ''' Untar PE inputs fetched from nodes. ''' if not os.path.isdir(self.outdir): return - for node,pe_l in a: - fl = glob.glob("%s/*%s*" % (self.outdir,node)) - if not fl: - continue - u_dir = os.path.join(self.loc, node) - rc = pipe_cmd_nosudo("tar -C %s -x < %s" % (u_dir,fl[0])) - def find_new_peinputs(self, node_l): + fl = glob.glob("%s/*%s*" % (self.outdir,node)) + if not fl: + return -1 + u_dir = os.path.join(self.loc, node) + return pipe_cmd_nosudo("tar -C %s -x < %s" % (u_dir,fl[0])) + def find_new_peinputs(self, node): ''' Get a list of pe inputs appearing in new logs. The log is put in self.outdir/node by pssh. ''' if not os.path.isdir(self.outdir): return [] - l = [] - for node in node_l: - fl = glob.glob("%s/*%s*" % (self.outdir,node)) - if not fl: - continue - try: - f = open(fl[0]) - except IOError,msg: - common_err("open %s: %s"%(fl[0],msg)) - continue - pe_l = self.list_transitions([x for x in f], future_pe = True) - if pe_l: - l.append([node,pe_l]) - return l - def update_live(self): + fl = glob.glob("%s/*%s*" % (self.outdir,node)) + if not fl: + return [] + try: + f = open(fl[0]) + except IOError,msg: + common_err("open %s: %s" % (fl[0], msg)) + return [] + common_debug("updating transitions from logs") + return self.list_transitions([x for x in f], future_pe = True) + def update_live_report(self): ''' Update the existing live report, if it's older than self.short_live_recent: - append newer logs - get new PE inputs ''' - if (time.time() - self.last_live_update) <= self.short_live_recent: - return True - if _NO_PSSH: - warn_once("pssh not installed, slow live updates ahead") - return False a = [] common_info("fetching new logs, please wait ...") for rptlog in self.log_l: @@ -649,28 +701,38 @@ if logf: a.append([node, rptlog, logf, pos]) if not a: - common_info("no elligible logs found :(") + common_info("no elligible logs found") return False rmdir_r(self.outdir) rmdir_r(self.errdir) + self.logobj = None + self.last_live_update = time.time() rc1 = next_loglines(a, self.outdir, self.errdir) self.append_newlogs(a) - pe_l = self.find_new_peinputs([x[0] for x in a]) + new_peinputs_l = [] + node_pe_l = [] + for node in [x[0] for x in a]: + pe_l = self.find_new_peinputs(node) + if pe_l: + node_pe_l.append([node, [x.pe_file for x in pe_l]]) + new_peinputs_l += pe_l rmdir_r(self.outdir) rmdir_r(self.errdir) - rc2 = True - if pe_l: - rc2 = next_peinputs(pe_l, self.outdir, self.errdir) - self.unpack_new_peinputs(pe_l) - self.logobj = None + if not node_pe_l: + return rc1 + rc2 = next_peinputs(node_pe_l, self.outdir, self.errdir) + unpack_rc = 0 + for node,pe_l in node_pe_l: + unpack_rc |= self.unpack_new_peinputs(node, pe_l) + rc2 |= (unpack_rc == 0) rmdir_r(self.outdir) rmdir_r(self.errdir) - self.last_live_update = time.time() + self.peinputs_l += new_peinputs_l return (rc1 and rc2) def get_live_report(self): if not acquire_lock(vars.report_cache): return None - loc = self.new_live_hb_report() + loc = self.new_live_report() release_lock(vars.report_cache) return loc def manage_live_report(self, force = False): @@ -684,15 +746,22 @@ # the live report is there, but we were just invoked self.loc = d self.report_setup() - if not force and self.is_last_live_recent(): - if not acquire_lock(vars.report_cache): - return None - rc = self.update_live() - release_lock(vars.report_cache) - if rc: + if not force and self.is_live_recent(): + # try just to refresh the live report + if self.to_dt or self.is_live_very_recent(): return self._live_loc() + if not _NO_PSSH: + if not acquire_lock(vars.report_cache): + return None + rc = self.update_live_report() + release_lock(vars.report_cache) + if rc: + self.change_origin = CH_UPD + return self._live_loc() + else: + warn_once("pssh not installed, slow live updates ahead") return self.get_live_report() - def new_live_hb_report(self): + def new_live_report(self): ''' Run hb_report to get logs now. ''' @@ -720,7 +789,10 @@ return self.unpack_report(tarball) def set_source(self,src): 'Set our source.' - self.source = src + if self.source != src: + self.change_origin = CH_SRC + self.source = src + self.ready = False def set_period(self,from_dt,to_dt): ''' Set from/to_dt. @@ -732,6 +804,7 @@ self.from_dt = from_dt self.to_dt = to_dt if need_ref: + self.change_origin = CH_UPD self.refresh_source(force = True) if self.logobj: self.logobj.set_log_timeframe(self.from_dt, self.to_dt) @@ -747,19 +820,21 @@ not part of the cluster). ''' self.setnodes = args + def get_cib_loc(self): + nl = self.get_nodes() + if not nl: + return "" + return os.path.join(self.loc, nl[0], "cib.xml") def read_cib(self): ''' Get some information from the report's CIB (node list, resource list, groups). If "live" and not central log, then use cibadmin. ''' - nl = self.get_nodes() - if not nl: - return - if self.source == "live" and not self.central_log: - doc = cibdump2doc() - else: - doc = file2doc(os.path.join(self.loc,nl[0],"cib.xml")) + doc = None + cib_f = self.get_cib_loc() + if cib_f: + doc = file2doc(cib_f) if not doc: return # no cib? try: conf = doc.getElementsByTagName("configuration")[0] @@ -783,6 +858,16 @@ for n in self.cibnode_l: self.nodecolor[n] = self.nodecolors[i] i = (i+1) % len(self.nodecolors) + def get_invoke_trans_msgs(self, msg_l): + te_invoke_patt = vars.transition_patt[0].replace("%%", "[0-9]+") + return [x for x in msg_l if re.search(te_invoke_patt, x)] + def get_all_trans_msgs(self, msg_l=None): + trans_re_l = [x.replace("%%", "[0-9]+") for x in vars.transition_patt] + if not msg_l: + return self.logobj.get_matches(trans_re_l) + else: + re_s = '|'.join(trans_re_l) + return [x for x in msg_l if re.search(re_s, x)] def list_transitions(self, msg_l = None, future_pe = False): ''' List transitions by reading logs. @@ -790,57 +875,57 @@ Some callers need original PE file path (future_pe), otherwise we produce the path within the report and check if the transition files exist. + NB: future_pe means that the peinput has not been fetched yet. If the caller doesn't provide the message list, then we build it from the collected log files (self.logobj). Otherwise, we get matches for transition patterns. + + WARN: We rely here on the message format (syslog, + pacemaker). ''' - trans_re_l = [x.replace("%%", "[0-9]+") for x in vars.transition_patt] - if not msg_l: - msg_l = self.logobj.get_matches(trans_re_l) - else: - re_s = '|'.join(trans_re_l) - msg_l = [x for x in msg_l if re.search(re_s, x)] + trans_msg_l = self.get_all_trans_msgs(msg_l) + trans_start_msg_l = self.get_invoke_trans_msgs(trans_msg_l) pe_l = [] - for msg in msg_l: - msg_a = msg.split() - if len(msg_a) < 8: - # this looks too short - common_warn("log message <%s> unexpected format, please report a bug" % msg) - continue - if "run_graph:" in msg: - continue # we want another message - common_debug("trans msg use: %s" % msg_a) - node = msg_a[3] - pe_file = msg_a[-1] - pe_base = os.path.basename(pe_file) - num_actions = transition_actions(msg_l, msg, pe_file) - if num_actions <= 0: # empty transition - common_debug("skipping empty transition (%s)" % pe_base) + for msg in trans_start_msg_l: + run_msg = get_matching_run_msg(msg, trans_msg_l) + t_obj = Transition(msg, run_msg) + num_actions = t_obj.total_actions() + if num_actions == 0: # empty transition + common_debug("skipping empty transition (%s)" % t_obj) continue if not future_pe: - pe_l_file = os.path.join(self.loc, node, "pengine", pe_base) + pe_l_file = self.pe_report_path(t_obj) if not os.path.isfile(pe_l_file): - warn_once("%s in the logs, but not in the report" % pe_l_file) + warn_once("%s in the logs, but not in the report" % t_obj) continue - else: - pe_l_file = pe_file - if pe_l_file in pe_l: - common_debug("duplicate %s, replacing older PE file" % pe_l_file) - pe_l.remove(pe_l_file) - common_debug("found PE input: %s" % pe_l_file) - pe_l.append(pe_l_file) + common_debug("found PE input: %s" % t_obj) + pe_l.append(t_obj) return pe_l def report_setup(self): + if not self.change_origin: + return if not self.loc: return - self.desc = os.path.join(self.loc,"description.txt") - self.find_logs() - self.find_central_log() - self.read_cib() - self.set_node_colors() + if self.change_origin == CH_SRC: + vars.pcmk_version = None + self.desc = os.path.join(self.loc,"description.txt") + self.log_l = self.find_logs() + self.find_central_log() + self.read_cib() + self.set_node_colors() + elif self.change_origin == CH_UPD: + l = self.find_logs() + if self.log_l != l: + self.log_l = l + self.read_cib() + self.set_node_colors() self.logobj = LogSyslog(self.central_log, self.log_l, \ self.from_dt, self.to_dt) - self.peinputs_l = self.list_transitions() + if self.change_origin != CH_UPD: + common_debug("getting transitions from logs") + self.peinputs_l = self.list_transitions() + self.ready = self.check_report() + self.change_origin = 0 def prepare_source(self): ''' Unpack a hb_report tarball. @@ -862,7 +947,6 @@ if not self.loc: return False self.report_setup() - self.ready = self.check_report() return self.ready def refresh_source(self, force = False): ''' @@ -874,13 +958,19 @@ self.last_live_update = 0 self.loc = self.manage_live_report(force) self.report_setup() - self.ready = self.check_report() return self.ready def get_patt_l(self,type): ''' get the list of patterns for this type, up to and including current detail level ''' + cib_f = None + if self.source != "live" or self.central_log: + cib_f = self.get_cib_loc() + if is_pcmk_118(cib_f=cib_f): + from log_patterns_118 import log_patterns + else: + from log_patterns import log_patterns if not type in log_patterns: common_error("%s not featured in log patterns" % type) return None @@ -974,72 +1064,28 @@ self.error("no resources or nodes found") return False self.show_logs(re_l = all_re_l) - def get_transition_msgs(self, pe_file, msg_l = None): - if not msg_l: - trans_re_l = [x.replace("%%", "[0-9]+") for x in vars.transition_patt] - msg_l = self.logobj.get_matches(trans_re_l) - te_invoke_msg = "" - run_msg = "" - unpack_msg = "" - pe_num = get_pe_num(pe_file) - te_invoke_patt = vars.transition_patt[0].replace("%%", pe_num) - run_patt = vars.transition_patt[1].replace("%%", pe_num) - r = None - msg_l.reverse() - for msg in msg_l: - r = re.search(te_invoke_patt, msg) - if r: - te_invoke_msg = msg - break - if not r: - return ["", "", ""] - trans_num = r.group(1) - unpack_patt = vars.transition_patt[2].replace("%%", trans_num) - for msg in msg_l: - if re.search(run_patt, msg): - run_msg = msg - elif re.search(unpack_patt, msg): - unpack_msg = msg - if run_msg and unpack_msg: - break - return [unpack_msg, te_invoke_msg, run_msg] - def show_transition_log(self, pe_file): + def find_peinput(self, pe_file): + for t_obj in self.peinputs_l: + if self.pe_report_path(t_obj) == pe_file: + return t_obj + return None + def show_transition_log(self, pe_file, full_log=False): ''' Search for events within the given transition. ''' if not self.prepare_source(): return False - pe_base = os.path.basename(pe_file) - pe_num = get_pe_num(pe_base) - unpack_msg, te_invoke_msg, run_msg = self.get_transition_msgs(pe_file) - if not te_invoke_msg: - common_warn("start of transition %s not found in logs" % pe_base) + t_obj = self.find_peinput(pe_file) + if not t_obj: + common_err("%s: transition not found" % pe_file) return False - if not run_msg: - common_warn("end of transition %s not found in logs (transition not complete yet?)" % pe_base) - return False - common_debug("transition start: %s" % te_invoke_msg) - common_debug("transition end: %s" % run_msg) - start_ts = syslog_ts(te_invoke_msg) - end_ts = syslog_ts(run_msg) - if not start_ts or not end_ts: - self.warn("strange, no timestamps found") - return False - act_d = run_graph_msg_actions(run_msg) - total = sum(act_d.values()) - s = "" - for a in act_d: - if not act_d[a]: - continue - s = "%s %s=%d" % (s, a, act_d[a]) - common_info("transition %s %d actions: %s" % - (pe_file.replace(self.loc+"/",""), total, s)) - common_info("logs for transition %s (%s-%s)" % - (pe_file.replace(self.loc+"/",""), \ - shorttime(start_ts), shorttime(end_ts))) # limit the log scope temporarily - self.logobj.set_log_timeframe(start_ts, end_ts) - self.events() + self.logobj.set_log_timeframe(t_obj.start_ts, t_obj.end_ts) + if full_log: + self.show_logs() + else: + t_obj.transition_info() + self.events() self.logobj.set_log_timeframe(self.from_dt, self.to_dt) return True def resource(self,*args): @@ -1103,8 +1149,8 @@ a.append(a[0]) elif a is not None: a = [a,a] - return [x for x in self.peinputs_l \ - if pe_file_in_range(x, a)] + return [self.pe_report_path(x) for x in self.peinputs_l \ + if pe_file_in_range(x.pe_file, a)] def dotlist(self, a = None): l = [x.replace("bz2","dot") for x in self.pelist(a)] return [x for x in l if os.path.isfile(x)] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/ui.py.in new/crmsh/modules/ui.py.in --- old/crmsh/modules/ui.py.in 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/ui.py.in 2012-12-11 18:29:34.000000000 +0100 @@ -122,6 +122,7 @@ self.cmd_table["check-mode"] = (self.set_check_mode,(1,1),0,0) self.cmd_table["sort-elements"] = (self.set_sort_elements,(1,1),0,0) self.cmd_table["wait"] = (self.set_wait,(1,1),0,0) + self.cmd_table["add-quotes"] = (self.set_add_quotes,(1,1),0,0) self.cmd_table["save"] = (self.save_options,(0,0),0,0) self.cmd_table["show"] = (self.show_options,(0,0),0,0) setup_aliases(self) @@ -162,6 +163,12 @@ common_err("%s: bad boolean option"%opt) return True return user_prefs.set_wait(opt) + def set_add_quotes(self,cmd,opt): + "usage: add-quotes {yes|no}" + if not verify_boolean(opt): + common_err("%s: bad boolean option"%opt) + return True + return user_prefs.set_add_quotes(opt) def show_options(self,cmd): "usage: show" return user_prefs.write_rc(sys.stdout) @@ -1761,6 +1768,7 @@ self.cmd_aliases.update({ "limit": ("timeframe",), }) + setup_aliases(self) self._set_source(options.history) self.current_session = None def _no_source(self): @@ -1922,14 +1930,15 @@ return l[0] def transition(self,cmd,*args): """usage: transition [<number>|<index>|<file>] [nograph] [v...] [scores] [actions] [utilization] - transition showdot [<number>|<index>|<file>]""" + transition showdot [<number>|<index>|<file>] + transition log [<number>|<index>|<file>]""" argl = list(args) subcmd = "show" - if argl and argl[0] == "showdot": - if not user_prefs.dotty: + if argl and argl[0] in ("showdot", "log"): + if argl[0] == "showdot" and not user_prefs.dotty: common_err("install graphviz to draw transition graphs") return False - subcmd = "showdot" + subcmd = argl[0] argl.remove(subcmd) if argl: if re.search('pe-', argl[0]): @@ -1949,18 +1958,21 @@ if not f: return False rc = True + full_log = False if subcmd == "show": self.pe_file = f # self.pe_file needed by self.ptest common_info("running ptest with %s" % f) rc = ptestlike(self.ptest,'vv', cmd, *argl) - else: + elif subcmd == "showdot": f = crm_report.pe2dot(f) if not f: common_err("dot file not found in the report") return False show_dot_graph(f) + else: + full_log = True if rc: - crm_report.show_transition_log(f) + rc = crm_report.show_transition_log(f, full_log) return rc def session(self,cmd,subcmd = None,name = None): "usage: session [{save|load|delete} <name> | pack [<name>] | update | list]" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/userprefs.py new/crmsh/modules/userprefs.py --- old/crmsh/modules/userprefs.py 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/userprefs.py 2012-12-11 18:29:34.000000000 +0100 @@ -79,6 +79,7 @@ self.force = False self.sort_elems = "yes" self.wait = False + self.add_quotes = "yes" def missing(self,n): common_err("could not find any %s on the system" % n) def check_skill_level(self,n): @@ -168,6 +169,10 @@ self.wait = is_boolean_true(opt) and "yes" or "no" def get_wait(self): return self.wait == "yes" + def set_add_quotes(self,opt): + self.add_quotes = is_boolean_true(opt) and "yes" or "no" + def get_add_quotes(self): + return self.add_quotes == "yes" def write_rc(self,f): print >>f, '%s "%s"' % ("editor",self.editor) print >>f, '%s "%s"' % ("pager",self.pager) @@ -179,6 +184,7 @@ print >>f, '%s "%s"' % ("check-frequency",self.check_frequency) print >>f, '%s "%s"' % ("check-mode",self.check_mode) print >>f, '%s "%s"' % ("wait",self.wait) + print >>f, '%s "%s"' % ("add-quotes",self.add_quotes) def save_options(self,rc_file): try: f = open(rc_file,"w") except IOError,msg: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/utils.py new/crmsh/modules/utils.py --- old/crmsh/modules/utils.py 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/utils.py 2012-12-11 18:29:34.000000000 +0100 @@ -155,6 +155,7 @@ def filter_string(cmd,s,stderr_on = True): rc = -1 # command failed + outp = '' if stderr_on: stderr = None else: @@ -167,8 +168,13 @@ outp = p.communicate(s)[0] p.wait() rc = p.returncode - except IOError, msg: + except OSError, (errno, strerror): + if errno != os.errno.EPIPE: + common_err(strerror) + common_info("from: %s" % cmd) + except Exception, msg: common_err(msg) + common_info("from: %s" % cmd) return rc,outp def str2tmp(s): @@ -381,6 +387,9 @@ cmd = "crmadmin -S %s" % dc cnt = 0 output_started = 0 + init_sleep = 0.25 + max_sleep = 1.00 + sleep_time = init_sleep while True: s = get_stdout(add_sudo(cmd)) if not s.startswith("Status"): @@ -394,7 +403,9 @@ if output_started: sys.stderr.write(" done\n") return True - time.sleep(0.1) + time.sleep(sleep_time) + if sleep_time < max_sleep: + sleep_time *= 2 if show_progress: if not output_started: output_started = 1 @@ -620,6 +631,8 @@ if len(s) > max_len: max_len = len(s) cols = w/(max_len + min_gap) # approx. + if not cols: + cols = 1 col_len = w/cols for i in range(len(l)/cols + 1): s = '' @@ -691,6 +704,55 @@ return None return dt +def get_pcmk_version(dflt): + try: + v = get_stdout("crmd version").split()[2] + common_debug("found pacemaker version: %s" % v) + except Exception,msg: + v = dflt + common_warn("could not get the pacemaker version, bad installation?") + return v + +def get_cib_property(cib_f, attr, dflt): + """A poor man's get attribute procedure. + We don't want heavy parsing, this needs to be relatively + fast. + """ + open_t = "<cluster_property_set" + close_t = "</cluster_property_set" + attr_s = 'name="%s"' % attr + ver_patt = re.compile('value="([^"]+)"') + ver = dflt # return some version in any case + try: f = open(cib_f, "r") + except IOError, msg: + common_err(msg) + return ver + state = 0 + for s in f: + if state == 0: + if open_t in s: + state += 1 + elif state == 1: + if close_t in s: + break + if attr_s in s: + r = ver_patt.search(s) + if r: + ver = r.group(1) + break + f.close() + return ver + +def is_pcmk_118(cib_f=None): + if not vars.pcmk_version: + if cib_f: + vars.pcmk_version = get_cib_property(cib_f, "dc-version", "1.1.1") + common_debug("found pacemaker version: %s in cib: %s" % (ver, cib_f)) + else: + vars.pcmk_version = get_pcmk_version("1.1.1") + from distutils.version import LooseVersion + return LooseVersion(vars.pcmk_version) >= LooseVersion("1.1.8") + user_prefs = UserPrefs.getInstance() options = Options.getInstance() vars = Vars.getInstance() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/vars.py.in new/crmsh/modules/vars.py.in --- old/crmsh/modules/vars.py.in 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/modules/vars.py.in 2012-12-11 18:29:34.000000000 +0100 @@ -205,6 +205,7 @@ crm_daemon_dir = "@CRM_DAEMON_DIR@" crm_daemon_user = "@CRM_DAEMON_USER@" crm_version = "@VERSION@ (Build @BUILD_VERSION@)" + nagios_dir = "/usr/lib/nagios/plugins" ra_if = None # class interface to RA stonithd_metadata = None # stonithd meta data @@ -226,16 +227,17 @@ if not ocf_root: ocf_root = "/usr/lib/ocf" os.environ["OCF_ROOT"] = ocf_root + pcmk_version = "" # set later # r.group(1) transition number (a different thing from file number) # r.group(2) contains full path # r.group(3) file number transition_patt = [ "crmd.* do_te_invoke: Processing graph ([0-9]+) .*derived from (.*/pe-[^-]+-(%%)[.]bz2)", # transition start + # r.group(1) transition number (a different thing from file number) + # r.group(2) contains full path + # r.group(3) transition status "crmd.* run_graph: .*Transition ([0-9]+).*Source=(.*/pe-[^-]+-(%%)[.]bz2).: (Stopped|Complete|Terminated)", # and stop - # r.group(1) transition number - # r.group(2) number of actions - "crmd.* run_graph: .*Transition (%%) .*Complete=([0-9]+),", # number of actions ] # vim:ts=4:sw=4:et: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/testcases/Makefile.am new/crmsh/test/testcases/Makefile.am --- old/crmsh/test/testcases/Makefile.am 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/test/testcases/Makefile.am 2012-12-11 18:29:34.000000000 +0100 @@ -22,10 +22,10 @@ testcases_SCRIPTS = ra.filter xmlonly.sh testcases_DATA = BSC basicset common.excl \ confbasic confbasic-xml delete file node ra resource shadow acl \ - rset rset-xml \ + edit rset rset-xml \ confbasic-xml.exp confbasic.exp delete.exp file.exp \ node.exp ra.exp resource.exp shadow.exp acl.exp \ - rset.exp rset-xml.exp + edit.exp rset.exp rset-xml.exp confbasic-xml.filter: ln xmlonly.sh $@ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/testcases/basicset new/crmsh/test/testcases/basicset --- old/crmsh/test/testcases/basicset 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/test/testcases/basicset 2012-12-11 18:29:34.000000000 +0100 @@ -1,5 +1,6 @@ confbasic confbasic-xml +edit rset rset-xml delete diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/testcases/edit new/crmsh/test/testcases/edit --- old/crmsh/test/testcases/edit 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/test/testcases/edit 2012-12-11 18:29:34.000000000 +0100 @@ -4,7 +4,7 @@ attributes mem=16G primitive st stonith:null \ params hostlist='node1' \ - meta yoyo-meta="yoyo 2" \ + meta description="some description here" \ op start requires=nothing \ op monitor interval=60m primitive p1 ocf:heartbeat:Dummy \ @@ -29,6 +29,11 @@ primitive d3 ocf:heartbeat:Dummy group g2 d1 d2 filter "sed '/g2/s/d1/p1/;/g1/s/p1/d1/'" +filter "sed '$alocation loc-d1 d1 rule $id=r1 -inf: not_defined webserver rule $id=r2 webserver: defined webserver'" +filter "sed 's/not_defined webserver/& or mem number:lte 0/'" loc-d1 +filter "sed 's/ or mem number:lte 0//'" loc-d1 +filter "sed 's/not_defined webserver/& rule -inf: not_defined a2/'" loc-d1 +filter "sed 's/not_defined webserver/& or mem number:lte 0/'" loc-d1 _test verify . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/testcases/edit.exp new/crmsh/test/testcases/edit.exp --- old/crmsh/test/testcases/edit.exp 2012-10-15 20:13:49.000000000 +0200 +++ new/crmsh/test/testcases/edit.exp 2012-12-11 18:29:34.000000000 +0100 @@ -5,7 +5,7 @@ .INP: erase nodes .INP: property default-action-timeout=2m .INP: node node1 attributes mem=16G -.INP: primitive st stonith:null params hostlist='node1' meta yoyo-meta="yoyo 2" op start requires=nothing op monitor interval=60m +.INP: primitive st stonith:null params hostlist='node1' meta description="some description here" op start requires=nothing op monitor interval=60m .INP: primitive p1 ocf:heartbeat:Dummy op monitor interval=60m op monitor interval=120m OCF_CHECK_LEVEL=10 .INP: filter "sed '$aprimitive p2 ocf:heartbeat:Dummy'" .INP: filter "sed '$agroup g1 p1 p2'" @@ -29,6 +29,11 @@ .INP: filter "sed '/g2/s/d1/p1/;/g1/s/p1/d1/'" ERROR: 27: d1 already in use at g2 ERROR: 27: p1 already in use at g1 +.INP: filter "sed '$alocation loc-d1 d1 rule $id=r1 -inf: not_defined webserver rule $id=r2 webserver: defined webserver'" +.INP: filter "sed 's/not_defined webserver/& or mem number:lte 0/'" loc-d1 +.INP: filter "sed 's/ or mem number:lte 0//'" loc-d1 +.INP: filter "sed 's/not_defined webserver/& rule -inf: not_defined a2/'" loc-d1 +.INP: filter "sed 's/not_defined webserver/& or mem number:lte 0/'" loc-d1 .INP: _test .INP: verify .INP: show @@ -44,13 +49,17 @@ primitive p3 ocf:heartbeat:Dummy primitive st stonith:null \ params hostlist="node1" \ - meta yoyo-meta="yoyo 2" \ + meta description="some description here" \ op start interval="0" requires="nothing" \ op monitor interval="60m" group g1 p1 p2 group g2 d1 d2 clone c1 g1 location l1 p3 100: node1 +location loc-d1 d1 \ + rule $id="r1" -inf: not_defined webserver or mem number:lte 0 \ + rule $id="loc-d1-rule" -inf: not_defined a2 \ + rule $id="r2" webserver: defined webserver order o1 inf: p3 c1 property $id="cib-bootstrap-options" \ default-action-timeout="2m" -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org