0440703030
- PE: Demote from Master does not clear previous errors - crmd: Prevent secondary DC fencing resulting from CIB updates that are lost due to elections - crmd: Log duplicate DC detection as a WARNING not ERROR - crmd: Bug lf#2632 - Correctly handle nodes that return faster than stonith - Core: Treat GNUTLS_E_UNEXPECTED_PACKET_LENGTH as normal termination of a TLS session - cib: Call gnutls_bye() and shutdown() when disconnecting from remote TLS connections - cib: Remove disconnected remote connections from mainloop - cib: Attempt a graceful sign-off for remote TLS connections - Core: Ensure there is sufficient space for EOS when building short-form option strings (prevents segfault) - Core: Fix variable expansion in pkg-config files - PE: Resolve memory leak reported by valgrind - PE: Fix memory leak for re-allocated resources reported by valgrind - PE: Improve the merging with template's operations - crmd: Allow nodes to fence themselves if they're the last one standing (lf#2584) - stonith: Add an API call for listing installed agents - stonith: Allow the fencing history to be queried - stonith: Ensure completed operations are recorded as such in the history - stonith: Support --quiet to display just the seconds since epoch at which a node was last shot - stonith: Serialize actions for a given device - stonith: Add missing entries to stonith_error2string() (missing OBS-URL: https://build.opensuse.org/package/show/network:ha-clustering:Factory/pacemaker?expand=0&rev=18
559 lines
21 KiB
Diff
559 lines
21 KiB
Diff
# HG changeset patch
|
|
# User Dejan Muhamedagic <dejan@hello-penguin.com>
|
|
# Date 1312993121 -7200
|
|
# Node ID b3a014c0f85b2bbe1e6a2360c44fbbfc7ac27b73
|
|
# Parent a09974a06cdf6a3d73c3cdfa6e4d89d41e2ca9f0
|
|
Medium: Shell: improve peinputs and transition interface (bnc#710655,711060)
|
|
|
|
- allow specifying PE files as relative paths in order to
|
|
disambiguate between PE inputs with the same number
|
|
- remove peinputs "get" and "list" subcommands, just use 'v' for the
|
|
long listing
|
|
- remove transition "show" subcommand, if there is no subcommand
|
|
it is assumed that the user wants to do "show"
|
|
- detect (and ignore) empty transitions
|
|
- update completion tables
|
|
|
|
diff --git a/doc/crm.8.txt b/doc/crm.8.txt
|
|
--- a/doc/crm.8.txt
|
|
+++ b/doc/crm.8.txt
|
|
@@ -2560,55 +2560,62 @@ Example:
|
|
|
|
Every event in the cluster results in generating one or more
|
|
Policy Engine (PE) files. These files describe future motions of
|
|
-resources. The files are listed along with the node where they
|
|
-were created (the DC at the time). The `get` subcommand will copy
|
|
-all PE input files to the current working directory (and use ssh
|
|
-if necessary).
|
|
+resources. The files are listed as full paths in the current
|
|
+report directory. Add `v` to also see the creation time stamps.
|
|
|
|
Usage:
|
|
...............
|
|
- peinputs list [{<range>|<number>} ...]
|
|
- peinputs get [{<range>|<number>} ...]
|
|
+ peinputs [{<range>|<number>} ...] [v]
|
|
|
|
range :: <n1>:<n2>
|
|
...............
|
|
Example:
|
|
...............
|
|
- peinputs get 440:444 446
|
|
+ peinputs
|
|
+ peinputs 440:444 446
|
|
+ peinputs v
|
|
...............
|
|
|
|
[[cmdhelp_history_transition,show transition]]
|
|
==== `transition`
|
|
|
|
-The `show` subcommand will print actions planned by the PE and
|
|
-run graphviz (`dotty`) to display a graphical representation. Of
|
|
-course, for the latter an X11 session is required. This command
|
|
-invokes `ptest(8)` in background.
|
|
+This command will print actions planned by the PE and run
|
|
+graphviz (`dotty`) to display a graphical representation of the
|
|
+transition. Of course, for the latter an X11 session is required.
|
|
+This command invokes `ptest(8)` in background.
|
|
|
|
The `showdot` subcommand runs graphviz (`dotty`) to display a
|
|
graphical representation of the `.dot` file which has been
|
|
included in the report. Essentially, it shows the calculation
|
|
produced by `pengine` which is installed on the node where the
|
|
-report was produced.
|
|
+report was produced. In optimal case this output should not
|
|
+differ from the one produced by the locally installed `pengine`.
|
|
|
|
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.
|
|
|
|
+If there are warning and error PE input files or different nodes
|
|
+were the DC in the observed timeframe, it may happen that PE
|
|
+input file numbers collide. In that case provide some unique part
|
|
+of the path to the file.
|
|
+
|
|
After the `ptest` output, logs about events that happened during
|
|
the transition are printed.
|
|
|
|
Usage:
|
|
...............
|
|
- transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
- transition showdot [<number>]
|
|
+ transition [<number>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
+ transition showdot [<number>|<file>]
|
|
...............
|
|
Examples:
|
|
...............
|
|
- transition show
|
|
- transition show 444
|
|
- transition show -1
|
|
+ transition
|
|
+ transition 444
|
|
+ transition -1
|
|
+ transition pe-error-3.bz2
|
|
+ transition node-a/pengine/pe-input-2.bz2
|
|
transition showdot 444
|
|
...............
|
|
|
|
diff --git a/shell/modules/completion.py b/shell/modules/completion.py
|
|
--- a/shell/modules/completion.py
|
|
+++ b/shell/modules/completion.py
|
|
@@ -165,14 +165,14 @@ def report_node_list(idx,delimiter = Fal
|
|
if delimiter:
|
|
return ' '
|
|
return crm_report.node_list()
|
|
-def report_pe_cmd_list(idx,delimiter = False):
|
|
+def report_pe_list_transition(idx,delimiter = False):
|
|
if delimiter:
|
|
return ' '
|
|
- return ["list","get","show","showdot"]
|
|
-def report_pe_list(idx,delimiter = False):
|
|
+ return crm_report.peinputs_list() + ["showdot"]
|
|
+def report_pe_list_peinputs(idx,delimiter = False):
|
|
if delimiter:
|
|
return ' '
|
|
- return crm_report.peinputs_list()
|
|
+ return crm_report.peinputs_list() + ["v"]
|
|
|
|
#
|
|
# completion for primitives including help for parameters
|
|
@@ -484,7 +484,8 @@ completer_lists = {
|
|
"resource" : (report_rsc_list,loop),
|
|
"node" : (report_node_list,loop),
|
|
"log" : (report_node_list,loop),
|
|
- "peinputs" : (report_pe_cmd_list,report_pe_list,loop),
|
|
+ "peinputs" : (report_pe_list_peinputs,loop),
|
|
+ "transition" : (report_pe_list_transition,),
|
|
},
|
|
}
|
|
def get_completer_list(level,cmd):
|
|
diff --git a/shell/modules/crm_pssh.py b/shell/modules/crm_pssh.py
|
|
--- a/shell/modules/crm_pssh.py
|
|
+++ b/shell/modules/crm_pssh.py
|
|
@@ -156,6 +156,9 @@ def next_peinputs(node_pe_l, outdir, err
|
|
myopts = ["-q", "-o", outdir, "-e", errdir]
|
|
opts, args = parse_args(myopts)
|
|
l.append([node, cmdline])
|
|
+ if not l:
|
|
+ # is this a failure?
|
|
+ return True
|
|
return do_pssh(l, opts)
|
|
|
|
# vim:ts=4:sw=4:et:
|
|
diff --git a/shell/modules/log_patterns.py b/shell/modules/log_patterns.py
|
|
--- a/shell/modules/log_patterns.py
|
|
+++ b/shell/modules/log_patterns.py
|
|
@@ -62,8 +62,3 @@ log_patterns = {
|
|
),
|
|
),
|
|
}
|
|
-
|
|
-transition_patt = (
|
|
- "crmd: .* Processing graph.*derived from .*/pe-[^-]+-(%%)[.]bz2", # transition start
|
|
- "crmd: .* Transition.*Source=.*/pe-[^-]+-(%%)[.]bz2.: (Stopped|Complete|Terminated)", # and stop
|
|
-)
|
|
diff --git a/shell/modules/report.py b/shell/modules/report.py
|
|
--- a/shell/modules/report.py
|
|
+++ b/shell/modules/report.py
|
|
@@ -31,7 +31,7 @@ from term import TerminalController
|
|
from xmlutil import *
|
|
from utils import *
|
|
from msg import *
|
|
-from log_patterns import log_patterns, transition_patt
|
|
+from log_patterns import log_patterns
|
|
_NO_PSSH = False
|
|
try:
|
|
from crm_pssh import next_loglines, next_peinputs
|
|
@@ -297,8 +297,8 @@ def human_date(dt):
|
|
def is_log(p):
|
|
return os.path.isfile(p) and os.path.getsize(p) > 0
|
|
|
|
-def pe_file_in_range(pe_f, a, ext):
|
|
- r = re.search("pe-[^-]+-([0-9]+)[.]%s$" % ext, pe_f)
|
|
+def pe_file_in_range(pe_f, a):
|
|
+ r = re.search("pe-[^-]+-([0-9]+)[.]bz2$", pe_f)
|
|
if not r:
|
|
return None
|
|
if not a or (a[0] <= int(r.group(1)) <= a[1]):
|
|
@@ -325,6 +325,17 @@ def update_loginfo(rptlog, logfile, oldp
|
|
except IOError, msg:
|
|
common_err("couldn't the update %s.info: %s" % (rptlog, msg))
|
|
|
|
+# 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
|
|
+ "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: .* unpack_graph: Unpacked transition (%%): ([0-9]+) actions", # number of actions
|
|
+)
|
|
+
|
|
class Report(Singleton):
|
|
'''
|
|
A hb_report class.
|
|
@@ -346,6 +357,7 @@ class Report(Singleton):
|
|
self.desc = None
|
|
self.log_l = []
|
|
self.central_log = None
|
|
+ self.peinputs_l = []
|
|
self.cibgrp_d = {}
|
|
self.cibrsc_l = []
|
|
self.cibnode_l = []
|
|
@@ -363,7 +375,7 @@ class Report(Singleton):
|
|
return self.cibnode_l
|
|
def peinputs_list(self):
|
|
return [re.search("pe-[^-]+-([0-9]+)[.]bz2$", x).group(1)
|
|
- for x in self._file_list("bz2")]
|
|
+ for x in self.peinputs_l]
|
|
def unpack_report(self, tarball):
|
|
'''
|
|
Unpack hb_report tarball.
|
|
@@ -495,28 +507,26 @@ class Report(Singleton):
|
|
continue
|
|
u_dir = os.path.join(self.loc, node)
|
|
rc = ext_cmd_nosudo("tar -C %s -x < %s" % (u_dir,fl[0]))
|
|
- def find_new_peinputs(self, a):
|
|
+ def find_new_peinputs(self, node_l):
|
|
'''
|
|
- Get a list of pe inputs appearing in logs.
|
|
+ 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 = []
|
|
- trans_re_l = [x.replace("%%","") for x in transition_patt]
|
|
- for node,rptlog,logfile,nextpos in a:
|
|
- node_l = []
|
|
+ for node in node_l:
|
|
fl = glob.glob("%s/*%s*" % (self.outdir,node))
|
|
if not fl:
|
|
continue
|
|
- for s in file2list(fl[0]):
|
|
- r = re.search(trans_re_l[0], s)
|
|
- if not r:
|
|
- continue
|
|
- node_l.append(r.group(1))
|
|
- if node_l:
|
|
- common_debug("found new PE inputs %s at %s" %
|
|
- ([os.path.basename(x) for x in node_l], node))
|
|
- l.append([node,node_l])
|
|
+ try:
|
|
+ f = open(fl[0])
|
|
+ except IOError,msg:
|
|
+ common_err("open %s: %s"%(fl[0],msg))
|
|
+ continue
|
|
+ pe_l = self.get_transitions([x for x in f], keep_pe_path = True)
|
|
+ if pe_l:
|
|
+ l.append([node,pe_l])
|
|
return l
|
|
def update_live(self):
|
|
'''
|
|
@@ -544,7 +554,7 @@ class Report(Singleton):
|
|
rmdir_r(self.errdir)
|
|
rc1 = next_loglines(a, self.outdir, self.errdir)
|
|
self.append_newlogs(a)
|
|
- pe_l = self.find_new_peinputs(a)
|
|
+ pe_l = self.find_new_peinputs([x[0] for x in a])
|
|
rmdir_r(self.outdir)
|
|
rmdir_r(self.errdir)
|
|
rc2 = True
|
|
@@ -677,6 +687,55 @@ class Report(Singleton):
|
|
for n in self.cibnode_l:
|
|
self.nodecolor[n] = self.nodecolors[i]
|
|
i = (i+1) % len(self.nodecolors)
|
|
+ def get_transitions(self, msg_l = None, keep_pe_path = False):
|
|
+ '''
|
|
+ Get a list of transitions.
|
|
+ Empty transitions are skipped.
|
|
+ We use the unpack_graph message to see the number of
|
|
+ actions.
|
|
+ Some callers need original PE file path (keep_pe_path),
|
|
+ otherwise we produce the path within the report.
|
|
+ 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.
|
|
+ '''
|
|
+ trans_re_l = [x.replace("%%", "[0-9]+") for x in 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)]
|
|
+ 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 msg_a[7] in ("unpack_graph:","run_graph:"):
|
|
+ continue # we want another message
|
|
+ node = msg_a[3]
|
|
+ pe_file = msg_a[-1]
|
|
+ pe_base = os.path.basename(pe_file)
|
|
+ # check if there were any actions in this transition
|
|
+ r = re.search(trans_re_l[0], msg)
|
|
+ trans_num = r.group(1)
|
|
+ unpack_patt = transition_patt[2].replace("%%", trans_num)
|
|
+ num_actions = 0
|
|
+ for t in msg_l:
|
|
+ try:
|
|
+ num_actions = int(re.search(unpack_patt, t).group(2))
|
|
+ break
|
|
+ except: pass
|
|
+ if num_actions == 0: # empty transition
|
|
+ common_debug("skipping empty transition %s (%s)" % (trans_num, pe_base))
|
|
+ continue
|
|
+ common_debug("found PE input at %s: %s" % (node, pe_file))
|
|
+ if keep_pe_path:
|
|
+ pe_l.append(pe_file)
|
|
+ else:
|
|
+ pe_l.append(os.path.join(self.loc, node, "pengine", pe_base))
|
|
+ return pe_l
|
|
def report_setup(self):
|
|
if not self.loc:
|
|
return
|
|
@@ -687,6 +746,11 @@ class Report(Singleton):
|
|
self.set_node_colors()
|
|
self.logobj = LogSyslog(self.central_log, self.log_l, \
|
|
self.from_dt, self.to_dt)
|
|
+ self.peinputs_l = self.get_transitions()
|
|
+ for pe_input in self.peinputs_l:
|
|
+ if not os.path.isfile(pe_input):
|
|
+ warn_once("%s in the logs, but not in the report" % pe_input)
|
|
+ self.peinputs_l.remove(pe_input)
|
|
def prepare_source(self):
|
|
'''
|
|
Unpack a hb_report tarball.
|
|
@@ -821,16 +885,16 @@ class Report(Singleton):
|
|
Search for events within the given transition.
|
|
'''
|
|
pe_base = os.path.basename(pe_file)
|
|
- r = re.search("pe-[^-]+-([0-9]+)[.]bz2", pe_base)
|
|
+ r = re.search("pe-[^-]+-([0-9]+)[.]", pe_base)
|
|
pe_num = r.group(1)
|
|
trans_re_l = [x.replace("%%",pe_num) for x in transition_patt]
|
|
trans_start = self.logobj.search_logs(self.log_l, trans_re_l[0])
|
|
trans_end = self.logobj.search_logs(self.log_l, trans_re_l[1])
|
|
if not trans_start:
|
|
- common_warn("transition %s start not found in logs" % pe_base)
|
|
+ common_warn("start of transition %s not found in logs" % pe_base)
|
|
return False
|
|
if not trans_end:
|
|
- common_warn("transition %s end not found in logs" % pe_base)
|
|
+ common_warn("end of transition %s not found in logs (transition not complete yet?)" % pe_base)
|
|
return False
|
|
common_debug("transition start: %s" % trans_start[0])
|
|
common_debug("transition end: %s" % trans_end[0])
|
|
@@ -891,23 +955,23 @@ class Report(Singleton):
|
|
if not l:
|
|
return False
|
|
self.show_logs(log_l = l)
|
|
- def _file_list(self, ext, a = []):
|
|
- '''
|
|
- Return list of PE (or dot) files (abs paths) sorted by
|
|
- mtime.
|
|
- Input is a number or a pair of numbers representing
|
|
- range. Otherwise, all matching files are returned.
|
|
- '''
|
|
+ def pelist(self, a = []):
|
|
if not self.prepare_source():
|
|
return []
|
|
- if not isinstance(a,(tuple,list)) and a is not None:
|
|
+ if isinstance(a,(tuple,list)):
|
|
+ if len(a) == 1:
|
|
+ a.append(a[0])
|
|
+ elif a is not None:
|
|
a = [a,a]
|
|
- return sort_by_mtime([x for x in dirwalk(self.loc) \
|
|
- if pe_file_in_range(x,a,ext)])
|
|
- def pelist(self, a = []):
|
|
- return self._file_list("bz2", a)
|
|
+ return [x for x in self.peinputs_l \
|
|
+ if pe_file_in_range(x, a)]
|
|
def dotlist(self, a = []):
|
|
- return self._file_list("dot", a)
|
|
+ l = [x.replace("bz2","dot") for x in self.pelist(a)]
|
|
+ return [x for x in l if os.path.isfile(x)]
|
|
+ def find_pe_files(self, path):
|
|
+ 'Find a PE or dot file matching part of the path.'
|
|
+ pe_l = path.endswith(".dot") and self.dotlist() or self.pelist()
|
|
+ return [x for x in pe_l if x.endswith(path)]
|
|
def find_file(self, f):
|
|
return file_find_by_name(self.loc, f)
|
|
|
|
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
|
|
--- a/shell/modules/ui.py.in
|
|
+++ b/shell/modules/ui.py.in
|
|
@@ -1686,8 +1686,8 @@ Examine Pacemaker's history: node and re
|
|
self.cmd_table["resource"] = (self.resource,(1,),1,0)
|
|
self.cmd_table["node"] = (self.node,(1,),1,1)
|
|
self.cmd_table["log"] = (self.log,(0,),1,0)
|
|
- self.cmd_table["peinputs"] = (self.peinputs,(1,),1,0)
|
|
- self.cmd_table["transition"] = (self.transition,(1,),1,0)
|
|
+ self.cmd_table["peinputs"] = (self.peinputs,(0,),1,0)
|
|
+ self.cmd_table["transition"] = (self.transition,(0,),1,0)
|
|
self._set_source(options.history)
|
|
def _no_source(self):
|
|
common_error("we have no source set yet! please use the source command")
|
|
@@ -1831,64 +1831,83 @@ Examine Pacemaker's history: node and re
|
|
s = bz2.decompress(''.join(f))
|
|
f.close()
|
|
return run_ptest(s, nograph, scores, utilization, actions, verbosity)
|
|
- def peinputs(self,cmd,subcmd,*args):
|
|
- """usage: peinputs list [{<range>|<number>} ...]
|
|
- peinputs get [{<range>|<number>} ...]"""
|
|
- if subcmd not in ("get","list"):
|
|
- bad_usage(cmd,subcmd)
|
|
- return False
|
|
- if args:
|
|
+ def peinputs(self,cmd,*args):
|
|
+ """usage: peinputs [{<range>|<number>} ...] [v]"""
|
|
+ argl = list(args)
|
|
+ long = "v" in argl
|
|
+ if long:
|
|
+ argl.remove("v")
|
|
+ if argl:
|
|
l = []
|
|
- for s in args:
|
|
+ for s in argl:
|
|
a = convert2ints(s.split(':'))
|
|
- if len(a) == 2 and not check_range(a):
|
|
+ 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)
|
|
else:
|
|
l = crm_report.pelist()
|
|
if not l: return False
|
|
- if subcmd == "list":
|
|
- s = get_stdout("ls -lrt %s" % ' '.join(l))
|
|
- page_string(s)
|
|
+ if long:
|
|
+ s = get_stdout("for f in %s; do ls -l $f; done" % ' '.join(l))
|
|
else:
|
|
- print '\n'.join(l)
|
|
- def transition(self,cmd,subcmd,*args):
|
|
- """usage: transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
|
|
- transition showdot [<number>]"""
|
|
- if subcmd not in ("show", "showdot"):
|
|
- bad_usage(cmd,subcmd)
|
|
- return False
|
|
- try: n = convert2ints(args[0])
|
|
- except: n = None
|
|
- startarg = 1
|
|
- if n is None:
|
|
- idx = -1
|
|
- startarg = 0 # peinput number missing
|
|
- elif n <= 0:
|
|
- idx = n - 1
|
|
- n = [] # to get all peinputs
|
|
- else:
|
|
- idx = 0
|
|
- if subcmd == "showdot":
|
|
+ s = '\n'.join(l)
|
|
+ page_string(s)
|
|
+ def transition(self,cmd,*args):
|
|
+ """usage: transition [<number>|<file>] [nograph] [v...] [scores] [actions] [utilization]
|
|
+ transition showdot [<number>|<file>]"""
|
|
+ argl = list(args)
|
|
+ subcmd = "show"
|
|
+ if argl and argl[0] == "showdot":
|
|
if not user_prefs.dotty:
|
|
common_err("install graphviz to draw transition graphs")
|
|
return False
|
|
- l = crm_report.dotlist(n)
|
|
+ subcmd = "showdot"
|
|
+ argl.remove(subcmd)
|
|
+ f = None
|
|
+ startarg = 1
|
|
+ if argl and re.search('pe-', argl[0]):
|
|
+ l = crm_report.find_pe_files(argl[0])
|
|
+ if len(l) == 0:
|
|
+ common_err("%s: path not found" % argl[0])
|
|
+ return False
|
|
+ elif len(l) > 1:
|
|
+ common_err("%s: path ambiguous" % argl[0])
|
|
+ return False
|
|
+ f = l[0]
|
|
else:
|
|
- l = crm_report.pelist(n)
|
|
- if len(l) < abs(idx):
|
|
- common_err("pe input or dot file not found")
|
|
+ try: n = convert2ints(argl[0])
|
|
+ except: n = None
|
|
+ if n is None:
|
|
+ idx = -1
|
|
+ startarg = 0 # peinput number missing
|
|
+ elif n <= 0:
|
|
+ idx = n - 1
|
|
+ n = [] # to get all peinputs
|
|
+ else:
|
|
+ idx = 0
|
|
+ if subcmd == "showdot":
|
|
+ l = crm_report.dotlist(n)
|
|
+ else:
|
|
+ l = crm_report.pelist(n)
|
|
+ if len(l) < abs(idx):
|
|
+ if subcmd == "show":
|
|
+ common_err("pe input file not found")
|
|
+ else:
|
|
+ common_err("dot file not found")
|
|
+ return False
|
|
+ f = l[idx]
|
|
+ if not f:
|
|
return False
|
|
rc = True
|
|
if subcmd == "show":
|
|
- self.pe_file = l[idx]
|
|
+ self.pe_file = f # self.pe_file needed by self.ptest
|
|
rc = ptestlike(self.ptest,'vv',"%s %s" % \
|
|
- (cmd, subcmd), *args[startarg:])
|
|
- if rc:
|
|
- crm_report.show_transition_log(self.pe_file)
|
|
+ (cmd, subcmd), *argl[startarg:])
|
|
else:
|
|
- show_dot_graph(l[idx])
|
|
+ show_dot_graph(f.replace("bz2","dot"))
|
|
+ if rc:
|
|
+ crm_report.show_transition_log(f)
|
|
return rc
|
|
|
|
class TopLevel(UserInterface):
|
|
diff --git a/shell/modules/utils.py b/shell/modules/utils.py
|
|
--- a/shell/modules/utils.py
|
|
+++ b/shell/modules/utils.py
|
|
@@ -392,7 +392,7 @@ def run_ptest(graph_s, nograph, scores,
|
|
Pipe graph_s thru ptest(8). Show graph using dotty if requested.
|
|
'''
|
|
actions_filter = "grep LogActions: | grep -vw Leave"
|
|
- ptest = "ptest -X"
|
|
+ ptest = "2>&1 ptest -X"
|
|
if verbosity:
|
|
if actions:
|
|
verbosity = 'v' * max(3,len(verbosity))
|
|
@@ -408,7 +408,8 @@ def run_ptest(graph_s, nograph, scores,
|
|
dotfile = None
|
|
# ptest prints to stderr
|
|
if actions:
|
|
- ptest = "%s 2>&1 | %s" % (ptest, actions_filter)
|
|
+ ptest = "%s | %s" % (ptest, actions_filter)
|
|
+ common_debug("invoke: %s" % ptest)
|
|
print get_stdout(ptest, input_s = graph_s)
|
|
#page_string(get_stdout(ptest, input_s = graph_s))
|
|
if dotfile:
|
|
@@ -443,7 +444,7 @@ def check_range(a):
|
|
return False
|
|
if not isinstance(a[0],int) or not isinstance(a[1],int):
|
|
return False
|
|
- return (int(a[0]) < int(a[1]))
|
|
+ return (int(a[0]) <= int(a[1]))
|
|
|
|
def sort_by_mtime(l):
|
|
'Sort a (small) list of files by time mod.'
|