add flex-grid folder for flexlm license manager accounting

This commit is contained in:
Kasper D. Fischer 2024-08-26 17:54:28 +02:00
parent d26631afd2
commit 81897cf285
17 changed files with 3691 additions and 0 deletions

1
flex-grid/cache Symbolic link
View File

@ -0,0 +1 @@
/rscratch/minos19/flex_grid_cache

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<qlicserverConfig>
<parameters type="overwrite">
<param name="lmutil">/opt/SGE/flex-grid/scripts/abaqus_lmutil</param>
<!-- <param name="LM_LICENSE_FILE">27000@abaqus-lizenz.rz.ruhr-uni-bochum.de</param> -->
<param name="LM_LICENSE_FILE">27000@vmrz0300.vm.ruhr-uni-bochum.de</param>
<param name="dir">/opt/SGE/flex-grid/cache</param>
<param name="output">qlicserver_abaqus.xml</param>
</parameters>
<!--
| Map resource names (complexes) to values (features)
| served by the license manager(s).
| Resources without a "served" attribute are considered internal
| Resources with type "track" are reported but not managed
| The urgency is how much extra weight to give to particular resources.
| If a 'slot' is weighted with 1000, we can give an extra 10% to
| a few resources. [Format: INTEGER]
|
| The resource 'limit' specifies an upper limit to prevent applications
| from flooding the cluster and/or prevent jobs from consuming all the
| available licenses. A negative limit is subtracted from the total
| to obtain the limit. [Format: INTEGER]
|
| Derived resources are combined from sub-elements and inherit the
| limits from their sub-elements.
|
| Resources that are not served and not derived are internal resources
+ -->
<resources type="overwrite">
<resource name="abaqus" served="abaqus" limit="30" type="job"/>
<resource name="cae" served="cae" limit="2" type="job"/>
</resources>
</qlicserverConfig>

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<qlicserverConfig>
<parameters type="overwrite">
<param name="lmutil">/opt/matlab/etc/glnxa64/lmutil</param>
<param name="LM_LICENSE_FILE">/opt/SGE/flex-grid/licenses/comsol.lic</param>
<param name="dir">/opt/SGE/flex-grid/cache</param>
<param name="output">qlicserver_comsol.xml</param>
</parameters>
<!--
| Map resource names (complexes) to values (features)
| served by the license manager(s).
| Resources without a "served" attribute are considered internal
| Resources with type "track" are reported but not managed
| The urgency is how much extra weight to give to particular resources.
| If a 'slot' is weighted with 1000, we can give an extra 10% to
| a few resources. [Format: INTEGER]
|
| The resource 'limit' specifies an upper limit to prevent applications
| from flooding the cluster and/or prevent jobs from consuming all the
| available licenses. A negative limit is subtracted from the total
| to obtain the limit. [Format: INTEGER]
|
| Derived resources are combined from sub-elements and inherit the
| limits from their sub-elements.
|
| Resources that are not served and not derived are internal resources
+ -->
<resources type="overwrite">
<resource name="comsol" served="COMSOL" type="job"/>
</resources>
</qlicserverConfig>

View File

@ -0,0 +1,36 @@
<?xml version="1.0"?>
<qlicserverConfig>
<parameters type="overwrite">
<param name="lmutil">/opt/matlab/etc/glnxa64/lmutil</param>
<param name="LM_LICENSE_FILE">/opt/SGE/flex-grid/licenses/multiphysics.lic</param>
<param name="dir">/opt/SGE/flex-grid/cache</param>
<param name="output">qlicserver_local.xml</param>
<param name="qhost">qhost.xml</param>
<param name="qstat">qstat.xml</param>
</parameters>
<!--
| Map resource names (complexes) to values (features)
| served by the license manager(s).
| Resources without a "served" attribute are considered internal
| Resources with type "track" are reported but not managed
| The urgency is how much extra weight to give to particular resources.
| If a 'slot' is weighted with 1000, we can give an extra 10% to
| a few resources. [Format: INTEGER]
|
| The resource 'limit' specifies an upper limit to prevent applications
| from flooding the cluster and/or prevent jobs from consuming all the
| available licenses. A negative limit is subtracted from the total
| to obtain the limit. [Format: INTEGER]
|
| Derived resources are combined from sub-elements and inherit the
| limits from their sub-elements.
|
| Resources that are not served and not derived are internal resources
resource name="hyper" served="GridWorks" type="job"
<resource name="matlab" served="MATLAB" type="job" limit="-2"/>
<resource name="signal_toolbox" served="Signal_Toolbox" type="job" limit="-2"/>
+ -->
<resources type="overwrite">
<resource name="femlab" served="COMSOL" type="track"/>
</resources>
</qlicserverConfig>

View File

