#
# CC_FLEX_GRAPH_LIC.pl
#
# Track and graphically display ClearCase license usage for a day
# or series of days.
#
# Could be started as continuous "cron" (UNIX) or "at" job (Windows).
#
# REQUIRED: Required GIFs etc. are located here (self extracting exe):
# http://www.abs-consulting.com/ftp/SCRIPTS/CC_GRAPH_LIC.exe (100k)
#
#
# A detailed readme is located at:
# http://www.abs-consulting.com/ftp/SCRIPTS/CC_GRAPH_LIC.readme.html
#
# ASSUMED: Must run on a machine that has access to ClearCase licenses server
# or the FlexLM License server.
#
# Author: Charles W. Clarke III (ABS)
# email: charles@abs-consulting.com
# URL: http://www.abs-consulting.com
# Date: Feb. 25, 2009
####################################################################
# History: 02/25/09 : Created by A Better Solution, Inc. for Xtera
####################################################################
##########################################
# Site data: #
# You can change this data within limits #
##########################################
$CLOSE_OUT_AFTER = "23.5"; # Period that signals to perform closout functions
# This means run till 11:50pm then stop
$UPDATE_MINUTES = 3; # From 1 to 3 - never more than 3 or you will have
# to rewrite end of day code
$DAYS_TO_KEEP = 120; # Must be divisible by 5
# This is for the "range" graph data only
# - All daily graphs are saved until you remove
# but their data is "tossed' daily
$flexlm_port = "27000"; # Change these two values for your FlexLM port
$flexlm_server = "vulcan"; # and FlexLM server
#$FLEXLM_VERSION = "11"; # Change to "" if not running againts FlexLM
# version 7.0
####################################
######## Data Initializaton ########
####################################
@hour_text = ( '12', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11',
'12', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11' );
$self = $parent_dir = $0;
$UPDATE_SECONDS = $UPDATE_MINUTES * 60;
$END_OF_DAY_PAUSE = 600 + ($UPDATE_SECONDS * 2);
$DENIED_GRAPH_HEIGHT = 30;
#############################################################################
# There are functions that perform dirname and basename in "real" Perl, but #
# this was designed to also work with cqperl distributed with ClearCase. #
#############################################################################
$char = chop($parent_dir);
while (($char !~ /[\\\/]/) && ($char ne ""))
{ $char = chop($parent_dir); }
$parent_dir = ($char eq "") ? "." : $parent_dir.$char;
$self .= "/";
@me = split (/[\\\/]/, $self);
$self = $me[$#me];
##########################################
# Warning placed in generated html files #
##########################################
$STAMP = " \n";
$STAMP .= " \n";
########################
######## MAIN ########----------------------------------------------------------------
########################
chdir ($parent_dir); # Its all relative - Eienstien ??
if (! -e "data")
{ mkdir ("data", 0777) or die "Can't create data directory \n$!\n"; }
if (! -e "web_results")
{ mkdir ("web_results", 0777) or die "Can't create web_results directory \n$!\n"; }
$OS = "$ENV{'OS'}";
if ($OS =~ /[Ww]indows/)
{
$_front_html = "display_license_data.html";
}
else
{
$_front_html = "display_license_data.html";
}
##############################
# add products to track here
##############################
#@products = ("ClearCase", "ClearQuest", "Multisite", "AnalystStudio", "DevelopmentStudio", "UnifyingPlatform", "TestStudio");
@products = ("ClearCase", "ClearQuest");
##############################################
# Rebuild the required licenses.html page. #
##############################################
open (FRONT_HTML, ">$_front_html") || die "Can't open file ($_front_html)\n$!\n";
# select (FRONT_HTML);
printf FRONT_HTML " \n";
printf FRONT_HTML "
License Tracker \n";
printf FRONT_HTML " \n";
printf FRONT_HTML $STAMP;
printf FRONT_HTML "\n";
printf FRONT_HTML "
Dynamic License Tracker
";
printf FRONT_HTML "
\n";
foreach $product (@products){
printf FRONT_HTML "Licenses for ${product}
\n";
}
printf FRONT_HTML "\n";
printf FRONT_HTML "
\n";
printf FRONT_HTML $STAMP;
printf FRONT_HTML "For support issues please contact Support
\n";
printf FRONT_HTML " \n";
printf FRONT_HTML " \n";
close (FRONT_HTML);
$running = 1;
while ($running)
{
##############################
# begin loop per product
##############################
foreach ${product} (@products){
#######################
# Initialze some data #
#######################
%HASHED_DATA = ();
@BUFF = ();
($seconds, $minutes, $hours, $day_of_month, $month, $year, $week_day, $day_of_year, $junk) = localtime (time);
$month += 1;
$month = ($month < 10) ? "0"."$month" : $month;
$day_of_month = ($day_of_month < 10) ? "0"."$day_of_month" : $day_of_month;
$year += 1900;
${date} = "$year"."_"."$month"."_"."$day_of_month";
$printed_date = "$month/$day_of_month/$year";
$key_minutes = int ($minutes / 10);
$current_key = ($hours < 10) ? "0$hours.$key_minutes" : "$hours.$key_minutes";
$printed_hour = "$hour_text[$hours]:";
$printed_hour = ($minutes < 10) ? "$printed_hour"."0$minutes" : "$printed_hour"."$minutes";
$printed_time = ($hours < 12) ? "$printed_hour"."am" : "$printed_hour"."pm" ;
if ($OS =~ /[Ww]indows/)
{
$_front_html = "display_license_data.html";
$_main_html = "display_${product}_license_data.html";
$_run_duration = "run_duration.txt";
$_html_file = "web_results\\${product}-${date}.html";
$_history_html_file = "web_results\\${product}_history.html";
$_blank_html_file = "web_results\\${product}_blank.html";
$_selection_html_file = "web_results\\${product}_selection.html";
$_today_html_file = "web_results\\${product}_today.html";
$_yesterday_html_file = "web_results\\${product}_yesterday.html";
$_today_data = "data\\${product}_today_data.txt";
$_historical_data = "data\\${product}_historical_data.txt";
$TRASH_CAN = "NUL";
# FlexLM is called differently depending on OS
$clearlicense = "clearlicense";
$flexlm_cmd = "lmutil lmstat -f ${product} -c -s ${flexlm_port}\@${flexlm_server}";
$flexlm_cmd = "lmutil lmstat -f ${product} -c -s ";
}
else
{
$_front_html = "display_license_data.html";
$_main_html = "display_${product}_license_data.html";
$_run_duration = "run_duration.txt";
$_html_file = "web_results/${product}-${date}.html";
$_history_html_file = "web_results/${product}_history.html";
$_blank_html_file = "web_results/${product}_blank.html";
$_selection_html_file = "web_results/${product}_selection.html";
$_today_html_file = "web_results/${product}_today.html";
$_yesterday_html_file = "web_results/${product}_yesterday.html";
$_today_data = "data/${product}_today_data.txt";
$_historical_data = "data/${product}_historical_data.txt";
$TRASH_CAN = "/dev/null";
# FlexLM is called differently depending on OS
$clearlicense = "/usr/atria/bin/clearlicense";
$flexlm_cmd = "rsh ${flexlm_server} \"/apps/flexlm/solaris/rational/base/cots/flexlm.11.1.1/sun4_solaris2/lmutil lmstat -f ${product} -c -s ${flexlm_server}\"";
$flexlm_cmd = "/apps/flexlm/solaris/rational/base/cots/flexlm.11.1.1/sun4_solaris2/lmutil lmstat -f ${product} -c -s ${flexlm_server}";
#$flexlm_cmd = "/opt/rational/base/cots/flexlm.10.8.0.1/rs6k_aix/lmutil lmstat -f ${product} -c -s ${flexlm_port}\@${flexlm_server}\"";
}
$MAX_USED_TODAY = 0;
$MAX_LIC_FOR_GRAPH = 0;
$LAST_MAX_LIC_GRAPH = 0;
$MAX_LIC = 0;
$MAX_LIC_DENIED = 0;
$LIC_DENIED = 0;
$LAST_MAX = 0;
$LIC_IN_USE = 0;
$OK_TO_BUILD = 0;
$IS_CURRENT = 0;
$PAST_CURRENT = 0;
$USER = "";
$USER_LIST = "";
$USER_LIST_TODAY = "";
%UNIQUE_USERS_TODAY = ();
@_USER_LIST_TODAY = ();
$SORTED_UNIQUE_USERS_TODAY = "";
$max_licenses = 0;
$user = "";
$licenses_used = 0;
$licenses_denied = 0;
$licenses_bumped = 0;
$overage_data = 0;
#################################
# Create history file if needed #
#################################
if (! -e $_historical_data)
{
open (HISTORY_CREATE, ">>$_historical_data") || die "Can't create file ($_historical_data)\n$!\n";
close (HISTORY_CREATE);
}
#######################################################################
# Get ${product} license usage at this moment and store in today_data #
# Store data with key for time period. #
#######################################################################
# if (($product =~ /clearcase/i) || ( $product =~ /multisite/i)){$license_cmd = "$clearlicense -product $product"}
# else {$license_cmd = "$flexlm_cmd"}
$license_cmd = "$flexlm_cmd";
open LICENSES, "$license_cmd |" || die "Can't execute ($license_cmd) \n$!\n";
while ()
{
$data_line = $_;
# Pre FlexLM Version 7.0
if ($data_line =~ /(\d*)\slicenses\savailable/)
{ $max_licenses = $1; }
# Post FlexLM Version 7.0
if ($data_line =~ /Total of (\d+) licenses issued/)
{ $max_licenses = $1; }
elsif ($data_line =~ /Maximum active users allowed: (\d+)/)
{ $max_licenses = $1; }
elsif ($data_line =~ /Current active users: (\d+)/)
{ $licenses_used = $1; }
elsif ($data_line =~ /(\d+) license requests denied/)
{ $licenses_denied = $1; }
elsif ($data_line =~ /(\d+) active users bumped/)
{ $licenses_bumped = $1; }
elsif ($data_line =~ /minutes \(at /)
{
($JUNK, $user, $JUNK) = split (/\s+/, $data_line);
$user_list ="$user,$user_list";
}
# elsif (($data_line =~ /\, start /) && ! (($product =~ /clearcase/i) || ($product =~ /multisite/i)))
elsif ($data_line =~ /\, start /)
{
$data_line =~ s/^\s+//g;
($user, $JUNK) = split (/\ /, $data_line);
$user_list ="$user,$user_list";
$licenses_used++;
}
}
close LICENSES;
if ($licenses_used == 1)
{ $user_list = $user; }
# far as I can tell FlexLM doesn't report bumped or denied
# so these values will always be 0.
if (($product =~ /clearcase/i) || ( $product =~ /multisite/i)){
$overage_data = $licenses_denied + $licenses_bumped ;
}
else {
$overage_data = 0;
$licenses_denied = 0;
$licenses_bumped = 0;
}
#############################
# Append to today data file #
#############################
open (_TODAY_DATA, ">>$_today_data") or die "Can't open file ($_today_data)\n$!\n";
printf _TODAY_DATA "\n$current_key $max_licenses $licenses_used $overage_data $user_list";
close (_TODAY_DATA);
##########################
# Build _today.html file #---------------------------------------------------------------------
##########################
########################################
# Read the current data file for today #
# and store in the expected html file. #
########################################
open (_TODAY_DATA, $_today_data) or die "Can't open file ($_today_data)\n$!\n";
@BUFF = <_TODAY_DATA>;
close (_TODAY_DATA);
$OK_TO_BUILD = ($#BUFF != -1) ? 1:0;
foreach $_data (@BUFF)
{
%UNIQUE_USERS = ();
@_USER_LIST = ();
$user_list = "";
$SORTED_UNIQUE_USERS = "";
chomp($_data);
($TIME_KEY, $MAX_LIC, $LIC_IN_USE, $LIC_DENIED, $USER_LIST) = split (/ /, $_data);
@USERS = split (/\,/, $USER_LIST);
foreach $USER (@USERS)
{
if (! exists ($UNIQUE_USERS{$USER}))
{
$UNIQUE_USERS{$USER} = "using...";
push (@_USER_LIST, $USER);
}
if (! exists ($UNIQUE_USERS_TODAY{$USER}))
{
$UNIQUE_USERS_TODAY{$USER} = "using...";
push (@_USER_LIST_TODAY, $USER);
}
}
$LAST_MAX_LIC_GRAPH = $MAX_LIC; # Last read is used to initailze tomorrow
if ( $MAX_LIC > $MAX_LIC_FOR_GRAPH )
{ $MAX_LIC_FOR_GRAPH = $MAX_LIC; } # Upper bounds for graph
if ( $LIC_DENIED > $MAX_LIC_DENIED )
{ $MAX_LIC_DENIED = $LIC_DENIED; } # upper bounds for excess graph
$MAX_USED_TODAY = ($LIC_IN_USE > $MAX_USED_TODAY) ? $LIC_IN_USE : $MAX_USED_TODAY;
if (exists ($HASHED_DATA{$TIME_KEY}))
{
##########################################
# take the greater of any duplicate data #
# and store just one key. #
##########################################
($ML, $LIU, $LD, $UL) = split (/ /, $HASHED_DATA{$TIME_KEY});
$MAX_LIC = ($MAX_LIC > $ML) ? $MAX_LIC : $ML ;
$LIC_IN_USE = ($LIC_IN_USE > $LIU) ? $LIC_IN_USE : $LIU ;
$LIC_DENIED = ($LIC_DENIED > $LIU) ? $LIC_DENIED : $LD ;
@USERS = split (/\,/, $UL);
foreach $USER (@USERS)
{
if (! exists ($UNIQUE_USERS{$USER}))
{
$UNIQUE_USERS{$USER} = "using...";
push (@_USER_LIST, $USER);
}
}
}
$SORTED_UNIQUE_USERS="";
foreach $USER (sort (@_USER_LIST))
{ $SORTED_UNIQUE_USERS = "$USER,$SORTED_UNIQUE_USERS"; }
if ( "$SORTED_UNIQUE_USERS" ne "" )
{ chop ($SORTED_UNIQUE_USERS); }
$HASHED_DATA{$TIME_KEY} = "$MAX_LIC $LIC_IN_USE $LIC_DENIED $SORTED_UNIQUE_USERS";
}
foreach $USER (sort (@_USER_LIST_TODAY))
{ $SORTED_UNIQUE_USERS_TODAY = "$USER,$SORTED_UNIQUE_USERS_TODAY"; }
if ( "$SORTED_UNIQUE_USERS_TODAY" ne "" )
{ chop ($SORTED_UNIQUE_USERS_TODAY); }
$LAST_MAX = $MAX_LIC; # incase a piece of data is missing then blend the graph
################################################################
# Open the html file to write to and select it for all printfs #
################################################################
open (_TFILE, ">$_html_file") or open (_TFILE, ">>$_html_file") or die "Can't open file ($_html_file)\n$!\n";
select(_TFILE);
printf (" \n");
printf (" \n");
printf ($STAMP);
$BLOCK = <<' BLOCK_1';
\n");
printf (" \n");
printf (" \n");
close (_TFILE);
##########################
# End of today.html file #---------------------------------------------------------------------
##########################
#################################
# start of historical.html file #---------------------------------------------------------------------
#################################
###########################################
# Build the current data file for hsitory #
# and store in the expected html file. #
###########################################
if (-e $_historical_data)
{
###############################
# It exists - open and use it #
###############################
open (_HISTORY_DATA, $_historical_data) or die "Can't open file ($_historical_data)\n$!\n";
@BUFF = <_HISTORY_DATA>;
close (_HISTORY_DATA);
$HISTORY_INIT = 0;
}
else
{
###############################################
# Init the data - file will get created later #
###############################################
$HISTORY_INIT = 1;
@BUFF = ("$MAX_LIC_FOR_GRAPH.0.0");
}
$MAX_DAY_LIC_FOR_HISTORY = 0;
$MAX_USE_LIC_FOR_HISTORY = 0;
$DAYS_READ = 0;
$FIRST_DAY_LIC_HISTORY = 0;
$LIC_DENIED = 0;
$LIC_MAX_DENIED = 0;
$FIRST_SET = "no";
$OK_TO_BUILD = ($#BUFF != -1) ? 1:0;
foreach $_data (@BUFF)
{
chomp($_data);
$DAYS_READ += 1;
($MAX_DAY_LIC, $MAX_DAY_USE, $LIC_DENIED, $USERS_FOR_DAY) = split (/\./, $_data);
if ( $MAX_DAY_LIC > $MAX_DAY_LIC_FOR_HISTORY)
{ $MAX_DAY_LIC_FOR_HISTORY = $MAX_DAY_LIC; }
if ( $MAX_DAY_USE > $MAX_USE_LIC_FOR_HISTORY)
{ $MAX_USE_LIC_FOR_HISTORY = $MAX_DAY_USE; }
if ( $LIC_DENIED > $LIC_MAX_DENIED)
{ $LIC_MAX_DENIED = $LIC_DENIED; }
if ( "$FIRST_SET" eq "no" )
{
$FIRST_DAY_LIC_HISTORY = $MAX_DAY_LIC;
$FIRST_SET = "yes";
}
}
@BUILT_HISTORY = ();
for ($I = 0; ($I < ($DAYS_TO_KEEP - $DAYS_READ)); $I++)
{ push (@BUILT_HISTORY, "$FIRST_DAY_LIC_HISTORY.0.0."); }
foreach $_data (@BUFF)
{ push (@BUILT_HISTORY, $_data); }
################################################################
# Open the html file to write to and select it for all printfs #
################################################################
open (_TFILE, ">$_history_html_file") or open (_TFILE, ">>$_history_html_file") or die "Can't open file ($_history_html_file)\n$!\n";
select(_TFILE);
printf (" \n");
printf (" \n");
printf ($STAMP);
$BLOCK = <<' BLOCK_3';
\n");
printf (" \n");
printf (" \n");
close (_TFILE);
###############################
# End of historical.html file #---------------------------------------------------------------------
###############################
######################################################
# Copy the specific html to the generic html as well #
######################################################
open (TODAY, ">$_today_html_file") || open (TODAY, ">>$_today_html_file") || die "Can't open file ($_today_html_file)\n$!\n";
open (BY_DATE, "<$_html_file") || die "Can't open file ($_html_file)\n$!\n";
########################################################################
# The _today.html version automatically refreshes every UPDATE_SECONDS #
########################################################################
printf TODAY " \n" ;
while ()
{
if ($_ =~ /^${product} License usage/) # (code reference #1)
{ printf TODAY "Dynamic " ; }
printf TODAY $_ ;
}
close (TODAY);
close (BY_DATE);
#############################################
# If at end of day then do more processing #
# .. turn today into yesterday and initial #
# today. #
#############################################
if ("$current_key" eq "$CLOSE_OUT_AFTER")
{
open (YESTERDAY, ">$_yesterday_html_file") || open (YESTERDAY, ">>$_yesterday_html_file") || die "Can't open file ($_yesterday_html_file)\n$!\n";
open (TODAY, "<$_today_html_file") || die "Can't open file ($_today_html_file)\n$!\n";
while ()
{ printf YESTERDAY $_ ; }
close (YESTERDAY);
close (TODAY);
open (TODAY, ">$_today_html_file") || open (TODAY, ">>$_today_html_file") || die "Can't open file ($_today_html_file)\n$!\n";
printf TODAY " \n";
printf TODAY " \n";
printf TODAY $STAMP;
printf TODAY "No data collected yet for today...
\n";
printf TODAY " \n";
printf TODAY " \n";
close (TODAY);
open (TOMORROW, ">$_today_data") || open (TOMORROW, ">>$_today_data") || die "Can't open file ($_today_data)\n$!\n";
printf TOMORROW "x.x $LAST_MAX_LIC_GRAPH 0 0";
close (TOMORROW);
open (HISTORY_READ, "<$_historical_data") || die "Can't open file ($_historical_data)\n$!\n";
@historical_data = ;
close (HISTORY_READ);
$days_in_file = $#historical_data + 1;
if ($days_in_file < $DAYS_TO_KEEP)
{
open (HISTORY_WRITE, ">>$_historical_data") || die "Can't open file ($_historical_data)\n$!\n";
printf HISTORY_WRITE "\n$MAX_LIC_FOR_GRAPH.$MAX_USED_TODAY.$MAX_LIC_DENIED.$SORTED_UNIQUE_USERS_TODAY";
close (HISTORY_WRITE);
}
else
{
open (HISTORY_WRITE, ">$_historical_data") || open (HISTORY_WRITE, ">>$_historical_data") || die "Can't open file ($_historical_data)\n$!\n";
for ($I = ($days_in_file - $DAYS_TO_KEEP + 1); ($I <= $#historical_data); $I++)
{ printf HISTORY_WRITE "$historical_data[$I]"; }
printf HISTORY_WRITE "\n$MAX_LIC_FOR_GRAPH.$MAX_USED_TODAY.$MAX_LIC_DENIED.$SORTED_UNIQUE_USERS_TODAY";
close (HISTORY_WRITE);
}
}
####################################
# Rebuild the selection.html page. #
####################################
open (SELECTION, ">$_selection_html_file") || open (SELECTION, ">>$_selection_html_file") || die "Can't open file ($_selection_html_file)\n$!\n";
select (SELECTION);
printf (" \n");
printf (" \n");
printf ($STAMP);
$BLOCK = <<' BLOCK_5';
\n");
printf ("
\n");
printf ($STAMP);
printf (" \n");
printf (" \n");
close (SELECTION);
chdir ("..");
##########################################
# Rebuild the required _blank.html page. #
##########################################
if ( ! -e $_blank_html_file)
{
open (BLANK, ">>$_blank_html_file") || die "Can't open file ($_blank_html_file)\n$!\n";
select (BLANK);
printf (" \n");
printf (" \n");
printf ($STAMP);
printf (" \n");
printf (" \n");
close (BLANK);
}
##############################################
# Rebuild the required _yesterday.html page. #
##############################################
if ( ! -e $_yesterday_html_file)
{
open (YESTERDAY, ">>$_yesterday_html_file") || die "Can't open file ($_yesterday_html_file)\n$!\n";
select (YESTERDAY);
printf (" \n");
printf (" \n");
printf ("Cannot look at yesterday because $self was not running then. This data will not be available until tomorrow..
\n");
printf ($STAMP);
printf (" \n");
printf (" \n");
close (YESTERDAY);
}
##############################################
# Rebuild the required _yesterday.html page. #
##############################################
if ( ! -e $_main_html)
{
open (MAIN_HTML, ">>$_main_html") || die "Can't open file ($_main_html)\n$!\n";
select (MAIN_HTML);
printf (" \n");
printf ("${product} License Tracker \n");
printf ($STAMP);
printf ("\n");
printf ($STAMP);
printf (" \n");
printf ("