Author: eallen
Date: 2008-09-19 10:17:07 -0400 (Fri, 19 Sep 2008)
New Revision: 2502
Modified:
mgmt/trunk/cumin/python/cumin/job.py
Log:
Prepare for job.Fetch
Handle case where job ad attributes contain double quotes within the value.
Modified: mgmt/trunk/cumin/python/cumin/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/job.py 2008-09-19 14:12:00 UTC (rev 2501)
+++ mgmt/trunk/cumin/python/cumin/job.py 2008-09-19 14:17:07 UTC (rev 2502)
@@ -380,7 +380,7 @@
return items
- def gen_items(self, session, job):
+ def get_raw_ads(self, session, job):
self.job_ads = dict()
self.got_data = False
@@ -394,20 +394,25 @@
model = self.app.model
job.GetAd(model.data, completion, self.job_ads)
- cls = self.app.model.get_class_by_object(job)
# wait for up to 20 seconds for completion to be called
succeeded = wait(predicate, timeout=20)
if not succeeded:
self.job_ads = {"": ""}
+
+ return self.job_ads
+
+ def gen_items(self, session, job):
+ job_ads = self.get_raw_ads(session, job)
+
+ cls = self.app.model.get_class_by_object(job)
# list of dictionaries
# each disctionary has:
# name:, value:, type: [, error:] [, property:] [,path:]
- return [self.gen_item(x, self.job_ads[x], cls) for x in self.job_ads]
-#TODO: handle case where completion status isn't OK
-
+ return [self.gen_item(x, job_ads[x], cls) for x in job_ads]
+#
def gen_item(self, name, value, cls, path=None, dtype=None, error=None, orig=None):
- """ Generate a dict with name, value, type, error, path, property
+ """ Generate a dict with name, value, type, error, path, property,
orig
This is called with raw GetAd data and with processed data from
a form submit. With raw data, only the name and value will be present.
@@ -441,15 +446,20 @@
def get_type(self, value):
dvalue = value
- if isinstance(value, int):
- dtype = "number"
- else:
- dquote = value.split("\"")
- if len(dquote) == 3 and (not dquote[0] and not dquote[2]):
- dtype = "string"
- dvalue = dquote[1]
- else:
- dtype = "expression"
+ dtype = "string"
+ try:
+ if isinstance(value, int) or isinstance(value, float) or isinstance(value,
long):
+ dtype = "number"
+ elif isinstance(value, basestring):
+ if value[:1] == "\"" and value[-1:] ==
"\"":
+ dtype = "string"
+ dvalue = value[1:-1]
+ else:
+ dtype = "expression"
+ elif value is None:
+ dvalue = ""
+ except:
+ pass
return dtype, dvalue
class JobPropertyRenderer(TemplateRenderer):
@@ -467,7 +477,16 @@
property = item["property"]
if property.renderer:
value = property.renderer(session, value)
- return escape_entity(str(value))
+ ret = escape_entity(str(value))
+ return self.insert_breaks(ret)
+
+ def insert_breaks(self, value):
+ subwords = list()
+ while len(value) > 40:
+ subwords.append(value[:40])
+ value = value[40:]
+ subwords.append(value)
+ return "​".join(subwords)
def render_inline_help(self, session, item):
if "property" in item:
@@ -485,7 +504,7 @@
return self.frame.get_args(session)
def render_title(self, session, job):
- return "Properties"
+ return "Attributes"
def do_get_items(self, session, args):
job = args[0]
@@ -610,20 +629,105 @@
self.out_time = Attribute(app, "out_time")
self.add_attribute(self.out_time)
+
+ self.ads = JobAdsSet(app, "ads")
+ self.add_child(self.ads)
- def render_title(self, session):
+ self.out_file = Parameter(app, "out")
+ self.add_parameter(self.out_file)
+ self.add_form_parameter(self.out_file)
+
+ self.err_file = Parameter(app, "err")
+ self.add_parameter(self.err_file)
+ self.add_form_parameter(self.err_file)
+
+ self.user_file = Parameter(app, "user")
+ self.add_parameter(self.user_file)
+ self.add_form_parameter(self.user_file)
+
+ def get_args(self, session):
+ return self.frame.get_args(session)
+
+ def render_title(self, session, *args):
return "Output"
- def render_out_time(self, session):
- return "13:14:00 Sept 16 2008"
+ def render(self, session, *args):
+ out_file = self.out_file.get(session)
+ err_file = self.err_file.get(session)
+ user_file = self.user_file.get(session)
+ if not out_file:
+ job = self.frame.get_args(session)[0]
+ items = self.ads.get_raw_ads(session, job)
+ out_file = err_file = user_file = None
+ if "Out" in items:
+ out_file = items["Out"]
+ if "Err" in items:
+ err_file = items["Err"]
+ if "UserLog" in items:
+ user_file = items["UserLog"]
- def render_tail_js(self, session):
+ # strip any double quotes surrounding file names
+ dtype, out_file = self.ads.get_type(out_file)
+ dtype, err_file = self.ads.get_type(err_file)
+ dtype, user_file = self.ads.get_type(user_file)
+
+ # remember the file names so we don't need to reget them
+ self.out_file.set(session, out_file)
+ self.err_file.set(session, err_file)
+ self.user_file.set(session, user_file)
+
+ # set title for radiotab so mouseover will display file name
+ self.which_file.set_file_name(session, "o", out_file)
+ self.which_file.set_file_name(session,"e", err_file)
+ self.which_file.set_file_name(session,"u", user_file)
+
+ if self.which_file.is_bad(out_file):
+ self.which_file.disable(session, "o")
+ if self.which_file.is_bad(err_file):
+ self.which_file.disable(session, "e")
+ if self.which_file.is_bad(user_file):
+ self.which_file.disable(session, "u")
+
+ return super(JobOutput, self).render(session, *args)
+
+ def render_out_time(self, session, *args):
+ now = datetime.now()
+ return fmt_datetime(now, sec=True)
+
+ def render_tail_js(self, session, *args):
is_tail = self.first_last.get(session) == "t"
return is_tail and "<script language=\"javascript\"
type=\"text/javascript\">addEvent(window, \"load\",
outputEnd);</script>" or ""
def render_the_output(self, session, *args):
+ self.job_output = None
+ self.got_data = False
- raw = """fcrawler.looksmart.com - - [26/Apr/2000:00:00:12 -0400]
"GET /contacts.html HTTP/1.0" 200 4595 "-"
"FAST-WebCrawler/2.1-pre2 (ashen(a)looksmart.net)"
+ def completion(status, job_output):
+ self.job_output = job_output["JobOutput"]
+ self.got_data = True
+
+ def predicate():
+ return self.got_data
+
+ first_last = self.first_last.get(session)
+ start = first_last == "t" and -1024 or 0
+ end = first_last == "t" and 0 or 1024
+ file = self.which_file.get_current_file_name(session)
+ if file:
+ try:
+ model = self.app.model
+ job = args[0]
+ job.Fetch(model.data, completion, file, start, end)
+ # wait for up to 20 seconds for completion to be called
+ wait(predicate, timeout=20)
+ except:
+ #self.job_output = "Unable to get file at %s" % file
+ self.job_output = self.get_fake_output()
+
+ return self.job_output and escape_entity(self.job_output)
+
+ def get_fake_output(self):
+ return """fcrawler.looksmart.com - - [26/Apr/2000:00:00:12 -0400]
"GET /contacts.html HTTP/1.0" 200 4595 "-"
"FAST-WebCrawler/2.1-pre2 (ashen(a)looksmart.net)"
fcrawler.looksmart.com - - [26/Apr/2000:00:17:19 -0400] "GET /news/news.html
HTTP/1.0" 200 16716 "-" "FAST-WebCrawler/2.1-pre2
(ashen(a)looksmart.net)"
ppp931.on.bellglobal.com - - [26/Apr/2000:00:16:12 -0400] "GET
/download/windows/asctab31.zip HTTP/1.0" 200 1540096
"http://www.htmlgoodies.com/downloads/freeware/webdevelopment/15.html"
"Mozilla/4.7 [en]C-SYMPA (Win95; U)"
@@ -649,12 +753,8 @@
123.123.123.123 - - [26/Apr/2000:00:23:51 -0400] "GET /pics/a2hlogo.jpg
HTTP/1.0" 200 4282 "http://www.jafsoft.com/asctortf/" "Mozilla/4.05
(Macintosh; I; PPC)"
123.123.123.123 - - [26/Apr/2000:00:23:51 -0400] "GET
/cgi-bin/newcount?jafsof3&width=4&font=digital&noshow HTTP/1.0" 200 36
"http://www.jafsoft.com/asctortf/" "Mozilla/4.05 (Macintosh; I; PPC)"
192.168.2.20 - - [28/Jul/2006:10:27:10 -0300] "GET /cgi-bin/try/ HTTP/1.0" 200
3395"""
- return escape_entity(raw)
class FetchButton(FormButton):
- def process_submit(self, session):
- pass
-
def render_content(self, session):
return "Refresh"
@@ -664,14 +764,81 @@
self.add_state("o", "Output")
self.add_state("e", "Error")
- self.add_state("l", "UserLog")
+ self.add_state("u", "UserLog")
+ self.disabled = self.DisabledList(app, "disabled")
+ self.add_attribute(self.disabled)
+
+ self.link_titles = self.Titles(app, "link_titles")
+ self.add_attribute(self.link_titles)
+
+ class DisabledList(Attribute):
+ def get_default(self, session):
+ return list()
+
+ class Titles(Attribute):
+ def get_default(self, session):
+ return dict()
+
+ def disable(self, session, state):
+ disabled = self.disabled.get(session)
+ disabled.append(state)
+ self.disabled.set(session, disabled)
+ if state == self.get(session):
+ self.select_first_enabled(session)
+
+ def set_file_name(self, session, state, link_title):
+ link_titles = self.link_titles.get(session)
+ link_titles[state] = link_title
+ self.link_titles.set(session, link_titles)
+
+ def get_file_name(self, session, state):
+ link_titles = self.link_titles.get(session)
+ return state in link_titles and link_titles[state] or ""
+
+ def get_current_file_name(self, session):
+ state = self.get(session)
+ return self.get_file_name(session, state)
+
+ def select_first_enabled(self, session):
+ states = self.get_items(session)
+ disabled = self.disabled.get(session)
+ for state in states:
+ if not state in disabled:
+ self.set(session, state)
+ break
+
+ def render_item_link(self, session, state, id=""):
+ branch = session.branch()
+ self.set(branch, state)
+
+ title = self.get_title(state)
+ link_titles = self.link_titles.get(session)
+ link_title = state in link_titles and link_titles[state] or ""
+ disabled = self.disabled.get(session)
+ if state in disabled:
+ class_ = "disabled"
+ href = "javascript:void(0)"
+ else:
+ class_ = self.get(session) == state and "selected"
+ href = branch.marshal()
+ return fmt_link(href, title, class_, id=id, link_title=link_title)
+
+ def is_bad(self, file):
+ bad = False
+ if not file:
+ bad = True
+ elif "/dev/null" in file.lower():
+ bad = True
+ return bad
+
+
class FLSwitch(StateSwitch):
def __init__(self, app, name):
super(JobOutput.FLSwitch, self).__init__(app, name)
- self.add_state("t", "Tail")
- self.add_state("h", "Head")
+ self.add_state("t", "Tail", "Display end of
file")
+ self.add_state("h", "Head", "Display beginning of
file")
class JobStatus(CuminStatus):
def render_color(self, session, job):