| #! /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. |
| # ----------------------------------------------------------------------- |
| |
| import datetime |
| import getpass |
| import socket |
| import sys |
| import time |
| |
| from HTMLParser import HTMLParser |
| |
| from optparse import HelpFormatter |
| from optparse import OptionGroup |
| from optparse import OptionParser |
| |
| default_host = 'localhost' |
| default_port = '42133' |
| protocol = 'http://' |
| servlet = '/ducc-servlet/classic-jobs-data' |
| options = None |
| |
| sep = '\n' |
| found = False |
| |
| # ---------------------------------------------- |
| |
| # 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 jobs WS page |
| class DuccHtmlParser(HTMLParser): |
| |
| token = 0 |
| |
| id = '' |
| date = '' |
| duration= '' |
| user = '' |
| sched_class ='' |
| state = '' |
| reason = '' |
| services = '' |
| processes = '' |
| init_fails = '' |
| run_fails = '' |
| pgin = '' |
| swap = '' |
| memory = '' |
| total = '' |
| done = '' |
| error = '' |
| dispatch = '' |
| retry = '' |
| preempt = '' |
| description = '' |
| |
| def handle_starttag(self, tag, attrs): |
| if(tag == 'tr' ): |
| self.token = 0 |
| elif(tag == 'td' ): |
| self.token = self.token + 1 |
| elif(tag == 'span' ): |
| pass |
| elif(tag == 'input' ): |
| pass |
| elif(tag == 'a' ): |
| pass |
| elif(tag == 'br' ): |
| pass |
| elif(tag == 'div' ): |
| pass |
| elif(tag == 'i' ): |
| pass |
| else: |
| debug("start: "+tag) |
| |
| def handle_endtag(self, tag): |
| global sep |
| global options |
| global found |
| if(options.id == self.id): |
| if(tag == 'tr' ): |
| found = True |
| text = '' \ |
| +'id............ '+self.id \ |
| +sep \ |
| +'date.......... '+self.date \ |
| +sep \ |
| +'duration...... '+self.duration \ |
| +sep \ |
| +'user.......... '+self.user \ |
| +sep \ |
| +'class......... '+self.sched_class \ |
| +sep \ |
| +'state......... '+self.state \ |
| +sep \ |
| +'reason........ '+self.reason \ |
| +sep \ |
| +'services...... '+self.services \ |
| +sep \ |
| +'processes..... '+self.processes \ |
| +sep \ |
| +'init_fails.... '+self.init_fails \ |
| +sep \ |
| +'run_fails..... '+self.run_fails \ |
| +sep \ |
| +'pgin.......... '+self.pgin \ |
| +sep \ |
| +'swap.......... '+self.swap \ |
| +sep \ |
| +'memory........ '+self.memory \ |
| +sep \ |
| +'total......... '+self.total \ |
| +sep \ |
| +'done.......... '+self.done \ |
| +sep \ |
| +'error......... '+self.error \ |
| +sep \ |
| +'dispatch...... '+self.dispatch \ |
| +sep \ |
| +'retry......... '+self.retry \ |
| +sep \ |
| +'preempt....... '+self.preempt \ |
| +sep \ |
| +'description... '+self.description \ |
| +'' |
| print text |
| elif(tag == 'td' ): |
| pass |
| elif(tag == 'span' ): |
| pass |
| elif(tag == 'input' ): |
| pass |
| elif(tag == 'a' ): |
| pass |
| elif(tag == 'br' ): |
| pass |
| elif(tag == 'div' ): |
| pass |
| elif(tag == 'i' ): |
| pass |
| else: |
| debug("end: "+tag) |
| |
| def handle_data(self, data): |
| global options |
| if(self.token == 0): |
| pass |
| elif(self.token == 1): |
| pass |
| # Id |
| elif(self.token == 2): |
| self.id = data |
| if(options.id == self.id): |
| # Start |
| if(self.token == 3): |
| self.date = data |
| # Duration |
| elif(self.token == 4): |
| self.duration = self.duration+data |
| elif(self.token == 5): |
| self.user = data |
| elif(self.token == 6): |
| self.sched_class = data |
| elif(self.token == 7): |
| self.state = data |
| elif(self.token == 8): |
| self.reason = data |
| elif(self.token == 9): |
| self.services = data |
| elif(self.token == 10): |
| self.processes = data |
| elif(self.token == 11): |
| self.init_fails = data |
| elif(self.token == 12): |
| self.run_fails = data |
| elif(self.token == 13): |
| self.pgin = data |
| elif(self.token == 14): |
| self.swap = data |
| elif(self.token == 15): |
| self.memory = data |
| elif(self.token == 16): |
| self.total = data |
| elif(self.token == 17): |
| self.done = data |
| elif(self.token == 18): |
| self.error = data |
| elif(self.token == 19): |
| self.dispatch = data |
| elif(self.token == 20): |
| self.retry = data |
| elif(self.token == 21): |
| self.preempt = data |
| elif(self.token == 22): |
| self.description = data |
| else: |
| debug("token: "+str(self.token)+" "+"data: "+data) |
| |
| # ----------------------------------------------------------------------- |
| |
| # epilog for --help |
| def get_epilog(): |
| epilog = '' |
| return epilog |
| |
| # produce a time stamp |
| def get_timestamp(): |
| tod = time.time() |
| timestamp = datetime.datetime.fromtimestamp(tod).strftime('%Y-%m-%d %H:%M:%S') |
| return timestamp |
| |
| # 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 |
| try: |
| if(not options == None): |
| if(options.flag_log_format): |
| retVal = True |
| except Exception: |
| pass |
| return retVal |
| |
| # info message to log |
| 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) |
| |
| # error message |
| def error(text): |
| prefix = '' |
| if(is_log_format()): |
| type = 'E' |
| prefix = get_timestamp()+' '+type+' ' |
| line = prefix+text |
| to_stdout(line) |
| |
| # exception |
| def exception(e): |
| to_stdout(str(e)) |
| |
| # id is required |
| def validate_id(): |
| global options |
| if(not options.id): |
| error('required "id" not specified') |
| exit(1) |
| |
| # --target host:port of WS for fetching of daemons status |
| def validate_target(): |
| global options |
| global default_host |
| 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 |
| parser = ExtendedOptionParser(epilog=get_epilog()) |
| width = 45 |
| parser.formatter.help_position = width |
| parser.formatter.max_help_position = width |
| parser.add_option('--id', action='store', dest='id', default=None, |
| help='[REQUIRED] id of job to query') |
| parser.add_option('--debug', action='store', dest='flag_debug', default=False, |
| help='display debugging information') |
| parser.add_option('--target', action='store', dest='target', default=default_host+':'+default_port, |
| help='<host>:<port> with default of '+default_host+':'+default_port) |
| |
| (options, args) = parser.parse_args() |
| |
| # -id |
| validate_id() |
| |
| # -target |
| validate_target() |
| |
| # fetch current daemons state |
| def fetch_state_current(): |
| global options |
| import urllib2 |
| try: |
| opener = urllib2.build_opener() |
| response = opener.open(options.ducc_url_servlet) |
| options.ducc_raw_data = response.read() |
| debug(options.ducc_raw_data) |
| except Exception,e: |
| error('unable to fetch data from '+options.ducc_url_servlet) |
| exception(e) |
| exit(1) |
| |
| # transform raw data |
| def transform(): |
| global options |
| global head_daemons |
| global found |
| try: |
| parser = DuccHtmlParser() |
| parser.feed(options.ducc_raw_data) |
| if(found == False): |
| print options.id+' '+'not found' |
| except Exception,e: |
| error('unable to transform data from '+options.ducc_url_servlet) |
| exception(e) |
| exit(1) |
| |
| def main(argv): |
| global default_host |
| try: |
| from ducc_base import DuccBase |
| base = DuccBase() |
| default_host = base.ducc_properties.get('ducc.head') |
| parse_cmdline() |
| fetch_state_current() |
| transform() |
| |
| except Exception,e: |
| error('exception in main') |
| exception(e) |
| |
| if __name__ == '__main__': |
| main(sys.argv[1:]) |