File crm_history_peinputs.patch of Package pacemaker

changeset:   10788:6f9cc20dba0d
user:        Dejan Muhamedagic <dejan@hello-penguin.com>
date:        Mon Jul 18 12:35:57 2011 +0200
summary:     Dev: Shell: spawn transition command from peinputs

diff -r b694b75d2e33 -r 6f9cc20dba0d doc/crm.8.txt
--- a/doc/crm.8.txt	Mon Jul 18 12:35:57 2011 +0200
+++ b/doc/crm.8.txt	Mon Jul 18 12:35:57 2011 +0200
@@ -2565,6 +2565,21 @@ were created (the DC at the time). The `
 all PE input files to the current working directory (and use ssh
 if necessary).
 
+Usage:
+...............
+        peinputs list [{<range>|<number>} ...]
+        peinputs get [{<range>|<number>} ...]
+
+        range :: <n1>:<n2>
+...............
+Example:
+...............
+        peinputs get 440:444 446
+...............
+
+[[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
@@ -2581,22 +2596,20 @@ last one, i.e. the last transition. If t
 then the corresponding transition relative to the last one is
 chosen.
 
+After the `ptest` output, logs about events that happened during
+the transition are printed.
+
 Usage:
 ...............
-        peinputs list [{<range>|<number>} ...]
-        peinputs get [{<range>|<number>} ...]
-        peinputs show [<number>] [nograph] [v...] [scores] [actions] [utilization]
-        peinputs showdot [<number>]
-
-        range :: <n1>:<n2>
+        transition show [<number>] [nograph] [v...] [scores] [actions] [utilization]
+        transition showdot [<number>]
 ...............
-Example:
+Examples:
 ...............
-        peinputs get 440:444 446
-        peinputs show
-        peinputs show 444
-        peinputs show -1
-        peinputs showdot 444
+        transition show
+        transition show 444
+        transition show -1
+        transition showdot 444
 ...............
 
 === `end` (`cd`, `up`)
diff -r b694b75d2e33 -r 6f9cc20dba0d shell/modules/log_patterns.py
--- a/shell/modules/log_patterns.py	Mon Jul 18 12:35:57 2011 +0200
+++ b/shell/modules/log_patterns.py	Mon Jul 18 12:35:57 2011 +0200
@@ -64,6 +64,6 @@ log_patterns = {
 }
 
 transition_patt = (
-	"crmd: .* Processing graph.*derived from (.*bz2)", # transition start
-	"crmd: .* Transition.*Source=(.*bz2): (Stopped|Complete|Terminated)", # and stop
+	"crmd: .* Processing graph.*derived from .*/pe-[^-]+-(%%)[.]bz2", # transition start
+	"crmd: .* Transition.*Source=.*/pe-[^-]+-(%%)[.]bz2.: (Stopped|Complete|Terminated)", # and stop
 )
diff -r b694b75d2e33 -r 6f9cc20dba0d shell/modules/report.py
--- a/shell/modules/report.py	Mon Jul 18 12:35:57 2011 +0200
+++ b/shell/modules/report.py	Mon Jul 18 12:35:57 2011 +0200
@@ -177,8 +177,12 @@ class LogSyslog(object):
         find out start/end file positions. Logs need to be
         already open.
         '''
-        self.from_ts = convert_dt(from_dt)
-        self.to_ts = convert_dt(to_dt)
+        if isinstance(from_dt, datetime.datetime):
+            self.from_ts = convert_dt(from_dt)
+            self.to_ts = convert_dt(to_dt)
+        else:
+            self.from_ts = from_dt
+            self.to_ts = to_dt
         bad_logs = []
         for log in self.f:
             f = self.f[log]
@@ -498,13 +502,14 @@ class Report(Singleton):
         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 = []
             fl = glob.glob("%s/*%s*" % (self.outdir,node))
             if not fl:
                 continue
             for s in file2list(fl[0]):
-                r = re.search(transition_patt[0], s)
+                r = re.search(trans_re_l[0], s)
                 if not r:
                     continue
                 node_l.append(r.group(1))
@@ -680,7 +685,8 @@ class Report(Singleton):
         self.find_central_log()
         self.read_cib()
         self.set_node_colors()
-        self.logobj = None
+        self.logobj = LogSyslog(self.central_log, self.log_l, \
+                self.from_dt, self.to_dt)
     def prepare_source(self):
         '''
         Unpack a hb_report tarball.
@@ -740,6 +746,15 @@ class Report(Singleton):
         try: clr = self.nodecolor[a[3]]
         except: return s
         return termctrl.render("${%s}%s${NORMAL}" % (clr,s))
+    def display_logs(self, l):
+        if not options.batch and sys.stdout.isatty():
+            page_string('\n'.join([ self.disp(x) for x in l ]))
+        else: # raw output
+            try: # in case user quits the next prog in pipe
+                for s in l: print s
+            except IOError, msg:
+                if not ("Broken pipe" in msg):
+                    common_err(msg)
     def show_logs(self, log_l = [], re_l = []):
         '''
         Print log lines, either matched by re_l or all.
@@ -749,18 +764,7 @@ class Report(Singleton):
         if not self.central_log and not log_l:
             self.error("no logs found")
             return
-        if not self.logobj:
-            self.logobj = LogSyslog(self.central_log, log_l, \
-                    self.from_dt, self.to_dt)
-        l = self.logobj.get_matches(re_l, log_l)
-        if not options.batch and sys.stdout.isatty():
-            page_string('\n'.join([ self.disp(x) for x in l ]))
-        else: # raw output
-            try: # in case user quits the next prog in pipe
-                for s in l: print s
-            except IOError, msg:
-                if not ("Broken pipe" in msg):
-                    common_err(msg)
+        self.display_logs(self.logobj.get_matches(re_l, log_l))
     def match_args(self, cib_l, args):
         for a in args:
             a_clone = re.sub(r':.*', '', a)
@@ -812,6 +816,34 @@ class Report(Singleton):
             self.error("no resources or nodes found")
             return False
         self.show_logs(re_l = all_re_l)
+    def show_transition_log(self, pe_file):
+        '''
+        Search for events within the given transition.
+        '''
+        pe_base = os.path.basename(pe_file)
+        r = re.search("pe-[^-]+-([0-9]+)[.]bz2", 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)
+            return False
+        if not trans_end:
+            common_warn("transition %s end not found in logs" % pe_base)
+            return False
+        common_debug("transition start: %s" % trans_start[0])
+        common_debug("transition end: %s" % trans_end[0])
+        start_ts = syslog_ts(trans_start[0])
+        end_ts = syslog_ts(trans_end[0])
+        if not start_ts or not end_ts:
+            self.warn("strange, no timestamps found")
+            return False
+        # limit the log scope temporarily
+        self.logobj.set_log_timeframe(start_ts, end_ts)
+        self.events()
+        self.logobj.set_log_timeframe(self.from_dt, self.to_dt)
+        return True
     def resource(self,*args):
         '''
         Show resource relevant logs.
diff -r b694b75d2e33 -r 6f9cc20dba0d shell/modules/ui.py.in
--- a/shell/modules/ui.py.in	Mon Jul 18 12:35:57 2011 +0200
+++ b/shell/modules/ui.py.in	Mon Jul 18 12:35:57 2011 +0200
@@ -1686,7 +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,(0,),1,0)
+        self.cmd_table["peinputs"] = (self.peinputs,(1,),1,0)
+        self.cmd_table["transition"] = (self.transition,(1,),1,0)
         self._set_source(options.history)
     def _no_source(self):
         common_error("we have no source set yet! please use the source command")
@@ -1832,57 +1833,63 @@ Examine Pacemaker's history: node and re
         return run_ptest(s, nograph, scores, utilization, actions, verbosity)
     def peinputs(self,cmd,subcmd,*args):
         """usage: peinputs list [{<range>|<number>} ...]
-        peinputs get [{<range>|<number>} ...]
-        peinputs show [<number>] [nograph] [v...] [scores] [actions] [utilization]
-        peinputs showdot [<number>]"""
-        if subcmd in ("get","list"):
-            if args:
-                l = []
-                for s in args:
-                    a = convert2ints(s.split(':'))
-                    if 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)
-            else:
-                print '\n'.join(l)
-        elif subcmd in ("show","showdot"):
-            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":
-                if not user_prefs.dotty:
-                    common_err("install graphviz to draw transition graphs")
+        peinputs get [{<range>|<number>} ...]"""
+        if subcmd not in ("get","list"):
+            bad_usage(cmd,subcmd)
+            return False
+        if args:
+            l = []
+            for s in args:
+                a = convert2ints(s.split(':'))
+                if len(a) == 2 and not check_range(a):
+                    common_err("%s: invalid peinputs range" % a)
                     return False
-                l = crm_report.dotlist(n)
-            else:
-                l = crm_report.pelist(n)
-            if len(l) < abs(idx):
-                common_err("pe input or dot file not found")
+                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)
+        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":
+            if not user_prefs.dotty:
+                common_err("install graphviz to draw transition graphs")
                 return False
-            if subcmd == "show":
-                self.pe_file = l[idx]
-                return ptestlike(self.ptest,'vv',"%s %s" % \
-                    (cmd, subcmd), *args[startarg:])
-            else:
-                show_dot_graph(l[idx])
+            l = crm_report.dotlist(n)
         else:
-            bad_usage(cmd,' '.join(subcmd,args))
+            l = crm_report.pelist(n)
+        if len(l) < abs(idx):
+            common_err("pe input or dot file not found")
             return False
+        rc = True
+        if subcmd == "show":
+            self.pe_file = l[idx]
+            rc = ptestlike(self.ptest,'vv',"%s %s" % \
+                (cmd, subcmd), *args[startarg:])
+            if rc:
+                crm_report.show_transition_log(self.pe_file)
+        else:
+            show_dot_graph(l[idx])
+        return rc
 
 class TopLevel(UserInterface):
     '''
openSUSE Build Service is sponsored by