#!/usr/bin/env python3 ##************************************************************** ## ## Copyright (C) 1990-2007, Condor Team, Computer Sciences Department, ## University of Wisconsin-Madison, WI. ## ## Licensed 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. ## ##************************************************************** from __future__ import print_function import sys import os import getopt import time class SiteSummary: name = None hours = None jobs = None def __init__(self): self.hours = {} self.jobs = {} def Usage(): msg = """ USAGE: condor_router_history [OPTIONS] --show_records (show individual records in addition to summary) --show_iwd (when showing records, include working directory) --age= (how many days ago end time should be) --days= (how many days report should cover) --start="YYYY-MM-DD HH:MM" (date of start time of report) """ sys.stderr.write(msg) def ReadHistoryFile(history_file,class_ads): F = open(history_file,"r") current_ad = {} while 1: line = F.readline() if not line: break if line.find("***") == 0: cluster = current_ad.get("clusterid") proc = current_ad.get("procid") if cluster and proc: class_ads[cluster + "." + proc] = current_ad current_ad = {} continue fields = line.split("=",1) if len(fields) == 2: attribute = fields[0].lower().strip() value = fields[1].strip() current_ad[attribute] = value cluster = current_ad.get("clusterid") proc = current_ad.get("procid") if cluster and proc: class_ads[cluster + "." + proc] = current_ad def ShowSummary(site_summaries): sorted_summary = [] total = SiteSummary() total.name = "TOTAL" for site in site_summaries.keys(): site_info = site_summaries[site] sort_val = site_info.hours.get("C") sorted_summary.append([sort_val,site_info]) for key in site_info.hours.keys(): if key not in total.hours: total.hours[key] = 0 total.hours[key] += site_info.hours[key] for key in site_info.jobs.keys(): if key not in total.jobs: total.jobs[key] = 0 total.jobs[key] += site_info.jobs[key] sorted_summary.sort() sorted_summary.reverse() sorted_summary.append([0,total]) print("%-15s %5s %7s %7s" % ("Site", "Hours", "Jobs", "Runs")) print("%-15s %5s %7s %5s" % ("", "", "Completed", "Aborted")) print("-------------------------------------------------------") for sort_val,site_info in sorted_summary: c_hours = int(round(site_info.hours.get("C",0))) c_jobs = site_info.jobs.get("C",0) x_jobs = 0 for code in site_info.jobs.keys(): if code == "C": continue x_jobs += site_info.jobs[code] if site_info.name == "TOTAL": print("-------------------------------------------------------") print("%-15s %5s %7s %5s" % (site_info.name, c_hours, c_jobs, x_jobs)) long_options = [ "help", "show_records", "days=", "age=", "start=", "show_iwd" ] report_period = 60*60*24 end_timestamp = time.time() show_records = 0 start_timestamp = None show_iwd = 0 try: options,args = getopt.getopt(sys.argv[1:],"h",long_options) for option,value in options: if option == "--help" or option == "-h": Usage() os._exit(0) if option == "--age": end_timestamp = time.time() - 3600*24*float(value) if option == "--start": t = time.strptime(value,"%Y-%m-%d %H:%M") a = [] for i in t: a.append(i) a[8] = -1 #unknown daylight savings time start_timestamp = time.mktime(a) if option == "--days": report_period = 3600*24*float(value) if option == "--show_records": show_records = 1 if option == "--show_iwd": show_iwd = 1 except Exception as e: sys.stderr.write("Command line argument error: %s\n" % (e)) Usage() sys.exit(1) show_summary = not show_records if not start_timestamp: start_timestamp = end_timestamp - report_period spool_dir = os.popen("condor_config_val SPOOL").read() spool_dir = spool_dir.strip() if not spool_dir: sys.stderr.write("Cannot find spool directory with 'condor_config_val SPOOL'\n") sys.exit(1) start_time_desc = time.strftime("%Y-%m-%d %H:%M",time.localtime(start_timestamp)) end_time_desc = time.strftime("%Y-%m-%d %H:%M",time.localtime(end_timestamp)) print("Routed job history from " + start_time_desc + " to " + end_time_desc) print() if show_records: print("JobID", "Status", "Site", "Runtime", end = ' ') if show_iwd: print("IWD", end = ' ') print() class_ads = {} for fname in os.listdir(spool_dir): if fname.find("history") == 0: history_file = os.path.join(spool_dir,fname) mtime = os.stat(history_file)[8] if mtime < start_timestamp: continue ReadHistoryFile(history_file,class_ads) site_summaries = {} for jobid in class_ads.keys(): ad = class_ads[jobid] route = ad.get("routename") if not route: #for backward compatibility route = ad.get("routedfromroute") if not route: continue route = route.replace('"','') cdate = float(ad.get("completiondate")) if cdate < start_timestamp: continue if cdate > end_timestamp: continue jobstatus = ad.get("jobstatus") job_status_codes = "UIRXCHE" status_code = job_status_codes[int(jobstatus)] remote_walltime = ad.get("remotewallclocktime",0) remote_walltime = int(round(float(remote_walltime))) site_sum = site_summaries.get(route) if not site_sum: site_sum = SiteSummary() site_sum.name = route site_summaries[route] = site_sum if not site_sum.hours.get(status_code): site_sum.hours[status_code] = 0 site_sum.hours[status_code] += remote_walltime/3600 if not site_sum.jobs.get(status_code): site_sum.jobs[status_code] = 0 site_sum.jobs[status_code] += 1 if show_iwd: iwd = ad.get("submit_iwd","") if len(iwd) > 1: if iwd[0] == '"' and iwd[-1] == '"': iwd = iwd[1:-1] if show_records: print(jobid, status_code, route, remote_walltime, end = ' ') if show_iwd: print(iwd, end = ' ') print() if show_summary: ShowSummary(site_summaries)