You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by de...@apache.org on 2016/08/11 18:37:54 UTC
svn commit: r1756025 - /uima/uima-ducc/trunk/src/main/admin/ducc_watcher
Author: degenaro
Date: Thu Aug 11 18:37:54 2016
New Revision: 1756025
URL: http://svn.apache.org/viewvc?rev=1756025&view=rev
Log:
UIMA-5053 DUCC ducc_watcher optional admin script to determine status and send notifications
Added:
uima/uima-ducc/trunk/src/main/admin/ducc_watcher (with props)
Added: uima/uima-ducc/trunk/src/main/admin/ducc_watcher
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/src/main/admin/ducc_watcher?rev=1756025&view=auto
==============================================================================
--- uima/uima-ducc/trunk/src/main/admin/ducc_watcher (added)
+++ uima/uima-ducc/trunk/src/main/admin/ducc_watcher Thu Aug 11 18:37:54 2016
@@ -0,0 +1,264 @@
+#! /usr/bin/env python
+# -----------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# -----------------------------------------------------------------------
+
+# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+# +
+# + ducc_watcher
+# +
+# + purpose: send e-mail notification when overall DUCC state changes
+# +
+# + configuration:
+# +
+# + - add ducc.watcher.notification.list = user1@host1 user2@host2...
+# + to ducc.properties
+# + - add this script as a cron job on a host that:
+# + > has access to $DUCC_HOME directory
+# + > has access to DUCC WebServer URL
+# + > has 'localhost' email server
+# +
+# + files:
+# +
+# + - $DUCC_HOME/state/watcher
+# + > comprises the last recorded overall state of DUCC
+# +
+# + - $DUCC_HOME/logs/watcher.log
+# + > comprises a state change events log
+# +
+# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+import datetime
+import getpass
+import os
+import socket
+import stat
+import smtplib
+import sys
+import time
+import urllib
+from HTMLParser import HTMLParser
+from ducc_util import DuccUtil
+from properties import Properties
+
+# amount of time to give DUCC WebServer
+# to boot and determine daemon states
+boot_time_seconds = 90
+
+# email server host name
+email_host = 'localhost'
+
+# for debugging only
+def debug(text):
+ debug = False
+ if(debug):
+ print text
+
+# determine age of the specified file in seconds
+def file_age_in_seconds(filename):
+ return time.time() - os.stat(filename)[stat.ST_MTIME]
+
+# produce a time stamp
+def get_timestamp():
+ tod = time.time()
+ timestamp = datetime.datetime.fromtimestamp(tod).strftime('%Y-%m-%d %H:%M:%S')
+ return timestamp
+
+# get the host running this script
+def get_host():
+ host = socket.gethostname()
+ return host
+
+# get the user running this script
+def get_user():
+ user = getpass.getuser()
+ return user
+
+# send email
+def email(sender,receivers,mail_host,text):
+ smtpObj = smtplib.SMTP(mail_host)
+ smtpObj.sendmail(sender,receivers,text)
+
+# log a message
+def logger(filename,text):
+ watcher_host = socket.gethostname()
+ line = get_timestamp()+' '+get_user()+'@'+get_host()+' '+text+'\n'
+ with open(filename, 'a') as f:
+ f.write(line)
+
+# the possible states of DUCC
+class DuccState:
+
+ up = ':-) All DUCC daemons up'
+ down = ':-( One or more DUCC daemons down'
+ lost = ';-( Lost contact with DUCC WebServer'
+
+# parser for the system.daemons WS page
+class DuccHtmlParser(HTMLParser):
+
+ tr_state = False
+ daemon_state = None
+ daemon_name = None
+ daemons = {}
+
+ def get_daemons(self):
+ return self.daemons
+
+ def handle_starttag(self, tag, attrs):
+ if(tag == 'tr' ):
+ self.tr_state = True
+
+ def handle_endtag(self, tag):
+ if(tag == 'tr'):
+ self.tr_state = False
+ self.daemon_state = None
+ self.daemon_name = None
+
+ def handle_data(self, data):
+ if(self.tr_state):
+ if(self.daemon_state == None):
+ self.daemon_state = data
+ elif(self.daemon_name == None):
+ self.daemon_name = data
+ self.daemons[self.daemon_name] = self.daemon_state
+ for key in self.daemons:
+ value = self.daemons[key]
+
+# determine current DUCC state & take action (send email)
+class DuccWatcher(DuccUtil):
+
+ log_file = '?'
+ state_file = '?'
+ state_prev = DuccState.lost
+ state_curr = DuccState.lost
+ port = ''
+ head = ''
+ host = ''
+ url = ''
+ daemons = {}
+
+ # initialize persistent state, if necessary
+ def init_state_prev(self):
+ filename = self.state_file
+ if(not os.path.isfile(filename)):
+ self.put_state_prev(DuccState.lost)
+
+ # change persistent state
+ def put_state_prev(self,state):
+ filename = self.state_file
+ with open(filename, 'w') as f:
+ f.seek(0)
+ f.write(state+'\n')
+ f.truncate()
+
+ # fetch persistent state
+ def get_state_prev(self):
+ filename = self.state_file
+ with open(filename) as f:
+ self.state_prev = f.read().strip()
+
+ # fetch a property from ducc.properties
+ def get_property(self,key,default):
+ value = self.ducc_properties.get(key)
+ if (value == None):
+ value = default
+ return value
+
+ # fetch the notification list from ducc.properties
+ def get_notification_list(self):
+ notification_list = []
+ key = 'ducc.watcher.notification.list'
+ value = self.get_property(key,'')
+ if(value != None):
+ value = value.replace(","," ")
+ list = value.split(" ")
+ for entry in list:
+ token = ''.join(entry.split())
+ if len(token) > 0:
+ notification_list.append(token)
+ return notification_list
+
+ # initialize variables
+ def initialize(self):
+ ducc_home = self.DUCC_HOME
+ if not ducc_home.endswith('/'):
+ ducc_home = ducc_home+'/'
+ self.ws_boot = ducc_home+'state'+'/'+'daemons'+'/'+'Webserver-boot.properties'
+ self.log_file = ducc_home+'logs'+'/'+'watcher.log'
+ self.state_file = ducc_home+'state'+'/'+'watcher'
+ self.init_state_prev()
+ self.get_state_prev()
+ self.ducc_port = self.get_property('ducc.ws.port','42133')
+ self.ducc_head = self.get_property('ducc.head','localhost')
+ self.ducc_host = self.get_property('ducc.ws.node',self.ducc_head)
+ self.ducc_url = 'http://'+self.ducc_host+':'+self.ducc_port+'/ducc-servlet/classic-system-daemons-data'
+
+ # perform watcher function
+ def run(self):
+ # fetch daemons page from DUCC WebServer
+ try:
+ response = urllib.urlopen(self.ducc_url)
+ data = response.read()
+ except:
+ data = None
+ # parse the daemons page date into
+ # a dict of ( daemon, status ) pairs
+ if(not data == None):
+ parser = DuccHtmlParser()
+ parser.feed(data)
+ daemons = parser.get_daemons()
+ if(daemons != None):
+ self.state_curr = DuccState.up
+ for key in daemons:
+ value = daemons[key]
+ if(value == 'down'):
+ self.state_curr = DuccState.down
+ self.daemons = daemons
+ debug('state'+' '+'curr='+self.state_curr+' '+'prev='+self.state_prev)
+ # if the state has changed, send email to
+ # addresses in ducc.watcher.notification.list
+ # and record to $DUCC_HOME/logs/watcher.log
+ if(self.state_curr != self.state_prev):
+ text = self.state_curr
+ if(self.state_curr == DuccState.down):
+ # allow DUCC WebServer sufficient time
+ # after booting to determine daemons states
+ age = file_age_in_seconds(self.ws_boot)
+ debug('Webserver-boot.properties age='+str(age))
+ if(age < boot_time_seconds):
+ return
+ self.put_state_prev(self.state_curr)
+ text = 'Subject: '+'['+self.ducc_host+']'+' '+text+' '+'</eom>'
+ sent_to = 'nobody'
+ notification_list = self.get_notification_list()
+ if(notification_list != None):
+ if(len(notification_list) > 0):
+ sender = get_user()+'@'+get_host()
+ receivers = notification_list
+ email(sender,receivers,email_host,text)
+ sent_to = ' '.join(notification_list)
+ logmsg = '"'+text+'"'+' sent to: '+sent_to
+ logger(self.log_file,logmsg)
+
+ def main(self, argv):
+ self.initialize()
+ self.run()
+
+if __name__ == "__main__":
+ instance = DuccWatcher()
+ instance.main(sys.argv[1:])
Propchange: uima/uima-ducc/trunk/src/main/admin/ducc_watcher
------------------------------------------------------------------------------
svn:executable = *