Hello community,
here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2012-12-28 14:56:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
and /work/SRC/openSUSE:Factory/.crmsh.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh", Maintainer is "DMuhamedagic@suse.com"
Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2012-12-19 10:50:40.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2012-12-28 14:56:19.000000000 +0100
@@ -1,0 +2,12 @@
+Wed Dec 19 14:27:48 UTC 2012 - dmuhamedagic@suse.com
+
+- history: force refresh on session load
+- history: detailed transition output
+- history: add colours to info
+- history: try always to print some real time period
+- history: print transitions in info
+- history: fix regression when creating log objects
+- history: implement transition save (to shadow) subcommand
+- upstream cs: 7c09f05419e6 (v1.2.4)
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.zFqxW0/_old 2012-12-28 14:56:21.000000000 +0100
+++ /var/tmp/diff_new_pack.zFqxW0/_new 2012-12-28 14:56:21.000000000 +0100
@@ -45,7 +45,7 @@
Summary: Pacemaker command line interface
License: GPL-2.0
Group: %{pkg_group}
-Version: 1.2.3
+Version: 1.2.4
Release: 0
Url: http://savannah.nongnu.org/projects/crmsh
Source0: crmsh.tar.bz2
@@ -90,6 +90,7 @@
%if 0%{?with_regression_tests}
BuildRequires: corosync
BuildRequires: procps
+BuildRequires: python-dateutil
BuildRequires: vim-base
Requires: pacemaker
%endif
++++++ 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-12-11 18:29:34.000000000 +0100
+++ new/crmsh/.hg_archival.txt 2012-12-19 13:36:50.000000000 +0100
@@ -1,5 +1,5 @@
repo: 13c3bd69e935090cd25213c474cafc3f01b5910b
-node: 355467d3974841ba2f0400ffe6cb251d88185786
+node: 7c09f05419e6d3a5abfef3afdfe92053a83cec8e
branch: default
latesttag: crmsh-1.2.3
-latesttagdistance: 1
+latesttagdistance: 20
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/ChangeLog new/crmsh/ChangeLog
--- old/crmsh/ChangeLog 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/ChangeLog 2012-12-19 13:36:50.000000000 +0100
@@ -1,3 +1,11 @@
+* Mon Dec 17 2012 Dejan Muhamedagic and many others
+- stable release 1.2.4
+- shadow: return proper exit code on I/O errors
+- history: implement transition save (to shadow) subcommand
+- history: fix regression when creating log objects
+- history: detailed transition output
+- history: force refresh on session load
+
* Tue Dec 11 2012 Dejan Muhamedagic and many others
- stable release 1.2.3
- ra: don't print duplicate RAs in the list command (bnc#793585)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/configure.ac new/crmsh/configure.ac
--- old/crmsh/configure.ac 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/configure.ac 2012-12-19 13:36:50.000000000 +0100
@@ -21,7 +21,7 @@
dnl checks for library functions
dnl checks for system services
-AC_INIT(crmsh, 1.2.3, linux-ha@lists.linux-ha.org)
+AC_INIT(crmsh, 1.2.4, linux-ha@lists.linux-ha.org)
AC_ARG_WITH(version,
[ --with-version=version Override package version (if you're a packager needing to pretend) ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/crmsh.spec new/crmsh/crmsh.spec
--- old/crmsh/crmsh.spec 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/crmsh.spec 2012-12-19 13:36:50.000000000 +0100
@@ -17,7 +17,7 @@
Name: crmsh
Summary: Pacemaker command line interface
-Version: 1.2.3
+Version: 1.2.4
Release: %{crmsh_release}%{?dist}
License: GPLv2+
Url: http://www.clusterlabs.org
@@ -27,6 +27,7 @@
AutoReqProv: on
Requires(pre): pacemaker
Requires: python >= 2.4
+Requires: python-dateutil
%if 0%{?suse_version}
# Suse splits this off into a separate package
@@ -40,7 +41,7 @@
BuildRequires: asciidoc
%if 0%{?with_regression_tests}
-BuildRequires: corosync procps vim-base
+BuildRequires: corosync procps vim-base python-dateutil
Requires: pacemaker
%endif
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-12-11 18:29:34.000000000 +0100
+++ new/crmsh/doc/crm.8.txt 2012-12-19 13:36:50.000000000 +0100
@@ -3034,10 +3034,15 @@
The `log` subcommand shows the full log for the duration of the
transition.
+A transition can also be saved to a CIB shadow for further
+analysis or use with `cib` or `configure` commands (use the
+`save` subcommand). The shadow file name defaults to the name of
+the PE input file.
+
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
-chosen.
+last one, i.e. the last transition. The last transition can also
+be referenced with number 0. If the number is negative, then the
+corresponding transition relative to the last one is chosen.
If there are warning and error PE input files or different nodes
were the DC in the observed timeframe, it may happen that PE
@@ -3052,6 +3057,7 @@
transition [<number>|<index>|<file>] [nograph] [v...] [scores] [actions] [utilization]
transition showdot [<number>|<index>|<file>]
transition log [<number>|<index>|<file>]
+ transition save [<number>|<index>|<file> [name]]
...............
Examples:
...............
@@ -3062,6 +3068,7 @@
transition node-a/pengine/pe-input-2.bz2
transition showdot 444
transition log
+ transition save 0 enigma-22
...............
[[cmdhelp_history_session,manage history sessions]]
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-12-11 18:29:34.000000000 +0100
+++ new/crmsh/modules/report.py 2012-12-19 13:36:50.000000000 +0100
@@ -409,6 +409,13 @@
break
return run_msg
+def trans_str(node, pe_file):
+ '''Convert node,pe_file to transition sting.'''
+ return "%s:%s" % (node, os.path.basename(pe_file).replace(".bz2",""))
+def rpt_pe2t_str(rpt_pe_file):
+ '''Convert report's pe_file path to transition sting.'''
+ node = os.path.basename(os.path.dirname(os.path.dirname(rpt_pe_file)))
+ return trans_str(node, rpt_pe_file)
class Transition(object):
'''
Capture transition related information.
@@ -418,8 +425,7 @@
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-",""))
+ return trans_str(self.dc, self.pe_file)
def parse_msgs(self):
self.pe_file = extract_pe_file(self.te_invoke_msg)
self.pe_num = get_pe_num(self.pe_file)
@@ -430,12 +436,14 @@
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):
+ def actions_count(self):
if self.run_msg:
act_d = run_graph_msg_actions(self.run_msg)
return sum(act_d.values())
else:
return -1
+ def shortname(self):
+ return os.path.basename(self.pe_file).replace(".bz2","")
def transition_info(self):
print "Transition %s (%s -" % (self, shorttime(self.start_ts)),
if self.run_msg:
@@ -463,7 +471,7 @@
print "Report saved in '%s'" % archive
return True
-CH_SRC, CH_TIME, CH_UPD = range(1,4)
+CH_SRC, CH_TIME, CH_UPD = 1, 2, 3
class Report(Singleton):
'''
A hb_report class.
@@ -537,7 +545,7 @@
else:
self.error("this doesn't look like a report tarball")
return None
- self.change_origin = CH_SRC
+ self.set_change_origin(CH_SRC)
if os.path.isdir(loc):
return loc
cwd = os.getcwd()
@@ -669,9 +677,9 @@
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):
+ def read_new_log(self, node):
'''
- Get a list of pe inputs appearing in new logs.
+ Get a list of log lines.
The log is put in self.outdir/node by pssh.
'''
if not os.path.isdir(self.outdir):
@@ -684,8 +692,7 @@
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)
+ return f.readlines()
def update_live_report(self):
'''
Update the existing live report, if it's older than
@@ -705,17 +712,18 @@
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)
- new_peinputs_l = []
node_pe_l = []
for node in [x[0] for x in a]:
- pe_l = self.find_new_peinputs(node)
+ log_l = self.read_new_log(node)
+ pe_l = []
+ for new_t_obj in self.list_transitions(log_l, future_pe=True):
+ self.new_peinput(new_t_obj)
+ pe_l.append(new_t_obj.pe_file)
if pe_l:
- node_pe_l.append([node, [x.pe_file for x in pe_l]])
- new_peinputs_l += pe_l
+ node_pe_l.append([node, pe_l])
rmdir_r(self.outdir)
rmdir_r(self.errdir)
if not node_pe_l:
@@ -727,7 +735,6 @@
rc2 |= (unpack_rc == 0)
rmdir_r(self.outdir)
rmdir_r(self.errdir)
- self.peinputs_l += new_peinputs_l
return (rc1 and rc2)
def get_live_report(self):
if not acquire_lock(vars.report_cache):
@@ -756,7 +763,7 @@
rc = self.update_live_report()
release_lock(vars.report_cache)
if rc:
- self.change_origin = CH_UPD
+ self.set_change_origin(CH_UPD)
return self._live_loc()
else:
warn_once("pssh not installed, slow live updates ahead")
@@ -790,7 +797,7 @@
def set_source(self,src):
'Set our source.'
if self.source != src:
- self.change_origin = CH_SRC
+ self.set_change_origin(CH_SRC)
self.source = src
self.ready = False
def set_period(self,from_dt,to_dt):
@@ -798,16 +805,17 @@
Set from/to_dt.
'''
common_debug("setting report times: <%s> - <%s>" % (from_dt,to_dt))
- need_ref = (self.source == "live") and \
+ need_refresh = (self.source == "live") and \
((from_dt and self.from_dt and self.from_dt > from_dt) or \
(to_dt and self.to_dt and self.to_dt < to_dt))
self.from_dt = from_dt
self.to_dt = to_dt
- if need_ref:
- self.change_origin = CH_UPD
+ if need_refresh:
+ self.set_change_origin(CH_UPD)
self.refresh_source(force = True)
- if self.logobj:
- self.logobj.set_log_timeframe(self.from_dt, self.to_dt)
+ else:
+ self.set_change_origin(CH_TIME)
+ self.report_setup()
return True
def set_detail(self,detail_lvl):
'''
@@ -844,8 +852,11 @@
for x in conf.getElementsByTagName("primitive") ]
self.cibnode_l = [ x.getAttribute("uname")
for x in conf.getElementsByTagName("node") ]
+ self.cibgrp_d = {}
for grp in conf.getElementsByTagName("group"):
self.cibgrp_d[grp.getAttribute("id")] = get_rsc_children_ids(grp)
+ self.cibcln_d = {}
+ self.cibcloned_l = []
for cln in conf.getElementsByTagName("clone") + \
conf.getElementsByTagName("master"):
try:
@@ -853,6 +864,13 @@
self.cibcloned_l += self.cibcln_d[cln.getAttribute("id")]
except: pass
self.cibnotcloned_l = [x for x in self.cibrsc_l if x not in self.cibcloned_l]
+ def new_peinput(self, new_pe):
+ t_obj = self.find_peinput(str(new_pe))
+ if t_obj:
+ common_debug("duplicate %s, replacing older PE file" % t_obj)
+ self.peinputs_l.remove(t_obj)
+ common_debug("appending new PE %s" % new_pe)
+ self.peinputs_l.append(new_pe)
def set_node_colors(self):
i = 0
for n in self.cibnode_l:
@@ -885,11 +903,10 @@
'''
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 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()
+ num_actions = t_obj.actions_count()
if num_actions == 0: # empty transition
common_debug("skipping empty transition (%s)" % t_obj)
continue
@@ -899,8 +916,7 @@
warn_once("%s in the logs, but not in the report" % t_obj)
continue
common_debug("found PE input: %s" % t_obj)
- pe_l.append(t_obj)
- return pe_l
+ yield t_obj
def report_setup(self):
if not self.change_origin:
return
@@ -923,9 +939,11 @@
self.from_dt, self.to_dt)
if self.change_origin != CH_UPD:
common_debug("getting transitions from logs")
- self.peinputs_l = self.list_transitions()
+ self.peinputs_l = []
+ for new_t_obj in self.list_transitions():
+ self.new_peinput(new_t_obj)
self.ready = self.check_report()
- self.change_origin = 0
+ self.set_change_origin(0)
def prepare_source(self):
'''
Unpack a hb_report tarball.
@@ -988,17 +1006,20 @@
else:
re_l = mk_re_list(patt_l,r'(%s)' % "|".join(args))
return re_l
- def disp(self, s):
- 'color output'
- a = s.split()
- try: clr = self.nodecolor[a[3]]
+ def _str_nodecolor(self, node, s):
+ try: clr = self.nodecolor[node]
except: return s
try:
return "${%s}%s${NORMAL}" % (clr,s)
except:
- # ${..} in logs?
s = s.replace("${","$.{")
return "${%s}%s${NORMAL}" % (clr,s)
+ def disp(self, s):
+ 'color output'
+ a = s.split()
+ try: node = a[3]
+ except: return s
+ return self._str_nodecolor(node, s)
def match_filter_out(self, s):
for re in self.log_filter_out_re:
if re.search(s):
@@ -1035,22 +1056,55 @@
def dumpdescln(self, pfx, field):
s = self.get_desc_line(field)
if s:
- print "%s: %s" % (pfx, s)
+ return "%s: %s" % (pfx, s)
+ def short_peinputs_list(self):
+ '''There could be quite a few transitions, limit the
+ output'''
+ max_output = 20
+ s = ""
+ if len(self.peinputs_l) > max_output:
+ s = "... "
+ return "%s%s" % (s, \
+ ' '.join([self._str_nodecolor(x.dc, x.pe_num) \
+ for x in self.peinputs_l[-max_output:]]))
+ def get_rpt_dt(self, dt, whence):
+ '''
+ Figure out the time of the start/end of the report.
+ The ts input is the time stamp set by user (it can be
+ empty). whence is set either to "top" or "bottom".
+ '''
+ if dt:
+ return dt
+ try:
+ log_l = self.logobj.get_matches([])
+ if whence == "top":
+ myts = syslog_ts(log_l[0])
+ elif whence == "bottom":
+ myts = syslog_ts(log_l[-1])
+ return datetime.datetime.fromtimestamp(myts)
+ except:
+ return None
+ def _str_dt(self, dt):
+ return dt and human_date(dt) or "--/--/-- --:--:--"
def info(self):
'''
Print information about the source.
'''
if not self.prepare_source():
return False
- print "Source: %s" % self.source
- self.dumpdescln("Created on", "Date")
- self.dumpdescln("By", "By")
- print "Period: %s - %s" % \
- ((self.from_dt and human_date(self.from_dt) or "start"),
- (self.to_dt and human_date(self.to_dt) or "end"))
- print "Nodes:",' '.join(self.cibnode_l)
- print "Groups:",' '.join(self.cibgrp_d.keys())
- print "Resources:",' '.join(self.cibrsc_l)
+ page_string('\n'.join((
+ "Source: %s" % self.source,
+ self.dumpdescln("Created on", "Date") or "Created on: --:--:--",
+ self.dumpdescln("By", "By") or "By: unknown",
+ "Period: %s - %s" % \
+ (self._str_dt(self.get_rpt_dt(self.from_dt, "top")), \
+ self._str_dt(self.get_rpt_dt(self.to_dt, "bottom"))),
+ "Nodes: %s" % ' '.join([ self._str_nodecolor(x, x) \
+ for x in self.cibnode_l ]),
+ "Groups: %s" % ' '.join(self.cibgrp_d.keys()),
+ "Resources: %s" % ' '.join(self.cibrsc_l),
+ "Transitions: %s" % self.short_peinputs_list(),
+ )))
def events(self):
'''
Show all events.
@@ -1064,20 +1118,20 @@
self.error("no resources or nodes found")
return False
self.show_logs(re_l = all_re_l)
- def find_peinput(self, pe_file):
+ def find_peinput(self, t_str):
for t_obj in self.peinputs_l:
- if self.pe_report_path(t_obj) == pe_file:
+ if str(t_obj) == t_str:
return t_obj
return None
- def show_transition_log(self, pe_file, full_log=False):
+ def show_transition_log(self, rpt_pe_file, full_log=False):
'''
Search for events within the given transition.
'''
if not self.prepare_source():
return False
- t_obj = self.find_peinput(pe_file)
+ t_obj = self.find_peinput(rpt_pe2t_str(rpt_pe_file))
if not t_obj:
- common_err("%s: transition not found" % pe_file)
+ common_err("%s: transition not found" % rpt_pe_file)
return False
# limit the log scope temporarily
self.logobj.set_log_timeframe(t_obj.start_ts, t_obj.end_ts)
@@ -1141,7 +1195,23 @@
if not l:
return False
self.show_logs(log_l = l)
- def pelist(self, a = None):
+ pe_details_header = \
+"Start End Filename Client User Origin"
+ pe_details_separator = \
+"===== === ======== ====== ==== ======"
+ def pe_detail_format(self, t_obj):
+ l = [
+ shorttime(t_obj.start_ts),
+ t_obj.end_ts and shorttime(t_obj.end_ts) or "--:--:--",
+ # the format string occurs also below
+ self._str_nodecolor(t_obj.dc, '%-13s' % t_obj.shortname())
+ ]
+ l += get_cib_attributes(self.pe_report_path(t_obj), "cib", \
+ ("update-client", "update-user", "update-origin"), \
+ ("no-client", "no-user", "no-origin"))
+ return '%s - %s %-13s %-10s %-10s %s' % tuple(l)
+ #% (l2[0], l2[1], l2[2])
+ def pelist(self, a=None, long=False):
if not self.prepare_source():
return []
if isinstance(a,(tuple,list)):
@@ -1149,8 +1219,11 @@
a.append(a[0])
elif a is not None:
a = [a,a]
- return [self.pe_report_path(x) for x in self.peinputs_l \
- if pe_file_in_range(x.pe_file, a)]
+ l = [ long and self.pe_detail_format(x) or self.pe_report_path(x)
+ for x in self.peinputs_l if pe_file_in_range(x.pe_file, a) ]
+ if long:
+ l = [self.pe_details_header, self.pe_details_separator] + l
+ return l
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)]
@@ -1236,7 +1309,16 @@
common_err("%s: bad value '%s' for '%s' in "
"session state file %s" % (msg, v, n, fname))
rc = False
+ if rc:
+ self.set_change_origin(CH_SRC)
return rc
+ def set_change_origin(self, org):
+ '''Set origin only to a smaller value (if current > 0).
+ This prevents lesser change_origin overwriting a greater
+ one.
+ '''
+ if self.change_origin == 0 or org < self.change_origin:
+ self.change_origin = org
def manage_session(self, subcmd, name):
dir = self.get_session_dir(name)
if subcmd == "save" and os.path.exists(dir):
@@ -1263,6 +1345,9 @@
elif subcmd == "list":
ext_cmd("ls %s" % self.get_session_dir(None))
elif subcmd == "pack":
+ if self.source != "live":
+ common_err("only live sessions can be packed")
+ return False
return mkarchive(dir)
return True
log_section = 'log'
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-12-11 18:29:34.000000000 +0100
+++ new/crmsh/modules/ui.py.in 2012-12-19 13:36:50.000000000 +0100
@@ -252,27 +252,9 @@
if not infile:
return False
if not name:
- name = os.path.basename(infile)
- # read input
- try:
- f = open(infile)
- except IOError,msg:
- common_err("open: %s"%msg)
- return
- s = ''.join(f)
- f.close()
- # decompresed and rename shadow if it ends with .bz2
- if infile.endswith(".bz2"):
- name = name.replace(".bz2","")
- s = bz2.decompress(s)
- # copy input to the shadow
- try:
- f = open(shadowfile(name), "w")
- except IOError,msg:
- common_err("open: %s"%msg)
- return
- f.write(s)
- f.close()
+ name = os.path.basename(infile).replace(".bz2","")
+ if not pe2shadow(pe_file, name):
+ return False
# use the shadow and load the status from there
return self.use("use",name,"withstatus")
def delete(self,cmd,name):
@@ -1892,14 +1874,11 @@
if a and len(a) == 2 and not check_range(a):
common_err("%s: invalid peinputs range" % a)
return False
- l += crm_report.pelist(a)
+ l += crm_report.pelist(a, long=long)
else:
- l = crm_report.pelist()
+ l = crm_report.pelist(long=long)
if not l: return False
- if long:
- s = get_stdout("for f in %s; do ls -l $f; done" % ' '.join(l))
- else:
- s = '\n'.join(l)
+ s = '\n'.join(l)
page_string(s)
def _get_pe_byname(self, s):
l = crm_report.find_pe_files(s)
@@ -1931,10 +1910,11 @@
def transition(self,cmd,*args):
"""usage: transition [<number>|<index>|<file>] [nograph] [v...] [scores] [actions] [utilization]
transition showdot [<number>|<index>|<file>]
- transition log [<number>|<index>|<file>]"""
+ transition log [<number>|<index>|<file>]
+ transition save [<number>|<index>|<file> [name]]"""
argl = list(args)
subcmd = "show"
- if argl and argl[0] in ("showdot", "log"):
+ if argl and argl[0] in ("showdot", "log", "save"):
if argl[0] == "showdot" and not user_prefs.dotty:
common_err("install graphviz to draw transition graphs")
return False
@@ -1969,6 +1949,12 @@
common_err("dot file not found in the report")
return False
show_dot_graph(f)
+ return True
+ elif subcmd == "save":
+ try: name = argl[0]
+ except: name = os.path.basename(f).replace(".bz2","")
+ common_info("transition %s saved to shadow %s" % (f,name))
+ return pe2shadow(f, name)
else:
full_log = True
if rc:
@@ -1981,7 +1967,7 @@
return True
# verify arguments
if subcmd not in ("save", "load", "pack", "delete", "list", "update"):
- common_err("unknown history session subcmd: %s")
+ common_err("unknown history session subcmd: %s" % subcmd)
return False
if name:
if subcmd not in ("save", "load", "pack", "delete"):
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-12-11 18:29:34.000000000 +0100
+++ new/crmsh/modules/utils.py 2012-12-19 13:36:50.000000000 +0100
@@ -23,6 +23,7 @@
import glob
import time
import shutil
+import bz2
from userprefs import Options, UserPrefs
from vars import Vars
@@ -743,11 +744,39 @@
f.close()
return ver
+def get_cib_attributes(cib_f, tag, attr_l, dflt_l):
+ """A poor man's get attribute procedure.
+ We don't want heavy parsing, this needs to be relatively
+ fast.
+ """
+ open_t = "<%s " % tag
+ val_patt_l = [ re.compile('%s="([^"]+)"' % x) for x in attr_l ]
+ val_l = []
+ try: f = open(cib_f, "r")
+ except IOError, msg:
+ common_err(msg)
+ return ver
+ if os.path.splitext(cib_f)[-1] == '.bz2':
+ cib_s = bz2.decompress(''.join(f))
+ else:
+ cib_s = ''.join(f)
+ for s in cib_s.split('\n'):
+ if s.startswith(open_t):
+ i = 0
+ for patt in val_patt_l:
+ r = patt.search(s)
+ val_l.append(r and r.group(1) or dflt_l[i])
+ i += 1
+ break
+ f.close()
+ return val_l
+
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))
+ common_debug("found pacemaker version: %s in cib: %s" % \
+ (vars.pcmk_version, cib_f))
else:
vars.pcmk_version = get_pcmk_version("1.1.1")
from distutils.version import LooseVersion
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/modules/xmlutil.py new/crmsh/modules/xmlutil.py
--- old/crmsh/modules/xmlutil.py 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/modules/xmlutil.py 2012-12-19 13:36:50.000000000 +0100
@@ -18,6 +18,7 @@
import os
import subprocess
import xml.dom.minidom
+import bz2
from schema import Schema, rng_attr_values, rng_attr_values_l
from userprefs import Options, UserPrefs
@@ -186,6 +187,27 @@
return "%s/shadow.%s" % (cib_shadow_dir(), name)
def shadow2doc(name):
return file2doc(shadowfile(name))
+def pe2shadow(pe_file, name):
+ '''Copy a PE file (or any CIB file) to a shadow.'''
+ try:
+ f = open(pe_file)
+ except IOError,msg:
+ common_err("open: %s"%msg)
+ return False
+ s = ''.join(f)
+ f.close()
+ # decompresed if it ends with .bz2
+ if pe_file.endswith(".bz2"):
+ s = bz2.decompress(s)
+ # copy input to the shadow
+ try:
+ f = open(shadowfile(name), "w")
+ except IOError,msg:
+ common_err("open: %s"%msg)
+ return False
+ f.write(s)
+ f.close()
+ return True
def is_xs_boolean_true(bool):
return bool.lower() in ("true","1")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/Makefile.am new/crmsh/test/Makefile.am
--- old/crmsh/test/Makefile.am 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/test/Makefile.am 2012-12-19 13:36:50.000000000 +0100
@@ -22,6 +22,7 @@
testdir = $(datadir)/$(PACKAGE)/tests
test_SCRIPTS = regression.sh evaltest.sh
-test_DATA = README.regression defaults descriptions crm-interface empty.xml
+test_DATA = README.regression defaults descriptions \
+ crm-interface empty.xml history-test.tar.bz2
# shouldn't need this, but we do for some versions of autofoo tools
EXTRA_DIST = $(test_SCRIPTS) $(test_DATA)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/README.regression new/crmsh/test/README.regression
--- old/crmsh/test/README.regression 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/test/README.regression 2012-12-19 13:36:50.000000000 +0100
@@ -123,7 +123,7 @@
%repeat 10
configure primitive p-%i ocf:pacemaker:Dummy
-Filters and except files
+Filters and other auxiliary files
Some output is necessarily very volatile, such as time stamps.
It is possible to specify a filter for each testcase to get rid
@@ -137,3 +137,18 @@
egrep(1). That way one can filter out lines which are not
interesting. Again, the one applied to all is
testcases/common.excl.
+
+A test may need an arbitrary script executed before or after the
+test itself in order to ascertain some state. The two scripts
+have extensions .pre and .post respectively. Their output is sent
+to /dev/null and the exit status ignored.
+
+Finally, the daemon log files may be filtered using log_filter.
+
+The full collection of auxiliary files follows:
+
+ <TEST>.filter
+ <TEST>.excl
+ <TEST>.log_filter
+ <TEST>.pre
+ <TEST>.post
Files old/crmsh/test/history-test.tar.bz2 and new/crmsh/test/history-test.tar.bz2 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh/test/regression.sh new/crmsh/test/regression.sh
--- old/crmsh/test/regression.sh 2012-12-11 18:29:34.000000000 +0100
+++ new/crmsh/test/regression.sh 2012-12-19 13:36:50.000000000 +0100
@@ -102,6 +102,8 @@
setenvironment() {
filterf=$TESTDIR/$testcase.filter
+ pref=$TESTDIR/$testcase.pre
+ postf=$TESTDIR/$testcase.post
exclf=$TESTDIR/$testcase.excl
log_filter=$TESTDIR/$testcase.log_filter
expf=$TESTDIR/$testcase.exp
@@ -129,6 +131,7 @@
runtestcase() {
setenvironment
+ [ -x "$pref" ] && $pref >/dev/null 2>&1
echo -n "$testcase" >&3
logmsg "BEGIN testcase $testcase"
(
@@ -141,6 +144,7 @@
echo " saving to expect file" >&3
cat > $expf
else
+ [ -x "$postf" ] && $postf >/dev/null 2>&1
echo -n " checking..." >&3
if head -2 $expf | grep -qs '^