A simple python client script may be used to watch over a suite:
python ecflow_client.py localhost 31415 /compo/main/12
This simple example may be extended to generate a html page.
html client
CSS = "/home/ma/map/http/sms.css"
HEADER = '''<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="600">
<title>Status tree of {node_full_name} in {hostname}-{hostport}</title>
<link rel="stylesheet" type="text/css" href="file:{css}">
</head>
<body>
<table border=2 cellpadding=2> <tr>'''
FOOTER = '''</table>\n</body>\n</html>'''
class ObserverHtml(Observer):
""" simple ecflow watchdog class + html output """
def __init__(self, defs, node, port, path):
super(ObserverHtml, self).__init__(defs, node, port, path)
self.userdepth = 3
self.status_mask = ("queued", "complete", "unknown")
self.maxdepth = 100
self.openkids = True
def run(self):
client = ec.Client(self.node, self.port)
path = self.path
while 1:
client.sync_local() # get changes, synced with local definition
node = client.get_defs().find_abs_node(path)
if 0: assert node is not None
if node is None: node = client.get_defs()
self.html_write(node)
time.sleep(90)
def header(self):
print >>self.fp, HEADER.format(node_full_name=self.path,
hostname= self.node,
css= CSS,
hostport=self.port)
def tail(self, node=None):
print >>self.fp, FOOTER
def countnext(self, anything, depth):
np = anything;
n = 0;
if np is not None and depth > self.maxdepth:
self.maxdepth = depth;
while np is not None:
n += 1
np = np.next()
return n;
def count(self, np=None, depth=1):
n = 0;
if np is None: return
if ("%s" % np.get_state() not in self.status_mask
or depth > self.userdepth):
return
if depth > self.maxdepth: self.maxdepth = depth;
def html_write(self, np, fpp=None):
if fpp is None:
fpp = open("example.html", "w")
self.count(np,0);
self.fp = fpp;
self.header();
self.lineno = 0;
self.table(np,0);
self.tail(np);
fpp.close()
def write_link(self, node, horizontal, base, target):
print >>self.fp, '<base target="{target}">'.format(target=target)
for np in node.nodes:
print >>self.fp,' <td class="{status}">'.format(status="%s" % np.get_state())
print >>self.fp,'<a href="{base}/{name}.html">{name}</a>'.format(
base=base, name=np.name())
if horizontal and np.next():
print >>self.fp," </tr>"
print >>self.fp," <tr>"
print >>self.fp, " </tr>"
def img(self, name):
print >>self.fp, "<img src=\"../gifs/%s.gif\" alt=\"[%s]\">" % (name,name)
def decorations(self, node):
status = node.get_state()
if status == "halted": self.img("halted")
if status == "shutdown": self.img("shutdown")
# rerun
# messages
# late
# clock
def html_links(self, np, fpp=None, title=0, horizontal=0):
base = os.getenv("htmlbase");
target = os.getenv("htmltarget");
if base is not None: base = "od";
if target is not None: target = "level1";
self.fp = fpp;
self.header();
if title: print >>self.fp," <th>{name}</th>".format(name=np.name())
if horizontal: print >>self.fp," </tr>"
if np.nodes: print >>self.fp, " <tr>"
self.write_link(np, horizontal, base, target);
self.tail();
def table(self, node, depth):
n = 0
if node is None: return 0
# if depth > self.userdepth: return 0 # depth
try: print node.get_abs_node_path()
except: pass
if 1:
try: status = "%s" % node.get_state() # node
except:
status = node.value() # attribute
print >>self.fp, "<td>%s:%s" % (node.name(),status),"</td>"
return 1
if status in self.status_mask: return 0
try:
print >>self.fp, "<td class='%s'>" % status, "%s" % node.name(),"</td>"
except:
for suite in node.suites: self.table(suite, depth) # Defs
return 0
# decorations?
if self.openkids:
# n += self.table(node.get_repeat(), depth+1)
for item in node.meters:
n += self.table(item, depth+1)
for item in node.events:
n += self.table(item, depth+1)
for item in node.labels:
n += self.table(item, depth+1)
i = 0
for kid in node.nodes:
if 1: print >>self.fp, "<tr>"
n += self.table(kid, depth+1)
i += 1
if n == 0: print >>self.fp, "</tr>"; n=1
return n
It clearly needs to be refined to provide the expected output.