HWRF  trunk@4391
dbnalert.py
1 """!This module runs the NCO dbn_alert program, or logs dbn_alert messages
2 if run with dbn alerts disabled."""
3 
4 ##@var __all__
5 # Symbols exported by "from produtil.dbnalert import *"
6 __all__=["DBNAlert"]
7 
8 import logging, os
9 import produtil.run
10 
11 from produtil.prog import Runner
12 from produtil.run import checkrun, exe, alias, run
13 
14 # Globals:
15 
16 ##@var log
17 # logging.Logger object to send dbnalert messages
18 log=None
19 
20 ##@var job
21 # a string representing this job (from os.environ['job'] by default)
22 job=None
23 
24 ##@var send_dbn_alerts
25 # False = don't run dbn_alert. Just log the alerts.
26 send_dbn_alerts=True
27 
28 ##@var no_DBNROOT_warn
29 # True = I have already warned that $DBNROOT is unset
30 no_DBNROOT_warn=False
31 
33  """!Locates the dbn_alert executable based on environment
34  variables, and returns it as a produtil.prog.Runner object."""
35  global no_DBNROOT_warn
36  ENV=os.environ
37  if ENV.get('DBNROOT','')!='':
38  return alias(exe(os.path.join(ENV['DBNROOT'],'bin/dbn_alert')))
39  else:
40  if not no_DBNROOT_warn:
41  log.warning("$DBNROOT is not set. Will search for dbn_alert "
42  "in your $PATH.")
43  no_DBNROOT_warn=True
44  return alias(exe('dbn_alert'))
45 
46 ########################################################################
47 class DBNAlert(object):
48  """!This class represents a call to dbn_alert, as a callable Python
49  object. It allows the instructions on how to make the call to be
50  stored for later use by a produtil.datastore.Product object's
51  add_callback and call_callbacks functions."""
52  def __init__(self,args,loglevel=logging.WARNING,alert_exe=None):
53  """!Create a new DBNAlert object that can be used to send an
54  alert later on.
55  @param args The arguments to dbn_alert.
56  @param alert_exe The dbn_alert executable name.
57  @param loglevel A Python logging level to log messages before each
58  alert."""
59  if not isinstance(args,list) and not isinstance(args,tuple):
60  raise TypeError('In DBNAlert(), the first argument must be a list or tuple of arguments to send to dbn_alert')
61  if alert_exe is not None and not isinstance(alert_exe,basestring) \
62  and not isinstance(alert_exe,Runner):
63  raise TypeError('In DBNAlert(), the alert_exe argument must be a string executable name, or a produtil.prog.Runner object')
64 
65  self.alert_args=[ str(s) for s in args ]
66  if isinstance(alert_exe,Runner): alert_exe=alias(alert_exe)
67  self.alert_exe=alert_exe
68  if self.alert_exe is None: self.alert_exe=find_dbn_alert()
69  self.loglevel=loglevel
70  ##@var alert_args
71  # Array of arguments to the alert function
72 
73  ##@var loglevel
74  # Desired logging level.
75 
76  ##@var alert_exe
77  # Alert executable
78 
79  def __call__(self,**kwargs):
80  """!Expands strings specified in the constructor and calls
81  dbn_alert with the results. If dbn alerts are disabled, then
82  the fact that a dbn alert would be run is logged, but
83  dbn_alert is NOT called.
84  @param kwargs string formatting variables for the dbn alert arguments"""
85  assert(job is not None)
86  kwargs['job']=str(job)
87  alert_args=[ s.format(**kwargs) for s in self.alert_args ]
88  if send_dbn_alerts:
89  if isinstance(self.alert_exe,basestring):
90  cmd=exe(self.alert_exe)[alert_args]
91  else:
92  cmd=self.alert_exe[alert_args]
93  log.log(self.loglevel,'DBN Alert: '+repr(cmd))
94  ret=run(cmd)
95  log.log(self.loglevel,'Exit status %s from dbn_alert.'%(repr(ret), ))
96  else:
97  log.log(self.loglevel,'dbn_alert is disabled')
98  log.log(self.loglevel,'would run: dbn_alert '+( " ".join(alert_args) ))
99 
100 ########################################################################
101 def init_logging(logger=None):
102  """!Initializes logging for this module. The argument is either a
103  logging.Logger to log to, or the string name of the logging
104  domain."""
105  global log
106  if logger is None:
107  logger=logging.getLogger('dbn_alert')
108  elif isinstance(logger,basestring):
109  logger=logging.getLogger(logger)
110  log=logger
111 
112 ########################################################################
113 def init_jobstring(jobname=None):
114  """!Sets the job string (for dbn_alerts) to the specified value,
115  or if unspecified, tries to guess one from the environment."""
116  global job
117  if jobname is not None:
118  job=str(jobname)
119  return
120 
121  ENV=os.environ
122  if 'job' in ENV:
123  job=str(ENV['job'])
124  return
125 
126  # Cannot guess a full name, so try to piece one together. It will
127  # look like "LLHWRF_POST.30113"
128  (name,iid)=(None,None) # name=HWRF_POST part, iid=30113 part
129 
130  # Get the job name:
131  for namevar in ['LSB_JOBNAME','PBS_JOBNAME','MOAB_JOBNAME']:
132  if namevar in ENV and ENV[namevar]!='':
133  name=os.path.basename(ENV[namevar]) # remove slashes
134  break
135  if name is None: name='unknown'
136 
137  # Get the job id:
138  for iidvar in ['LSB_JOBID','PBS_JOBID','MOAB_JOBID']:
139  if iidvar in ENV and ENV[iidvar]!='':
140  iid=str(ENV[iidvar])
141  if iid is None: iid=str(os.getpid())
142 
143  job='LL%s.%s'%(name,iid)
144 
145 ########################################################################
146 def init_dbn_alert(send_dbn=None):
147  """!DBN alert initialization helper function.
148 
149  This is part of the implementation of init_module: it decides
150  whether to send DBNet alerts, and sets the module-scope
151  send_dbn_alerts variable accordingly. That will then be used by
152  DBNAlert objects to decide whether to actually call the dbn_alert
153  program.
154  @protected
155  @param send_dbn Do we send dbn alerts?"""
156  logger=logging.getLogger('dbn_alert')
157  global send_dbn_alerts
158  ENV=os.environ
159  send_dbn_alerts=False
160 
161  if send_dbn is not None and not send_dbn:
162  send_dbn_alerts=send_dbn
163  return
164 
165  if 'PARAFLAG' not in ENV:
166  logger.warning('PARAFLAG is unset. Disabling DBN alerts.')
167  elif ENV['PARAFLAG'].upper()!='NO':
168  logger.warning('PARAFLAG=%s is not "NO". Disabling DBN alerts.'
169  %(ENV['PARAFLAG'],))
170  elif send_dbn is None:
171  send_dbn_alerts = ( 'YES' == ENV.get('SENDDBN','NO').upper() )
172  if send_dbn_alerts:
173  logger.warning('Enabling dbn_alerts because SENDDBN=YES')
174  else:
175  logger.warning('Disabling dbn_alerts because SENDDBN is not YES')
176  else:
177  send_dbn_alerts=send_dbn
178  if send_dbn_alerts:
179  logger.warning('Enabling dbn_alerts because the code manually '
180  'turned them on (send_dbn=True)')
181  else:
182  logger.warning('Disabling dbn_alerts because the code manually '
183  'turned them off (send_dbn=False)')
184  if 'DBNROOT' not in ENV:
185  logger.warning('DBNROOT is unset. Disabling DBN alerts.')
186  send_dbn_alerts=False
187  elif ENV.get('DBNROOT') == 'DBNROOT_OFF':
188  logger.warning(
189  'DBNROOT is set to DBNROOT_OFF. Disabling DBN alerts.')
190  send_dbn_alerts=False
191 
192 ########################################################################
193 def init_module(logger=None,jobname=None,send_dbn=None):
194  """!Call to initialize this module.
195 
196  Initializes the logging and job string for this module.
197  @param logger Either a logging.Logger object to receive log
198  messages, or the string name of a logger domain.
199  @param jobname The dbn_alert job string for this job.
200  @param send_dbn Optional. If specified, this controls whether
201  dbn_alert is actually run (True) or not (False). If unspecified,
202  then the SENDDBN environment variable is used."""
203  init_jobstring(jobname)
204  init_logging(logger)
205  init_dbn_alert(send_dbn)
def find_dbn_alert()
Locates the dbn_alert executable based on environment variables, and returns it as a produtil...
Definition: dbnalert.py:32
loglevel
Desired logging level.
Definition: dbnalert.py:69
alert_args
Array of arguments to the alert function.
Definition: dbnalert.py:65
Implements the produtil.run: provides the object tree for representing shell commands.
Definition: prog.py:1
A shell-like syntax for running serial, MPI and OpenMP programs.
Definition: run.py:1
This class represents a call to dbn_alert, as a callable Python object.
Definition: dbnalert.py:47
def __init__
Create a new DBNAlert object that can be used to send an alert later on.
Definition: dbnalert.py:52
def __call__(self, kwargs)
Expands strings specified in the constructor and calls dbn_alert with the results.
Definition: dbnalert.py:79
def init_logging
Initializes logging for this module.
Definition: dbnalert.py:101
def init_dbn_alert
DBN alert initialization helper function.
Definition: dbnalert.py:146
def init_jobstring
Sets the job string (for dbn_alerts) to the specified value, or if unspecified, tries to guess one fr...
Definition: dbnalert.py:113
alert_exe
Alert executable.
Definition: dbnalert.py:67
def init_module
Call to initialize this module.
Definition: dbnalert.py:193