1 import turbogears as tg
2 from turbogears import controllers, expose, flash, exception_handler, redirect
3 from turbogears import widgets
4 from cherrypy import request, response
6 # from monitorweb import model
8 # log = logging.getLogger("monitorweb.controllers")
11 from monitor.database.info.model import *
12 #from monitor.database.zabbixapi.model import *
13 from monitor_xmlrpc import MonitorXmlrpcServer
15 from monitor import util
16 from monitor import reboot
17 from monitor import bootman
18 from monitor import scanapi
19 from monitor import config
22 from monitor.wrapper.plccache import plcdb_hn2lb as site_hn2lb
24 from monitorweb.templates.links import *
26 class ObjectQueryFields(widgets.WidgetsList):
27 """The WidgetsList defines the fields of the form."""
32 class NodeQueryFields(widgets.WidgetsList):
33 """The WidgetsList defines the fields of the form."""
35 object = widgets.RadioButtonList(label="Query Type", options=[('nodes', 'All Nodes'),
36 ('nodehistory', 'Single Node History'),
37 #('sites', 'All Sites'),
38 #('sitehistory', 'Single Site History'),
40 nodehistory_hostname = widgets.TextField(label="Hostname Node History", attrs={'size':30})
42 hostname = widgets.CheckBox(label="Hostname")
43 firewall = widgets.CheckBox(label="Firewall?")
44 ssh_status = widgets.CheckBox(label="SSH Status")
45 ssh_error = widgets.CheckBox(label="SSH Errors")
46 dns_status = widgets.CheckBox(label="DNS Status")
47 nm_status = widgets.CheckBox(label="NM Status")
48 princeton_comon_dir = widgets.CheckBox(label="CoMon Dir")
49 princeton_comon_running = widgets.CheckBox(label="CoMon Running")
50 princeton_comon_procs = widgets.CheckBox(label="CoMon Processes")
51 external_dns_status = widgets.CheckBox(label="Hostname Resolves?")
52 kernel_version = widgets.CheckBox(label="Kernel")
53 bootcd_version = widgets.CheckBox(label="BootCD")
54 observed_status = widgets.CheckBox(label="Observed Status")
55 port_status = widgets.CheckBox(label="Port Status")
56 rpms = widgets.CheckBox(label="RPM")
57 rpmvalue = widgets.TextField(label="RPM Pattern")
59 class QueryForm(widgets.TableForm):
61 <form xmlns:py="http://purl.org/kid/ns#"
68 <div py:for="field in hidden_fields"
69 py:replace="field.display(value_for(field), **params_for(field))"
71 <table border="0" cellspacing="0" cellpadding="2" py:attrs="table_attrs">
72 <tr py:for="i, field in enumerate(fields)"
73 class="${i%2 and 'odd' or 'even'}"
76 <label class="fieldlabel" for="${field.field_id}" py:content="field.label" />
79 <span py:replace="field.display(value_for(field), **params_for(field))" />
80 <span py:if="error_for(field)" class="fielderror" py:content="error_for(field)" />
81 <span py:if="field.help_text" class="fieldhelp" py:content="field.help_text" />
86 <td py:content="submit.display(submit_text)" />
92 def getNodeQueryForm():
93 return QueryForm(fields=NodeQueryFields(), action="query")
95 # make it easier group objects without invoking the elixir auto-write feature.
99 def query_to_dict(query):
100 """ take a url query string and chop it up """
102 query_fields = query.split('&')
103 for f in query_fields:
104 (k,v) = urllib.splitvalue(f)
109 def format_ports(data, pcumodel=None):
114 supported_ports=reboot.model_to_object(pcumodel).supported_ports
116 # ports of a production node
117 supported_ports=[22,80,806]
119 if data and len(data.keys()) > 0 :
120 for port in supported_ports:
122 state = data[str(port)]
126 if state == "filtered":
129 retval.append( (port, state) )
132 retval = [( "Closed/Filtered", "state" )]
134 if filtered_length == len(supported_ports):
135 retval = [( "All Filtered", "state" )]
139 def format_pcu_shortstatus(pcu):
142 if pcu.reboot_trial_status == str(0):
144 elif pcu.reboot_trial_status == "NetDown" or pcu.reboot_trial_status == "Not_Run":
145 status = pcu.reboot_trial_status
151 def prep_pcu_for_display(pcu):
156 agg.loginbase = PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base']
158 agg.loginbase = "unknown"
160 agg.pcuhist = HistoryPCURecord.query.get(pcu.plc_pcuid)
162 agg.ports = format_ports(pcu.port_status, pcu.plc_pcu_stats['model'])
163 agg.status = format_pcu_shortstatus(pcu)
165 #print pcu.entry_complete
166 agg.entry_complete_str = pcu.entry_complete
167 #pcu.entry_complete_str += "".join([ f[0] for f in pcu.entry_complete.split() ])
168 if pcu.dns_status == "NOHOSTNAME":
169 agg.dns_short_status = 'NoHost'
170 elif pcu.dns_status == "DNS-OK":
171 agg.dns_short_status = 'Ok'
172 elif pcu.dns_status == "DNS-NOENTRY":
173 agg.dns_short_status = 'NoEntry'
174 elif pcu.dns_status == "NO-DNS-OR-IP":
175 agg.dns_short_status = 'NoHostOrIP'
176 elif pcu.dns_status == "DNS-MISMATCH":
177 agg.dns_short_status = 'Mismatch'
180 class ActionListWidget(widgets.Widget):
183 class NodeWidget(widgets.Widget):
186 def prep_nodehist(node):
189 agg.loginbase = "unknown"
191 agg.loginbase = PlcSite.query.get(node.plc_siteid).plc_site_stats['login_base']
193 agg.loginbase = "exception"
198 def prep_node_for_display(node, pcuhash=None, preppcu=True, asofdate=None):
202 if node.plc_pcuid and preppcu:
204 pcu = pcuhash[node.plc_pcuid]
206 pcu = FindbadPCURecord.get_latest_by(plc_pcuid=node.plc_pcuid)
209 agg.pcu_status = pcu.reboot_trial_status
210 agg.pcu_short_status = format_pcu_shortstatus(pcu)
211 agg.pcu = prep_pcu_for_display(pcu)
213 agg.pcu_short_status = "none"
214 agg.pcu_status = "nodata"
218 agg.pcu_status = "nopcu"
219 agg.pcu_short_status = "none"
223 if node.kernel_version:
224 agg.kernel = node.kernel_version.split()[2]
229 agg.loginbase = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
231 agg.loginbase = "unknown"
234 agg.site = HistorySiteRecord.by_loginbase(agg.loginbase)
237 agg.site = agg.site.get_as_of(asofdate)
240 # TODO: need a cleaner fix for this...
241 agg.site = HistorySiteRecord.by_loginbase("pl")
243 agg.site = HistorySiteRecord.by_loginbase("ple")
245 agg.history = HistoryNodeRecord.by_hostname(node.hostname)
247 agg.history = agg.history.get_as_of(asofdate)
249 agg.ports = format_ports(node.port_status)
252 exists = node.plc_node_stats['last_contact']
254 # TODO: this should not assign to the fb object!
255 node.plc_node_stats = {'last_contact' : None}
260 class Root(controllers.RootController, MonitorXmlrpcServer):
261 @expose(template="monitorweb.templates.welcome")
263 # log.debug("Happy TurboGears Controller Responding For Duty")
264 flash("Welcome To MyOps!")
265 return dict(now=time.ctime())
267 @expose(template="monitorweb.templates.nodelist", allow_json=True)
268 def node3(self, filter=None):
269 nhquery = HistoryNodeRecord.query.all()
273 if nh.status == filter:
280 fb = FindbadNodeRecord.get_latest_by(hostname=q.hostname)
283 return dict(now=time.ctime(), query=rquery)
285 def node_query(self, filter):
286 nhquery = HistoryNodeRecord.query.all()
290 if nh.status == filter:
297 fb = FindbadNodeRecord.get_latest_by(hostname=q.hostname)
298 agg = prep_node_for_display(fb)
302 @expose("cheetah:monitorweb.templates.nodelist_plain", as_format="plain",
303 accept_format="text/plain", content_type="text/plain")
304 @expose(template="monitorweb.templates.nodelist", allow_json=True)
305 def node2(self, filter=None):
306 rquery=self.node_query(filter)
307 widget = NodeWidget(template='monitorweb.templates.node_template')
308 return dict(now=time.ctime(), query=rquery, nodewidget=widget)
310 @expose("cheetah:monitorweb.templates.query_plain", as_format="plain",
311 accept_format="text/plain", content_type="text/plain")
312 @expose(template="monitorweb.templates.query", allow_json=True)
313 def query(self, **data):
321 if 'object' in data and data['object'] == "nodes":
322 fbquery = FindbadNodeRecord.get_all_latest()
323 elif 'object' in data and data['object'] == "nodehistory":
324 hostname = data['nodehistory_hostname']
325 data['date_checked'] = 'date_checked'
326 fbrecord = FindbadNodeRecord.get_by(hostname=hostname)
327 fbquery = fbrecord.versions[-500:]
331 # NOTE: reformat some fields.
332 if type(node) is not type(FindbadNodeRecord):
333 agg = node.__dict__.copy()
336 agg.update(agg['plc_node_stats'])
337 if agg['kernel_version']:
338 agg['kernel_version'] = agg['kernel_version'].split()[2]
339 if 'rpmvalue' in data and 'rpms' in data:
341 rpm_list = agg['rpms'].split()
342 rpm_list = filter(lambda x: data['rpmvalue'] in x, rpm_list)
343 agg['rpms'] = " ".join(rpm_list)
351 del fields['rpmvalue']
352 del fields['nodehistory_hostname']
354 return dict(now=time.ctime(), query=query, fields=fields, data=data, queryform=getNodeQueryForm())
356 @expose(template="monitorweb.templates.nodefast", allow_json=True)
357 def node(self, filter=None):
358 nhquery = HistoryNodeRecord.query.all()
362 if nh.status == filter:
363 agg = prep_nodehist(nh)
366 agg = prep_nodehist(nh)
369 return dict(now=time.ctime(), query=query)
371 @expose(template="monitorweb.templates.nodelist")
372 def nodeslow(self, filter='boot'):
373 print "NODE------------------"
374 print "befor-len: ", len( [ i for i in session] )
375 session.flush(); session.clear()
376 print "after-len: ", len( [ i for i in session] )
377 fbquery = FindbadNodeRecord.get_all_latest()
379 filtercount = {'down' : 0, 'boot': 0, 'debug' : 0, 'diagnose' : 0, 'disabled': 0,
380 'neverboot' : 0, 'pending' : 0, 'all' : 0, None : 0}
382 # NOTE: reformat some fields.
383 agg = prep_node_for_display(node)
388 if agg.history.status in ['down', 'offline']:
389 if node.plc_node_stats and node.plc_node_stats['last_contact'] != None:
390 filtercount['down'] += 1
392 filtercount['neverboot'] += 1
393 elif agg.history.status in ['good', 'online']:
394 filtercount['boot'] += 1
395 elif agg.history.status in ['debug', 'monitordebug']:
396 filtercount['debug'] += 1
398 if filtercount.has_key(agg.history.status):
399 filtercount[agg.history.status] += 1
403 if filter == "neverboot":
404 if not node.plc_node_stats or node.plc_node_stats['last_contact'] == None:
406 elif filter == "all":
408 elif filter == agg.history.status:
410 elif filter == 'boot':
414 widget = NodeWidget(template='monitorweb.templates.node_template')
415 return dict(now=time.ctime(), query=query, fc=filtercount, nodewidget=widget)
417 def nodeaction_handler(self, tg_exceptions=None):
418 """Handle any kind of error."""
419 print "NODEACTION_HANDLER------------------"
421 if 'pcuid' in request.params:
422 pcuid = request.params['pcuid']
424 refurl = request.headers.get("Referer",link("pcu"))
427 # TODO: do this more intelligently...
428 uri_fields = urllib.splitquery(refurl)
429 if uri_fields[1] is not None:
430 val = query_to_dict(uri_fields[1])
433 elif 'hostname' in val:
434 pcuid = FindbadNodeRecord.get_latest_by(hostname=val['hostname']).plc_pcuid
440 cherry_trail = cherrypy._cputil.get_object_trail()
441 for i in cherry_trail:
445 return self.pcuview(None, pcuid, **dict(exceptions=tg_exceptions))
447 def nodeaction(self, **data):
448 print "NODEACTION------------------"
449 for item in data.keys():
450 print "%s %s" % ( item, data[item] )
452 if 'hostname' in data:
453 hostname = data['hostname']
455 flash("No hostname given in submitted data")
458 if 'submit' in data or 'type' in data:
460 action = data['submit']
462 action = data['type']
464 flash("No submit action given in submitted data")
467 if action == "Reboot":
468 print "REBOOT: %s" % hostname
469 ret = reboot.reboot_str(str(hostname))
471 if ret: raise RuntimeError("Error using PCU: " + str(ret))
472 flash("Reboot appeared to work. Allow at most 5 minutes. Then run ExternalScan to check current status.")
474 elif action == "ExternalScan":
475 scanapi.externalprobe(str(hostname))
476 flash("External Scan Successful!")
477 elif action == "InternalScan":
478 scanapi.internalprobe(str(hostname))
479 flash("Internal Scan Successful!")
482 raise RuntimeError("Unknown action given")
485 @expose(template="monitorweb.templates.simpleview")
486 def simpleview(self, **data):
487 return self.pre_view(**data)
489 @expose(template="monitorweb.templates.detailview")
490 def detailview(self, **data):
491 return self.pre_view(**data)
493 def pre_view(self, **data):
494 session.flush(); session.clear()
501 # if objtype is not None, then treat 'hostname' or 'loginbase' as a search pattern
516 fields = obj.split(":")
519 obj = fields[1].replace("*", "%")
522 if len(obj.split(".")) > 1 or objtype == "node":
527 if 'loginbase' in data:
528 loginbase = data['loginbase']
530 if 'hostname' in data:
531 hostname = data['hostname']
534 try: pcuid = int(data['pcuid'])
538 try: since = int(since)
542 print "pcuid: %s" % pcuid
543 pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
544 loginbase_list += [ PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base'] ]
548 nodes = [ FindbadNodeRecord.get_latest_by(hostname=hostname) ]
550 nodes = FindbadNodeRecord.query.filter(FindbadNodeRecord.hostname.like(hostname))
553 lb = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
554 if lb not in loginbase_list:
555 loginbase_list += [ lb ]
559 loginbase_list = [ loginbase ]
561 loginbase_list = HistorySiteRecord.query.filter(HistorySiteRecord.loginbase.like(loginbase))
562 loginbase_list = [ l.loginbase for l in loginbase_list ]
566 for loginbase in loginbase_list:
567 actions = ActionRecord.query.filter_by(loginbase=loginbase
568 ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
569 ).order_by(ActionRecord.date_created.desc())
570 actions_list += [ a for a in actions ]
571 site = HistorySiteRecord.by_loginbase(loginbase)
573 sitequery.append(site)
574 # NOTE: because a single pcu may be assigned to multiple hosts,
575 # track unique pcus by their plc_pcuid, then turn dict into list
577 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
578 # NOTE: reformat some fields.
579 agg = prep_node_for_display(node)
582 pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
584 for pcuid_key in pcus:
585 pcuquery += [pcus[pcuid_key]]
587 actionlist_widget = ActionListWidget(template='monitorweb.templates.actionlist_template')
588 return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions_list, actionlist_widget=actionlist_widget, since=since, exceptions=exceptions)
591 # TODO: add form validation
592 @expose(template="monitorweb.templates.pcuview")
593 @exception_handler(nodeaction_handler,"isinstance(tg_exceptions,RuntimeError)")
594 def pcuview(self, loginbase=None, pcuid=None, hostname=None, since=20, **data):
595 session.flush(); session.clear()
602 try: since = int(since)
608 if 'submit' in data.keys() or 'type' in data.keys():
609 if hostname: data['hostname'] = hostname
610 self.nodeaction(**data)
611 if 'exceptions' in data:
612 exceptions = data['exceptions']
616 if len(obj.split(".")) > 1: hostname = obj
620 print "pcuid: %s" % pcuid
621 pcu = FindbadPCURecord.get_latest_by(plc_pcuid=pcuid)
622 loginbase = PlcSite.query.get(pcu.plc_pcu_stats['site_id']).plc_site_stats['login_base']
625 node = FindbadNodeRecord.get_latest_by(hostname=hostname)
626 loginbase = PlcSite.query.get(node.plc_node_stats['site_id']).plc_site_stats['login_base']
629 actions = ActionRecord.query.filter_by(loginbase=loginbase
630 ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since)
631 ).order_by(ActionRecord.date_created.desc())
632 actions = [ a for a in actions ]
633 sitequery = [HistorySiteRecord.by_loginbase(loginbase)]
635 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
636 # NOTE: reformat some fields.
637 agg = prep_node_for_display(node)
639 if agg.pcu: #.pcu.plc_pcuid: # not None
640 #pcu = FindbadPCURecord.get_latest_by(plc_pcuid=agg.plc_pcuid)
641 #prep_pcu_for_display(pcu)
642 pcus[agg.pcu.pcu.plc_pcuid] = agg.pcu
644 for pcuid_key in pcus:
645 pcuquery += [pcus[pcuid_key]]
647 return dict(sitequery=sitequery, pcuquery=pcuquery, nodequery=nodequery, actions=actions, since=since, exceptions=exceptions)
649 @expose(template="monitorweb.templates.pcuhistory")
650 def pcuhistory(self, pcu_id=None):
653 fbnode = HistoryPCURecord.get_by(plc_pcuid=pcu_id)
654 l = fbnode.versions[-100:]
657 #prep_node_for_display(node)
660 return dict(query=query, pcu_id=pcu_id)
662 @expose(template="monitorweb.templates.nodescanhistory")
663 def nodescanhistory(self, hostname=None, length=10):
664 try: length = int(length)
667 fbnode = FindbadNodeRecord.get_by(hostname=hostname)
668 # TODO: add links for earlier history if desired.
669 l = fbnode.versions[-length:]
673 agg = prep_node_for_display(node, pcuhash=None, preppcu=False, asofdate=node.timestamp)
676 if 'length' in request.params:
677 del request.params['length']
678 return dict(query=query, hostname=hostname, params=request.params)
680 @expose(template="monitorweb.templates.nodehistory")
681 def nodehistory(self, hostname=None):
684 fbnode = HistoryNodeRecord.get_by(hostname=hostname)
685 l = fbnode.versions[-100:]
688 #prep_node_for_display(node)
691 return dict(query=query, hostname=hostname)
693 @expose(template="monitorweb.templates.sitehistory")
694 def sitehistory(self, loginbase=None):
697 fbsite = HistorySiteRecord.get_by(loginbase=loginbase)
698 # TODO: add links for earlier history if desired.
699 l = fbsite.versions[-100:]
703 return dict(query=query, loginbase=loginbase)
706 @expose(template="monitorweb.templates.pculist")
707 def pcu(self, filter='all'):
708 print "PCUVIEW------------------"
709 print "befor-len: ", len( [ i for i in session] )
710 session.flush(); session.clear()
711 print "after-len: ", len( [ i for i in session] )
712 fbquery = FindbadPCURecord.get_all_latest()
714 filtercount = {'ok' : 0, 'NetDown': 0, 'Not_Run' : 0, 'pending' : 0, 'all' : 0}
718 if node.reboot_trial_status == str(0):
719 filtercount['ok'] += 1
720 elif node.reboot_trial_status == 'NetDown' or node.reboot_trial_status == 'Not_Run':
721 filtercount[node.reboot_trial_status] += 1
723 filtercount['pending'] += 1
725 pcuagg = prep_pcu_for_display(node)
730 elif filter == "ok" and node.reboot_trial_status == str(0):
732 elif filter == node.reboot_trial_status:
734 elif filter == "pending":
735 # TODO: look in message logs...
736 if node.reboot_trial_status != str(0) and \
737 node.reboot_trial_status != 'NetDown' and \
738 node.reboot_trial_status != 'Not_Run':
742 return dict(query=query, fc=filtercount)
744 @expose(template="monitorweb.templates.sitelist")
745 def site(self, filter='all'):
746 print "SITE------------------"
747 print "befor-len: ", len( [ i for i in session] )
748 session.flush(); session.clear()
749 print "after-len: ", len( [ i for i in session] )
750 filtercount = {'good' : 0, 'down': 0, 'online':0, 'offline' : 0, 'new' : 0, 'pending' : 0, 'all' : 0}
751 fbquery = HistorySiteRecord.query.all()
755 filtercount['all'] += 1
756 if site.new and site.slices_used == 0 and not site.enabled:
757 filtercount['new'] += 1
758 elif not site.enabled:
759 filtercount['pending'] += 1
760 elif site.status in ['good', 'online']:
761 filtercount['good'] += 1
762 elif site.status in ['down', 'offline']:
763 filtercount['down'] += 1
768 elif filter == 'new' and site.new and site.slices_used == 0 and not site.enabled:
770 elif filter == "pending" and not site.enabled:
772 elif filter == 'good' and site.status in ['good', 'online']:
774 elif filter == 'down' and site.status in ['down', 'offline']:
777 return dict(query=query, fc=filtercount)
778 @expose(template="monitorweb.templates.sitesummary")
779 def sitesummary(self, loginbase="princeton"):
781 for node in FindbadNodeRecord.query.filter_by(loginbase=loginbase):
782 agg = prep_node_for_display(node)
785 return dict(nodequery=nodequery, loginbase=loginbase)
787 @expose(template="monitorweb.templates.summary")
788 def summary(self, since=7):
790 sumdata['nodes'] = {}
791 sumdata['sites'] = {}
794 def summarize(query, type):
796 if o.status not in sumdata[type]:
797 sumdata[type][o.status] = 0
798 sumdata[type][o.status] += 1
800 fbquery = HistorySiteRecord.query.all()
801 summarize(fbquery, 'sites')
802 fbquery = HistoryPCURecord.query.all()
803 summarize(fbquery, 'pcus')
804 fbquery = HistoryNodeRecord.query.all()
805 summarize(fbquery, 'nodes')
807 if 'monitordebug' in sumdata['nodes']:
808 d = sumdata['nodes']['monitordebug']
809 del sumdata['nodes']['monitordebug']
810 sumdata['nodes']['failboot'] = d
812 return dict(sumdata=sumdata, setorder=['good', 'offline', 'down', 'online'])
814 @expose(template="monitorweb.templates.actionsummary")
815 def actionsummary(self, since=7):
816 from monitor.wrapper.emailTxt import mailtxt
818 types = filter(lambda x: 'notice' in x, dir(mailtxt))
821 print mon_metadata.bind
822 if session.bind is None:
823 #TODO: figure out why this value gets cleared out...
824 session.bind = mon_metadata.bind
825 result = session.execute("select distinct(action_type) from actionrecord;")
827 types = [r[0] for r in result]
829 try: since = int(since)
833 acts = ActionRecord.query.filter(ActionRecord.action_type==t
834 ).filter(ActionRecord.date_created >= datetime.now() - timedelta(since))
835 results[t] = acts.count()
836 return dict(results=results)
838 @expose(template="monitorweb.templates.actionlist")
839 def actionlist(self, since=7, action_type=None, loginbase=None):
841 try: since = int(since)
844 acts_query = ActionRecord.query.filter(
845 ActionRecord.date_created >= datetime.now() - timedelta(since)
848 acts_query = acts_query.filter_by(loginbase=loginbase)
851 acts_query = acts_query.filter(ActionRecord.action_type==action_type)
853 acts = acts_query.order_by(ActionRecord.date_created.desc())
855 query = [ a for a in acts ]
857 return dict(actions=query, action_type=action_type, since=since)
860 def upload(self, log, **keywords):
863 logtype_list = ['bm.log', ]
865 if 'hostname' in keywords:
866 hostname = keywords['hostname']
867 if 'type' in keywords and keywords['type'] in logtype_list:
868 logtype = keywords['type']
870 if not hostname: return ""
871 if not logtype: return "unknown logtype: %s" % logtype
873 short_target_filename = bootman.bootmanager_log_name(hostname)
874 abs_target_filename = os.path.join(config.MONITOR_BOOTMANAGER_LOG, short_target_filename)
875 print "write data: %s" % abs_target_filename
876 util.file.dumpFile(abs_target_filename, log.file.read())
877 bootman.bootmanager_log_action(hostname, short_target_filename, logtype)
879 print "redirecting 3"