@ -0,0 +1,32 @@
<?xml version="1.0"?>
<qlicserverConfig>
<parameters type="overwrite">
<param name="lmutil">/opt/matlab/etc/glnxa64/lmutil</param>
<param name="LM_LICENSE_FILE">/opt/SGE/flex-grid/licenses/matlab.lic</param>
<param name="dir">/opt/SGE/flex-grid/cache</param>
<param name="output">qlicserver_matlab.xml</param>
</parameters>
<!--
| Map resource names (complexes) to values (features)
| served by the license manager(s).
| Resources without a "served" attribute are considered internal
| Resources with type "track" are reported but not managed
| The urgency is how much extra weight to give to particular resources.
| If a 'slot' is weighted with 1000, we can give an extra 10% to
| a few resources. [Format: INTEGER]
|
| The resource 'limit' specifies an upper limit to prevent applications
| from flooding the cluster and/or prevent jobs from consuming all the
| available licenses. A negative limit is subtracted from the total
| to obtain the limit. [Format: INTEGER]
|
| Derived resources are combined from sub-elements and inherit the
| limits from their sub-elements.
|
| Resources that are not served and not derived are internal resources
+ -->
<resources type="overwrite">
<resource name="matlab" served="MATLAB" type="job" limit="100"/>
<resource name="mcc" served="Compiler" type="job" limit="100"/>
</resources>
</qlicserverConfig>

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<qlicserverConfig>
<parameters type="overwrite">
<param name="lmutil">/opt/matlab/etc/glnxa64/lmutil</param>
<param name="LM_LICENSE_FILE">/opt/SGE/flex-grid/licenses/matlab.lic</param>
<param name="dir">/opt/SGE/flex-grid/cache</param>
<param name="output">qlicserver_trelis.xml</param>
</parameters>
<!--
| Map resource names (complexes) to values (features)
| served by the license manager(s).
| Resources without a "served" attribute are considered internal
| Resources with type "track" are reported but not managed
| The urgency is how much extra weight to give to particular resources.
| If a 'slot' is weighted with 1000, we can give an extra 10% to
| a few resources. [Format: INTEGER]
|
| The resource 'limit' specifies an upper limit to prevent applications
| from flooding the cluster and/or prevent jobs from consuming all the
| available licenses. A negative limit is subtracted from the total
| to obtain the limit. [Format: INTEGER]
|
| Derived resources are combined from sub-elements and inherit the
| limits from their sub-elements.
|
| Resources that are not served and not derived are internal resources
+ -->
<resources type="overwrite">
<resource name="trelis" served="TRELIS" type="job"/>
</resources>
</qlicserverConfig>

View File

@ -0,0 +1 @@
/opt/comsol53a/multiphysics/license/license.dat

View File

@ -0,0 +1,2 @@
SERVER kamikaze 80b660b0 7788
USE_SERVER

2
flex-grid/licenses/ifort.lic Executable file
View File

@ -0,0 +1,2 @@
SERVER kamikaze 80b660b0 28518
USE_SERVER

View File

@ -0,0 +1 @@
/opt/matlab/licenses/01network.lic

View File

@ -0,0 +1,2 @@
SERVER phaidra.geophysik.ruhr-uni-bochum.de 00163ef90680 1718
USE_SERVER

View File

