| #! /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_status |
| # + |
| # + purpose: report current ducc daemons status |
| # + |
| # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| |
| import datetime |
| import sys |
| import time |
| |
| from HTMLParser import HTMLParser |
| from optparse import OptionParser |
| |
| from ducc_base import find_ducc_home |
| from properties import * |
| |
| # ----------------------------------------------------------------------- |
| # Extend OptionParser class |
| class ExtendedOptionParser(OptionParser): |
| # override epilog formatter so |
| # that newlines are not deleted! |
| def format_epilog(self, formatter): |
| return self.epilog |
| # ----------------------------------------------------------------------- |
| # parser for the system.daemons WS page |
| class DuccHtmlParser(HTMLParser): |
| |
| tr_state = False |
| daemon_state = None |
| daemon_name = None |
| daemon_date = None |
| daemon_ip = None |
| daemon_host = 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 |
| self.daemon_date = None |
| self.daemon_ip = None |
| self.daemon_host = 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 |
| if(self.daemon_name == 'Agent'): |
| pass |
| else: |
| self.daemons[self.daemon_name] = self.daemon_state |
| elif(self.daemon_date == None): |
| self.daemon_date = data |
| elif(self.daemon_ip == None): |
| self.daemon_ip = data |
| elif(self.daemon_host == None): |
| self.daemon_host = data |
| self.daemon_name = data |
| self.daemons[self.daemon_name] = self.daemon_state |
| # ----------------------------------------------------------------------- |
| |
| default_host = 'localhost' |
| default_port = '42133' |
| protocol = 'http://' |
| servlet = '/ducc-servlet/classic-system-daemons-data' |
| options = None |
| |
| webserver = 'Webserver' |
| head_daemons = [ 'Orchestrator', 'ResourceManager', 'Database', 'Broker', 'ProcessManager', 'ServiceManager', webserver ] |
| |
| newline = '\n' |
| version = '1.0' |
| |
| # to console |
| def to_stdout(text): |
| try: |
| print text |
| except: |
| pass |
| try: |
| sys.stdout.flush() |
| except: |
| pass |
| |
| def close(): |
| try: |
| sys.stdout.close() |
| except: |
| pass |
| |
| # check for log-style formating of text message |
| def is_log_format(): |
| retVal = False |
| if(not options == None): |
| if(options.flag_log_format): |
| retVal = True |
| return retVal |
| |
| # produce a time stamp |
| def get_timestamp(): |
| global options |
| tod = time.time() |
| timestamp = datetime.datetime.fromtimestamp(tod).strftime('%Y-%m-%d %H:%M:%S') |
| return timestamp |
| |
| # exception |
| def exception(e): |
| to_stdout(str(e)) |
| |
| # error message |
| def error(text): |
| prefix = '' |
| if(is_log_format()): |
| type = 'E' |
| prefix = get_timestamp()+' '+type+' ' |
| line = prefix+text |
| to_stdout(line) |
| |
| # info message |
| def info(text): |
| prefix = '' |
| if(is_log_format()): |
| type = 'I' |
| prefix = get_timestamp()+' '+type+' ' |
| line = prefix+text |
| to_stdout(line) |
| |
| # debug message |
| def debug(text): |
| global options |
| if(not options == None): |
| if(options.flag_debug): |
| prefix = '' |
| if(is_log_format()): |
| type = 'D' |
| prefix = get_timestamp()+' '+type+' ' |
| line = prefix+text |
| to_stdout(line) |
| |
| # trace message |
| def trace(text): |
| pass |
| |
| # exit |
| def exit(code,msg=True): |
| if(msg): |
| text = 'exit code='+str(code) |
| error(text) |
| sys.exit(code) |
| |
| # epilog for --help |
| def get_epilog(): |
| epilog = '' |
| return epilog |
| |
| # --target host:port of WS for fetching of daemons status |
| def validate_target(): |
| global options |
| global default_port |
| global protocol |
| global servlet |
| target = options.target |
| if(':' not in target): |
| target = target+':'+default_port |
| if(target.startswith(protocol)): |
| target = target.replace(protocol,'',1) |
| options.ducc_url_base = protocol+target |
| options.ducc_url_servlet = protocol+target+servlet |
| debug('target: '+options.ducc_url_base) |
| |
| # parse command line |
| def parse_cmdline(): |
| global options |
| global default_host |
| global default_port |
| parser = ExtendedOptionParser(epilog=get_epilog()) |
| width = 45 |
| parser.formatter.help_position = width |
| parser.formatter.max_help_position = width |
| parser.add_option('-a','--agents', action='store_true', dest='flag_agents', default=False, |
| help='include agents') |
| parser.add_option('-d','--debug', action='store_true', dest='flag_debug', default=False, |
| help='display debugging messages') |
| parser.add_option('-e','--enumerate', action='store_true', dest='flag_enumerate', default=False, |
| help='display each individual daemon status') |
| parser.add_option('-l','--log-format', action='store_true', dest='flag_log_format', default=False, |
| help='display in log format') |
| parser.add_option('-t','--target', action='store', dest='target', default=default_host+':'+default_port, |
| help='<host>:<port> with default of '+default_host+':'+default_port) |
| parser.add_option('-v','--version', action='store_true', dest='flag_version', default=False, |
| help='display version of this script') |
| (options, args) = parser.parse_args() |
| if(options.flag_version): |
| info('version='+version) |
| exit(1,msg=False) |
| validate_target() |
| |
| # fetch current daemons state |
| def fetch_state_current(): |
| global options |
| import urllib2 |
| try: |
| opener = urllib2.build_opener() |
| if(options.flag_agents): |
| opener.addheaders.append(('Cookie', 'DUCCagents=show')) |
| response = opener.open(options.ducc_url_servlet) |
| options.ducc_raw_data = response.read() |
| trace(options.ducc_raw_data) |
| except Exception,e: |
| error('unable to fetch data from '+options.ducc_url_servlet) |
| exception(e) |
| exit(1) |
| |
| # filter non-head daemons |
| def filter(): |
| global options |
| global head_daemons |
| if(not options.flag_agents): |
| daemons = options.daemons |
| options.daemons = {} |
| for key in daemons: |
| if(key in head_daemons): |
| options.daemons[key] = daemons[key] |
| else: |
| debug('delete '+key) |
| |
| # transform raw data |
| def transform(): |
| global options |
| global head_daemons |
| try: |
| parser = DuccHtmlParser() |
| parser.feed(options.ducc_raw_data) |
| options.daemons = parser.get_daemons() |
| options.daemons_head = {} |
| options.daemons_agent = {} |
| for key in options.daemons: |
| value = options.daemons[key] |
| if(key in head_daemons): |
| options.daemons_head[key] = value |
| else: |
| options.daemons_agent[key] = value |
| debug(str(options.daemons)) |
| filter() |
| except Exception,e: |
| error('unable to transform data from '+options.ducc_url_servlet) |
| exception(e) |
| exit(1) |
| |
| # summarize |
| def summarize(): |
| global options |
| global head_daemons |
| options.head_up = 0 |
| options.head_down = 0 |
| options.agent_up = 0 |
| options.agent_down = 0 |
| for key in options.daemons_head: |
| value = options.daemons_head[key] |
| if(value == 'up'): |
| options.head_up = options.head_up + 1 |
| elif(value == 'up, pending JD allocation'): |
| options.head_up = options.head_up + 1 |
| else: |
| options.head_down = options.head_down + 1 |
| for key in options.daemons_agent: |
| value = options.daemons_agent[key] |
| if(value == 'up'): |
| options.agent_up = options.agent_up + 1 |
| else: |
| options.agent_down = options.agent_down + 1 |
| |
| # display results |
| def display(): |
| global options |
| global newline |
| summarize(); |
| text0 = options.target |
| text1 = 'head: '+'up='+str(options.head_up)+' '+'down='+str(options.head_down) |
| text2 = 'agent: '+'up='+str(options.agent_up)+' '+'down='+str(options.agent_down) |
| if(options.flag_agents): |
| text = text0+' '+text1+' '+text2 |
| else: |
| text = text0+' '+text1 |
| output = text |
| info(output) |
| if(options.flag_enumerate): |
| for key in sorted(options.daemons): |
| output = key+'='+options.daemons[key] |
| info(output) |
| |
| def init(): |
| global default_host |
| global default_port |
| DUCC_HOME = find_ducc_home() |
| #print DUCC_HOME |
| propsfile = DUCC_HOME+'/resources/ducc.properties' |
| ducc_properties = Properties() |
| ducc_properties.load(propsfile) |
| _head = ducc_properties.get('ducc.head') |
| #print _head |
| if _head != None: |
| default_host = _head |
| _port = ducc_properties.get('ducc.ws.port') |
| #print _port |
| if _port != None: |
| default_port = _port |
| |
| |
| # report current ducc daemons status |
| def main(argv): |
| init() |
| parse_cmdline() |
| fetch_state_current() |
| transform() |
| display() |
| close() |
| |
| if __name__ == '__main__': |
| main(sys.argv[1:]) |