@ -0,0 +1,221 @@
#!/bin/sh
#
# Snapshot of the current GridEngine configuration using git for the
# backend storage and tracking mechanism.
#
# Should normally be called via a cronjob.
#
# Following Edward Dale's idea:
# http://scompt.com/blog/archives/2009/10/13/versioned-grid-engine-configuration
# but using git for the backend
#
# initialize:
#
# git --git-dir=$GIT_DIR init --bare --shared=world
#
# Note: we use Perl for inplace editing since some versions of sed have
# problems with this task.
################################################################################
################################################################################
# CUSTOMIZE THESE SETTINGS TO MATCH YOUR REQUIREMENTS:
SGE_ROOT=/opt/grid
SGE_CELL=default
GIT_DIR=/data/cfd/share/git-repo/gridengine-config.git
#
# END OF CUSTOMIZE SETTINGS
################################################################################
################################################################################
Script=${0##.*/}
saveScript="$SGE_ROOT/util/upgrade_modules/save_sge_config.sh"
export SGE_ROOT SGE_CELL GIT_DIR
for i in git perl
do
type $i >/dev/null 2>&1 || {
echo "Error: $Script - no '$i' found"
exit 1
}
done
#------------------------------------------------------------------------------
usage() {
while [ "$#" -ge 1 ]; do echo "$1"; shift; done
cat<<USAGE
usage: ${0##*/} [OPTION | GIT_COMMAND]
options:
-help display this usage
init initialize git repo in $GIT_DIR
pass-through git commands:
log ls-files
show whatchanged
Snapshot of the current GridEngine configuration using git for the
backend storage and tracking mechanism.
* git repository stored here:
$GIT_DIR
copyright (c) 2009-10 <Mark.Olesen@faurecia.com>
USAGE
exit 1
}
#------------------------------------------------------------------------------
# parse options
while [ "$#" -gt 0 ]
do
case "$1" in
( help | -h | -help )
usage
;;
( init )
shift
if [ -d "$GIT_DIR" ]
then
echo "Error: $Script - $GIT_DIR already exists"
exit 1
else
git --git-dir=$GIT_DIR init --bare --shared=world $@
rc=$?
# add a description for gitweb
i="$GIT_DIR/description"
if [ -f "$i" -a -w "$i" ]
then
echo "snapshot of the current GridEngine configuration" > $i
fi
fi
exit $rc
;;
( log | ls-files | show | whatchanged )
git --git-dir=$GIT_DIR $@
exit $?
;;
(*)
usage "unknown option/argument: '$*'"
;;
esac
done
[ -d "$GIT_DIR" ] || {
echo "git repo: $GIT_DIR does not exist"
exit 1
}
i="$SGE_ROOT/$SGE_CELL/common/settings.sh"
if [ -f "$i" -a -r "$i" ]
then
. "$i"
else
echo "cannot read $i"
exit 1
fi
[ -f "$saveScript" -a -r "$saveScript" ] || {
echo "cannot read $i"
exit 1
}
# Create a fresh empty directory
# cannot use --tmpdir on older systems
tmpDir=$(mktemp -d "/tmp/sgeSaveConfig.XXXXXXXXXX")
trap "rm -rf $tmpDir 2>/dev/null; exit 0" EXIT TERM INT
[ -d "$tmpDir" ] || {
echo "Error: temp dir '$tmpDir' does not exist"
exit 1
}
$saveScript $tmpDir
#------------------------------------------------------------------------------
# cleanup
#
(
cd $tmpDir || exit 1
# all operations are now in the current directory
GIT_WORK_TREE=.
export GIT_WORK_TREE
# minor error checking that the save script worked
if [ -f backup_date -a -r backup_date ]
then
msg=$(cat backup_date)
else
echo "cannot read backup_date - $saveScript might have failed"
exit 1
fi
# ignore accounting (too big)
rm -f cell/accounting
# ignore current users
rm -f users/*
# ignore current load_values for exec hosts
perl -i -ne '/^load_values/ or print' execution/*
# assign (consumable) complex_values to zero - otherwise we indirectly
# track the external license usage when qlicserver is being used
# also sort the complexes to avoid spurious changes
perl -i -p -e 'if (/^complex_values/) { chomp; ' \
-e 's/=\d+/=0/g; s/^(complex\S+\s+)//; ' \
-e '$_ = $1 . join("," => sort split /,/) . "\n" }' \
execution/global
#
# determine if the configuration changed
#
# this is fairly roundabout until we find a better way
needsCommit=false
if [ -n "$(git ls-files -d)" ] # files deleted?
then
needsCommit=true
elif [ -n "$(git ls-files -o)" ] # files added?
then
needsCommit=true
else
# files modified?
# do it the long way to ensure we also get staged modifications
set -- $(git status | perl -ne 's/^#\s+modified:// and print')
# changes in backup_date, jobseqnum etc alone are not enough
# to warrant a commit
while [ "$#" -ge 1 ]
do
case $1 in
( arseqnum | backup_date | jobseqnum )
shift
;;
(*)
needsCommit=true
break
;;
esac
done
fi
if [ "$needsCommit" = true ]
then
# register all new files
git add .
# commit everything
git commit -a -m "$msg"
else
echo "no changes to be committed $msg"
fi
)
exit 0
#------------------------------------------------------------------------------

View File

@ -0,0 +1,5 @@
#!/bin/sh
# $Id: abaqus_lmutil 180 2010-09-17 15:46:41Z kasper $
/opt/abaqus/Commands/abaqus licensing lmstat -a -f abaqus -S ABAQUSLM
/opt/abaqus/Commands/abaqus licensing lmstat -a -f cae -S ABAQUSLM

View File

@ -0,0 +1,124 @@
#!/usr/bin/perl -w
use strict;
use Getopt::Std qw( getopts );
use Time::Local qw( timelocal );
my ($releaseDate) = qw( 2009-10-02 );
( my $Script = $0 ) =~ s{^.*/}{};
# -------------------------------------------------------------------------
sub usage {
$! = 0; # clean exit
warn "@_\n" if @_;
die <<"USAGE";
usage:
$Script [OPTION] file1 [ .. fileN ]
with options:
-b YYYY[-MM[-DD]]
begin date for accounting (job end_time > DATE 2 A.M.)
-e YYYY[-MM[-DD]]
end date for accounting (job end_time <= DATE 2 A.M.)
-h usage
Extract portions of the GridEngine accounting(5) file according to the
job end_time. For example,
$Script -b 2008-01-01 -e 2009 ...
extracts the accounting for jobs that finished running in 2008.
The value of 2 A.M. avoids problems that daylight savings time might
otherwise cause.
version ($releaseDate)
copyright (c) 2009 <Mark.Olesen\@faurecia.com>
Licensed and distributed under the Creative Commons
Attribution-NonCommercial-ShareAlike 3.0 License.
http://creativecommons.org/licenses/by-nc-sa/3.0
USAGE
}
# -------------------------------------------------------------------------
my %opt;
getopts( "hb:e:", \%opt ) or usage();
usage() if $opt{h};
@ARGV or usage();
for (@ARGV) {
-f $_ or die "no file '$_'\n";
## handle compressed files transparently
if (/\.bz2$/) {
$_ = qq{bzip2 -dc "$_"|};
}
elsif (/\.gz$/) {
$_ = qq{gzip -dc "$_"|};
}
}
for (qw( b e )) {
if ( $opt{$_} ||= 0 ) {
my ( $yy, $mm, $dd );
if ( $opt{$_} =~ /^(\d{2,4})-(\d{1,2})-(\d{1,2})$/ ) {
## YYYY-MM-DD
( $yy, $mm, $dd ) = ( $1, $2, $3 );
}
elsif ( $opt{$_} =~ /^(\d{2,4})-(\d{1,2})$/ ) {
## YYYY-MM
( $yy, $mm ) = ( $1, $2 );
}
elsif ( $opt{$_} =~ /^(\d{2,4})$/ ) {
## YYYY
($yy) = ($1);
}
else {
usage("invalid date format: '$opt{$_}'");
}
# treat missing month/day as '1'
$mm ||= 1;
$dd ||= 1;
# convert from YYYY-MM-DD to epoch,
# start at 2am - avoid problems with daylight savings time
$opt{$_} = timelocal( 0, 0, 2, $dd, $mm - 1, $yy ); # month (0..11)
}
}
$opt{b} or $opt{e} or usage("must specify at least one of -b or -e");
if ( $opt{e} and $opt{b} >= $opt{e} ) {
usage("-b DATE must less than -e DATE");
}
my $fileCount;
while (<>) {
if (/^\s*#/) {
## pass-thru comments, but only for the first file
print unless $fileCount;
next;
}
my ($endtime) = ( split /:/ )[10];
# only allow things that ran (endtime non-zero)
# and that are within the filter limits
if ( $endtime
and ( $opt{b} ? ( $endtime > $opt{b} ) : 'okay' )
and ( $opt{e} ? ( $endtime <= $opt{e} ) : 'okay' ) )
{
print;
}
}
continue {
$fileCount++ if eof;
}
__END__
FORMAT - see accounting(5)
08 submission_time
09 start_time
10 end_time

517
flex-grid/scripts/qlic Executable file
View File

@ -0,0 +1,517 @@
#!/usr/bin/perl -w
use strict;
use Getopt::Std qw( getopts );
use POSIX qw( );
( my $Script = $0 ) =~ s{^.*/}{};
my $time = time;
my $date = POSIX::strftime( "%F %T", localtime $time );
$ENV{SGE_ROOT} or die "Error $Script: \$SGE_ROOT is not set\n";
$ENV{SGE_CELL} ||= "default"; # sge_cell
my ($siteLocation) = join "/" => ( $ENV{SGE_ROOT}, $ENV{SGE_CELL}, "site" );
my $config = {
-site => ( $siteLocation || '' ),
-cache => ( $siteLocation || '' ) . "/cache/" . "qlicserver.xml",
-limits => ( $siteLocation || '' ) . "/" . "qlicserver.limits",
};
# ------------------------------------------------------------------------
# utils
#
# calculate age from an epoch value
#
sub age {
my ( $a, $b ) = @_;
my $diff = ( $a - $b );
my $sign = '';
if ( $diff < 0 ) { # handle negatives
$sign = '-';
$diff = abs($diff);
}
sprintf "$sign%d:%02d:%02d", # format into hh:mm:ss
( int $diff / 3_600 ), # hh
( ( int $diff / 60 ) % 60 ), # mm
( $diff % 60 ); # ss
}
#
# change hash references to a comma-delimited string of key=value entries
#
sub hashRefToString {
map {
my $ref = $_;
ref $ref ? map { "$_=$ref->{$_}" } sort keys %$ref : ()
} @_;
}
#
# extract attrib="value" ... attrib="value"
#
sub parseXMLattrib {
my $str = shift || '';
my %attr;
while ($str =~ s{^\s*(\w+)=\"([^\"]*)\"}{}s
or $str =~ s{^\s*(\w+)=\'([^\']*)\'}{}s )
{
$attr{$1} = $2;
}
%attr;
}
# ------------------------------------------------------------------------
# processing of qlicserver.xml output
#
package qlicCache;
sub new {
my $caller = shift;
my $file = shift;
my $self = bless {
( map { $_ => {} } qw( -rc ) ),
( map { $_ => '' } qw( -date -host -age ) )
}, $caller;
-f $file or return $self;
local $_ = do { local ( @ARGV, $/ ) = $file; <>; };
# strip out all xml comments
s{<!--.*?-->\s*}{}sg;
# get the header section
s{^(.+?)</query>}{}s or return;
my $header = $1;
for ($header) {
if (m{<host (?:\s+([^<>]*))? > \s*(.+?)\s* </host>}sx) {
my ( $attr, $content ) = ( $1, $2 );
$self->{-host} = $content;
}
if (m{<time (?:\s+([^<>]*))? > \s*(.+?)\s* </time>}sx) {
my ( $attr, $content ) = ( $1, $2 );
my %attr = main::parseXMLattrib($attr);
$self->{-age} = main::age( $time, $attr{epoch} ) if $attr{epoch};
$self->{-date} = $content;
}
}
# only retain the <resources> contents
s{^.*?<resources>}{}s and s{</resources>.*$}{}s or return;
## process <resource .../>
while (s{<resource (?:\s+([^/<>]*))? />}{}sx) {
my ($attr) = ($1);
my %attr = main::parseXMLattrib($attr);
my $name = delete $attr{name};
if ( defined $name ) {
for ( keys %attr ) {
$self->{-rc}{$name}{$_} = $attr{$_} || 0;
}
}
}
## process <resource ...> CONTENT </resource>
while (s{<resource (?:\s+([^<>]*))? > \s* (.*?) \s* </resource>}{}sx) {
my ( $attr, $content ) = ( $1, $2 );
my %attr = main::parseXMLattrib($attr);
my $name = delete $attr{name};
if ( defined $name ) {
for ( keys %attr ) {
$self->{-rc}{$name}{$_} = $attr{$_} || 0;
}
}
## process <user ...> COUNT </user>
while ( $content =~ s{<user (?:\s+([^<>]*))? >\s*(\d+)\s*</user>}{}sx )
{
my ( $attr, $count ) = ( $1, $2 );
my %attr = main::parseXMLattrib($attr);
my $user = delete $attr{name};
my $host = delete $attr{host};
if ( defined $user ) {
if ( defined $host ) {
$self->{-rc}{$name}{-where}{"$user\@$host"} = $count;
}
else {
## tag waiting with '[]'
$self->{-rc}{$name}{-where}{$user} = "[$count]";
}
}
}
}
return $self;
}
sub query {
my $self = shift;
%{ $self->{-rc} };
}
sub dump {
use Data::Dumper;
print Dumper( $_[0] );
}
sub available {
my $self = shift;
sort keys %{ $self->{-rc} };
}
# ------------------------------------------------------------------------
# processing of qlicserver.limits FILE or DIRECTORY
#
package qlicLimits;
sub new {
my $caller = shift;
my $diskValues = shift;
my $self = bless {}, $caller;
my $fileString;
if ( defined $diskValues and -f $diskValues ) {
$fileString = do {
local ( *FILE, $/ );
if ( open FILE, $diskValues ) {
<FILE>;
}
else {
undef;
}
};
}
elsif ( defined $diskValues and -d $diskValues ) {
local *DIR;
my $dir = $diskValues;
if ( opendir DIR, $dir ) {
my @files = grep { -f "$dir/$_" and -r _ } readdir DIR;
for my $name (@files) {
my $limit;
# use the last value
if ( open FILE, "$dir/$name" ) {
$limit = ( map { /^\s*(-?\d+)\s*$/ } <FILE> )[-1];
}
defined $limit or $limit = "NONE";
$self->{$name} = $limit;
}
}
}
for ($fileString) {
defined or next;
# strip out all comments
s{<!--.*?-->\s*}{}sg;
## process <resource .../> and <resource ...></resource>
while (s{<resource (?:\s+([^/<>]*))? />}{}sx
or s{<resource (?:\s+([^/<>]*))? >\s*</resource>}{}sx )
{
my %attr = main::parseXMLattrib($1);
my $name = delete $attr{name};
my $limit = delete $attr{limit};
if ( defined $name and defined $limit ) {
$self->{$name} = $limit;
}
}
}
return $self;
}
sub change {
my $caller = shift;
my $diskValues = shift;
my @args = @_;
@args or return;
my ( %pending, %adjusted );
for (@args) {
s{,}{ }g; # comma -> space-delimited
my %h = map { /^(.+?)=(.*)$/ } split;
for ( keys %h ) {
defined $h{$_} and length $h{$_} or $h{$_} = "NONE";
$pending{$_} = $h{$_};
}
}
keys %pending or return;
my $user = getpwuid $<;
if ( defined $diskValues and -d $diskValues ) {
local *DIR;
my $dir = $diskValues;
if ( opendir DIR, $dir ) {
my @files = grep { -f "$dir/$_" and -w _ } readdir DIR;
for my $name (@files) {
if ( exists $pending{$name} ) {
local *FILE;
if ( open FILE, ">", "$dir/$name" ) {
print FILE "# adjusted by $user $date\n",
"$pending{$name}\n";
$adjusted{$name} = delete $pending{$name};
}
}
}
}
}
for ( [ "adjusted" => \%adjusted ], [ "not adjusted" => \%pending ], ) {
my ( $label, $href ) = @$_;
keys %$href or next;
print "$label: ",
join( "," => map { qq{$_=$href->{$_}} } sort keys %$href ), "\n";
}
}
sub output {
my $self = shift;
my @list = map { qq{$_=$self->{$_}} } sort keys %$self;
print "limits: ";
if (@list) {
print join( "," => @list ), "\n";
}
else {
print "NONE\n";
}
}
# ------------------------------------------------------------------------
# main
#
package main;
import qlicCache;
# ------------------------------------------------------------------------
sub usage {
$! = 0; # clean exit
warn "@_\n" if @_;
die <<"USAGE";
usage:
$Script [OPTION]
$Script [OPTION] resource=limit .. resource=limit
with options:
-c FILE alternative location for the license cache
-C FILE alternative location for the license limit
-d dump cache file as raw xml
-D dump license cache in perl format
-f display free licenses only
-l list license limit
-q display free licenses via qhost query
-u license usage via 'lacct'
-U license usage per user via 'lacct -u'
-w show who/where ('[]' indicates waiting jobs)
-h this help
* extract / display information for the GridEngine license cache
$config->{-cache}
* adjust / display information for the license limits
$config->{-limits}
copyright (c) 2003-10 <Mark.Olesen\@faurecia.com>
Licensed and distributed under the Creative Commons
Attribution-NonCommercial-ShareAlike 3.0 License.
http://creativecommons.org/licenses/by-nc-sa/3.0
USAGE
}
# -------------------------------------------------------------------------
my %opt;
getopts( 'hc:C:DdflqUuw', \%opt ) or usage();
$opt{h} and usage();
if ( $opt{U} ) {
## user-based usage from accounting
my @query = ( "lacct", "-u" );
exec @query;
exit 2;
}
elsif ( $opt{u} ) {
## usage from accounting
my @query = ( "lacct", $opt{w} ? "-w" : () );
exec @query;
exit 2;
}
if ( $opt{d} ) {
my $file = $opt{c} || $config->{-cache};
if ( not -f $file and $file !~ m{/} ) {
$file = "$config->{-site}/$file";
}
-f $file or exit 1;
local $_ = do { local ( @ARGV, $/ ) = $file; <>; };
# do a basic check for well-formed xml
# this might not be the case if there is a race condition
# and the file has not been fully written
# check for '<?xml version="1.0"?><someTag ...' at the start
# and '</someTag>' at the end
my ($tag) = m{^<\?xml (?:\s+[^<>]*?)? \?>\s*\<(\w+)}sx;
unless ( $tag and m{</\Q$tag\E>\s*$} ) {
sleep 2; ## wait and try again
$_ = do { local ( @ARGV, $/ ) = $file; <>; };
}
$_ ||= ''; ## avoid uninitialized
print;
exit;
}
if ( $opt{q} ) {
my %free =
map { /^\s+gc:(\S+?)=(\d\S*)\s*$/ }
grep { /^global/ ... /^\S/ } qx{qhost -F};
$_ += 0 for values %free;
for ( sort keys %free ) {
my $intval = $free{$_} + 0; # normalize as integers
print "$_=$intval\n";
}
exit;
}
if ( $opt{l} ) {
qlicLimits->new( $opt{C} || $config->{-limits} )->output();
exit;
}
if (@ARGV) {
qlicLimits->change( $opt{C} || $config->{-limits}, @ARGV );
exit;
}
my $info = qlicCache->new( $opt{c} || $config->{-cache} );
$info->dump() if $opt{D};
my %resources = $info->query();
#
# display free licenses
#
if ( $opt{f} ) {
for my $resource ( sort keys %resources ) {
my $count = $resources{$resource} || {};
my $free = $count->{free} || 0;
print "$resource=$free\n" if $free;
}
exit;
}
#
# display who/where
#
if ( $opt{w} ) {
my ($len) = sort { $b <=> $a } map { length } keys %resources;
$len += 2;
my $fmt = "%-${len}s";
my $indent = sprintf "\n$fmt", '';
for my $resource ( sort keys %resources ) {
my $count = $resources{$resource} || {};
my @list = hashRefToString( $count->{-where} );
if (@list) {
printf $fmt, $resource;
print join( $indent => @list ), "\n";
}
}
exit;
}
#
# define table output format
#
my @outputList;
format =
# name total limit extern intern wait free
@<<<<<<<<<<< @>>>>> @>>>>> @>>>>> @>>>>> @>>>> @>>>>
@outputList
.
#
# display table header
# --------------------
{
my @info = qw( host age );
my ($len) = sort { $b <=> $a } map { length } @info;
print map {
my $k = sprintf "%-${len}s", $_;
my $v = $info->{"-$_"};
$v ? "$k = $v\n" : ();
} @info;
print "\n";
@outputList = qw( resource total limit extern intern wait free );
write;
s/./-/g for @outputList;
write;
}
#
# display table body
# ------------------
for my $resource ( sort keys %resources ) {
my $count = $resources{$resource} || {};
@outputList =
( $resource, @{$count}{qw( total limit extern intern waiting free )} );
my $type = $resources{$resource}{type} || 0;
# no total?
$_ ||= "?" for $outputList[1];
if ( $type eq "intern" ) {
$_ = "*" for $outputList[3];
}
elsif ( $type eq "track" ) {
$_ = "*" for $outputList[4];
}
# easy to read representation for zero
for (@outputList) {
defined $_ or $_ = '.';
}
write;
}
# ------------------------------------------------------------------------

2327
flex-grid/site/qlicserver Executable file

File diff suppressed because it is too large Load Diff

325
flex-grid/site/qloadsensor Executable file
View File

@ -0,0 +1,325 @@
#!/bin/bash
# $Id: qloadsensor 180 2010-09-17 15:46:41Z kasper $
#
# qloadsensor:
# load sensor for particular file systems and floating licenses
#
# NB:
# 1) add the new complexes (via qconf -mc) for the following:
# * complex configurations managed in the shell script
# eg, 'perl -x qloadsensor'
# * complex consumables managed global
# eg, 'qlicserver -c'
# 2) initialize the global complex consumables to be managed
# eg, 'qlicserver -C'
#
# copyright (c) 2003-10 <Mark.Olesen@faurecia.com>
#
# Licensed and distributed under the Creative Commons
# Attribution-NonCommercial-ShareAlike 3.0 License.
# http://creativecommons.org/licenses/by-nc-sa/3.0
# -----------------------------------------------------------------------------
#
# impose default GridEngine environment + ascertain the binary architecture
#
# you likely don't need to adjust these values, since the loadsensor is called
# from sge_execd, which in turn is started from /etc/init.d/n1ge and
# these variables should be correctly exported there
#
[ -d "$SGE_ROOT" ] || { echo "Error: SGE_ROOT=$SGE_ROOT not found"; exit 1; }
: ${SGE_CELL:=default}
: ${SGE_ARCH:=`$SGE_ROOT/util/arch`}
export SGE_ROOT SGE_CELL SGE_ARCH
# -----------------------------------------------------------------------------
# this script should run as the 'admin_user' registered in 'bootstrap'
#
if [ "$UID" -eq 0 ]
then
admin_user=$(sed -ne 's/^admin_user *//p' $SGE_ROOT/$SGE_CELL/common/bootstrap)
: ${admin_user:=root}
if [ $admin_user != root -a $(echo $admin_user | tr "A-Z" "a-z") != none ]
then
exec $SGE_ROOT/utilbin/$SGE_ARCH/adminrun $admin_user $0
fi
fi
# <settings>
# ========================================================================
# now that we are the admin_user, we can source our standard settings
# - customize *all* settings there (eg, license server settings)
# - ENSURE THAT '$SGE_site' IS DEFINED !!!
#
for i in $SGE_ROOT/$SGE_CELL/site/environ; do [ -f $i ] && . $i; done
# define (unique) cluster name if not already defined
if [ -z "$SGE_CLUSTER_NAME" -a -r "$SGE_ROOT/$SGE_CELL/common/cluster_name" ]
then
SGE_CLUSTER_NAME=$(cat $SGE_ROOT/$SGE_CELL/common/cluster_name 2>/dev/null)
fi
: ${SGE_CLUSTER_NAME:=default}
export SGE_CLUSTER_NAME
SGE_site="$SGE_ROOT/flex-grid/site"
#
# ========================================================================
# </settings>
###############################################################################
###############################################################################
# CUSTOMIZE THESE SETTINGS - iff. required
qlicserver="$SGE_site/qlicserver config=$SGE_site/../config/local_licenses.conf dir=$SGE_ROOT/flex-grid/cache output=$SGE_ROOT/flex-grid/cache/qlicserver.xml qhost=qhost.xml qstat=qstat.xml"
diskmon="$SGE_site/diskmon.pl"
# END OF CUSTOMIZE SETTINGS
###############################################################################
###############################################################################
#
# the real (not compiled in) architecture
#
os_arch=`$SGE_ROOT/util/arch`
SGE_utilbin=$SGE_ROOT/utilbin/$os_arch
#
# set some constants
#
HOST=$($SGE_utilbin/gethostname -aname)
UQHOST=$(echo $HOST | cut -f1 -d.)
SGE_qmaster=unknown; export SGE_qmaster
# -----------------------------------------------------------------------------
# act_qmaster
#
# extract the unqualified host name from the "act_qmaster" file
# return this value or 'unknown' on failure
#
act_qmaster()
{
tmp=$(cat $SGE_common/act_qmaster 2>/dev/null)
echo ${tmp:-unknown}
}
# -----------------------------------------------------------------------------
# df_info
#
# echo the $1_{total,used,free} space on filesystem $2
#
# gridengine uses the suffixes
# 'k' => blocksize 1000
# 'K' => blocksize 1024
#
# return 0 if 'df' fails
df_info()
{
# 1:tag 2:mount 3:filesys 4:total 5:Used 6:Avail 7:Used% 8:Mount
[ -d "$2" ] && set -- $1 $2 $( df -k -P $2 2>/dev/null | tail -1 )
#!# we could add the following check:
#!# [ "$2" != "$8" ] && set -- $1 $2; # mount point mismatch?
[ "$#" -ge 6 ] || set -- $1 $2 filesystem 0 0 0
echo "$UQHOST:$1_total:$4K"
echo "$UQHOST:$1_used:$5K"
#if [ -w "$2" ]
#then
echo "$UQHOST:$1_free:$6K"
#else
# echo "$UQHOST:$1_free:0"
#fi
}
# invariant values
if [ -e "/proc/cpuinfo" ]
then
# mips=$(awk '{if (/mips/) printf "%.0f\n", $NF}' /proc/cpuinfo | tail -1)
mips=$(awk 'BEGIN {mips=0} /mips/ {if ($NF > mips) mips=$NF }; END {print mips}' /proc/cpuinfo)
else
mips=0
fi
unset os_name
# extract lsb_release
if [ -e "/usr/bin/lsb_release" ]
then
os_name=$(/usr/bin/lsb_release -ircs | xargs echo | sed 's/ /_/g')
else
os_name='unkown'
fi
: ${os_name:=NONE}
# -----------------------------------------------------------------------------
# host_info
#
# report host specific information about filesystems, logins,
# special hardware extensions, etc.
#
host_info()
{
echo "$UQHOST:arch:$os_arch"
echo "$UQHOST:os:$os_name"
# df_info tmp /tmp
df_info scratch /scratch
echo "$UQHOST:mips:$mips"
}
# -----------------------------------------------------------------------------
# iidle_info()
# report a machine's idle time
#
# parse the contents from /proc/interrupts, which looks like the following:
#
# CPU0
# 0: 23024789 XT-PIC timer
# 1: 13 XT-PIC keyboard
# 2: 0 XT-PIC cascade
# 5: 0 XT-PIC usb-uhci
# 8: 2 XT-PIC rtc
# 9: 0 XT-PIC acpi
# 10: 0 XT-PIC ehci-hcd, usb-uhci
# 11: 16687253 XT-PIC eth0, usb-uhci, Intel 82801DB-ICH4, nvidia
# 12: 20 XT-PIC PS/2 Mouse
# 14: 77178 XT-PIC ide0
# 15: 2 XT-PIC ide1
# NMI: 0
# LOC: 0
# ERR: 0
# MIS: 0
#
# or,
#
# CPU0 CPU1
# 0: 12820049 12818168 IO-APIC-edge timer
# 1: 42889 43309 IO-APIC-edge keyboard
# 2: 0 0 XT-PIC cascade
# 8: 2 0 IO-APIC-edge rtc
# 9: 0 0 IO-APIC-edge acpi
# 12: 287235 296531 IO-APIC-edge PS/2 Mouse
# 14: 47423 40923 IO-APIC-edge ide0
# 15: 2 3 IO-APIC-edge ide1
# 16: 7733868 7737081 IO-APIC-level nvidia
# 17: 159 156 IO-APIC-level Intel ICH 82801AA
# 19: 2155710 2159943 IO-APIC-level e100, usb-uhci
# NMI: 0 0
# LOC: 25641034 25641033
# ERR: 0
# MIS: 0
#
# Thus, we need the [-1, 1..$ncpu] fields for the following sources:
# keyboard, Mouse, serial
#
# NB: adding 'usb-uhci' gives problems, since this is sometimes
# attached to the ethernet card
#
# set the variable 'iidle' to the idle time (seconds) since the last call
#
last="0 -1";
iidle_info()
{
set -- $(
perl -e '
my @last = @ARGV;
@ARGV = "/proc/interrupts";
$_ = <>;
my $ncpu = s/\s*CPU\d+//g || 0;
my ( $iidle, $int, $now ) = ( 0, 0, time );
$int += $_
for
map { /\s+(keyboard|Mouse|serial)$/ ? (split)[ 1 .. $ncpu ] : (); }
<>;
if ( $int == $last[-1] ) { # no interactivity since last round
$iidle = ( $now - $last[0] );
}
else {
@last = ( $now, $int );
}
print "$iidle @last\n";
' $last
);
echo "$UQHOST:iidle:$1";
shift; last="$@"; # save for later
}
# -----------------------------------------------------------------------------
#
# The execd running on the qmaster queries the license server
# The contents of 'act_qmaster' should suffice to migrate the load sensor
# for a controlled migration.
#
while :
do
read input || exit 1 # wait for input
[ "$input" = quit ] && exit 0
echo begin # begin load report
host_info # host information
iidle_info # machine's idle time
echo end # end load report
# let the license query run between load reports
# SGE_qmaster=`act_qmaster` # refresh the name of the qmaster
# if [ "$HOST" = "$SGE_qmaster" ]
if [ "$HOST" = "minos19" ]
then
# $qlicserver 2>> qloadsensor.err
$SGE_ROOT/flex-grid/site/qlicserver config=$SGE_ROOT/flex-grid/config/local_licenses.conf output=$SGE_ROOT/flex-grid/cache/qlicserver_local.xml
$SGE_ROOT/flex-grid/site/qlicserver config=$SGE_ROOT/flex-grid/config/abaqus_licenses.conf timeout=60 output=$SGE_ROOT/flex-grid/cache/qlicserver_abaqus.xml
# $SGE_ROOT/flex-grid/site/qlicserver config=/opt/SGE/flex-grid/config/trelis_licenses.conf timeout=60 output=$SGE_ROOT/flex-grid/cache/qlicserver_trelis.xml
$SGE_ROOT/flex-grid/site/qlicserver config=/opt/SGE/flex-grid/config/comsol_licenses.conf timeout=60 output=$SGE_ROOT/flex-grid/cache/qlicserver_comsol.xml
$SGE_ROOT/flex-grid/site/qlicserver config=$SGE_ROOT/flex-grid/config/matlab_licenses.conf timeout=60 output=$SGE_ROOT/flex-grid/cache/qlicserver_matlab.xml
lockfile $SGE_ROOT/flex-grid/cache/qlicserver.xml.lock
# (sed '/<\/resources>/,$ d' $SGE_ROOT/flex-grid/cache/qlicserver_abaqus.xml ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_trelis.xml | grep -v qlicserver | grep -v resources ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_local.xml | grep -v qlicserver | grep -v resources ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_matlab.xml;) > $SGE_ROOT/flex-grid/cache/qlicserver.xml
# (sed '/<\/resources>/,$ d' $SGE_ROOT/flex-grid/cache/qlicserver_abaqus.xml ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_local.xml | grep -v qlicserver | grep -v resources ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_matlab.xml;) > $SGE_ROOT/flex-grid/cache/qlicserver.xml
(sed '/<\/resources>/,$ d' $SGE_ROOT/flex-grid/cache/qlicserver_abaqus.xml ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_local.xml | grep -v qlicserver | grep -v resources; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_comsol.xml | grep -v qlicserver | grep -v resources ; sed '1,/<resources>/d' $SGE_ROOT/flex-grid/cache/qlicserver_matlab.xml;) > $SGE_ROOT/flex-grid/cache/qlicserver.xml
rm -f $SGE_ROOT/flex-grid/cache/qlicserver.xml.lock
# $diskmon -m 2>> qloadsensor.err
# force rescheduling of express jobs
# $SGE_site/qxprs >/dev/null 2>&1
# else
# $diskmon 2>> qloadsensor.err
fi
done
exit 0 # we never get here, but just in case
#------------------------------------------------------------------------------
# feed via 'perl -x' to extract the 'host' complex configuration
#!/usr/bin/perl -w
print <DATA>
__DATA__
#
# host complex configuration
#
#name shortcut type relop requestable consumable default urgency
#---------------------------------------------------------------------------
tmp_total tmpt MEMORY <= YES NO 0 0
tmp_used tmpu MEMORY >= NO NO 0 0
tmp_free tmpf MEMORY <= YES NO 0 0
iidle iidle INT <= YES NO 0 0
mips mips INT <= YES NO 0 0
os os RESTRING == YES NO NONE 0
abaqus abaqus DOUBLE <= YES YES 0 0
cae cae DOUBLE <= YES YES 0 0
comsol comsol DOUBLE <= YES YES 0 0
hyper hyper DOUBLE <= YES YES 0 0
ifort ifort DOUBLE <= YES YES 0 0
matlab matlab DOUBLE <= YES YES 0 0
mcc mcc DOUBLE <= YES YES 0 0
multiphysics multiphysics DOUBLE <= YES YES 0 0
trelis trelis DOUBLE <= YES YES 0 0
scratch_free scratch_free MEMORY <= YES YES 0 0
scratch_total scratch_total MEMORY <= YES NO 0 0
scratch_used scratch_used MEMORY >= NO NO 0 0
# -----------------------------------------------------------------------------