9
my $basedir = dirname($0);
10
chdir $basedir or die "$basedir: $!";
13
my $pkgdatadir = $basedir;
15
chdir $oldcwd or die "$oldcwd: $!";
17
unshift @INC, $pkgdatadir;
21
use LogUtils ( 'start_logging', 'error', 'warning', 'debug' );
22
use LRMS ('select_lrms', 'cluster_info');
23
use Shared ( 'print_ldif_data', 'post_process_config', 'diskspaces');
28
# Constructs clusterldif for NorduGrid ARC Information System
31
my ($totaltime) = time;
33
####################################################################
34
# Full definitions of the infosys attributes are documented in
35
# "The NorduGrid/ARC Information System", 2005-05-09.
36
####################################################################
38
####################################################################
39
# The "output" or interface towards ARC Information system is
40
# defined by elements in @cen array. The interface towards LRMS is
42
####################################################################
46
'nordugrid-cluster-name',
47
'nordugrid-cluster-aliasname',
48
'nordugrid-cluster-comment',
49
'nordugrid-cluster-owner',
50
'nordugrid-cluster-acl',
51
'nordugrid-cluster-location',
52
'nordugrid-cluster-issuerca',
53
'nordugrid-cluster-issuerca-hash',
54
'nordugrid-cluster-trustedca',
55
'nordugrid-cluster-contactstring',
56
'nordugrid-cluster-interactive-contactstring',
57
'nordugrid-cluster-support',
58
'nordugrid-cluster-lrms-type',
59
'nordugrid-cluster-lrms-version',
60
'nordugrid-cluster-lrms-config',
61
'nordugrid-cluster-architecture',
62
'nordugrid-cluster-opsys',
63
'nordugrid-cluster-benchmark',
64
'nordugrid-cluster-homogeneity',
65
'nordugrid-cluster-nodecpu',
66
'nordugrid-cluster-nodememory',
67
'nordugrid-cluster-nodeaccess',
68
'nordugrid-cluster-totalcpus',
69
'nordugrid-cluster-usedcpus',
70
'nordugrid-cluster-cpudistribution',
71
'nordugrid-cluster-prelrmsqueued',
72
'nordugrid-cluster-totaljobs',
73
'nordugrid-cluster-localse',
74
'nordugrid-cluster-sessiondir-free',
75
'nordugrid-cluster-sessiondir-total',
76
'nordugrid-cluster-sessiondir-lifetime',
77
'nordugrid-cluster-cache-free',
78
'nordugrid-cluster-cache-total',
79
'nordugrid-cluster-middleware',
80
'nordugrid-cluster-runtimeenvironment',
81
'nordugrid-cluster-credentialexpirationtime',
85
########################################################
87
########################################################
89
my (%config, %gm_info, @runtimeenvironment );
91
########################################################
93
########################################################
96
$config{loglevel} = 1;
97
$config{homogeneity} = "TRUE";
98
$config{defaultttl} = "604800";
99
$config{"x509_user_cert"} = "/etc/grid-security/hostcert.pem";
100
$config{"x509_cert_dir"} = "/etc/grid-security/certificates/";
101
$config{arc_location} = $ENV{ARC_LOCATION} ||= "@prefix@";
102
$config{gridmap} = "/etc/grid-security/grid-mapfile";
104
########################################################
105
# Parse command line options
106
########################################################
109
GetOptions("dn:s" => \$config{dn},
110
"valid-to:i" => \$config{ttl},
111
"config:s" => \$config{conf_file},
112
"loglevel:i" => \$config{loglevel},
113
"help|h" => \$print_help
119
mandatory arguments: --dn
122
optional arguments: --valid-to
130
if (! ( $config{dn} and $config{conf_file} ) ) {
131
error("a command line argument is missing, see --help ");
134
##################################################
135
# Read ARC configuration
136
##################################################
138
# Whole content of the config file
140
my $parser = SubstitutingConfigParser->new($config{conf_file}) or die "Cannot parse config file at '$config{conf_file}'\n";
142
# copy blocks that are relevant to %config
144
%config = ( %config, $parser->get_section('common') );
145
%config = ( %config, $parser->get_section('grid-manager') );
146
my %gconf = $parser->get_section('gridftpd');
147
%config = ( %config, %gconf );
148
$config{gm_port} = $gconf{port} || 2811;
149
my %gjconf = $parser->get_section('gridftpd/jobs');
150
$config{gm_mount_point} = $gjconf{path} || "/jobs";
151
$config{remotegmdirs} = $gjconf{remotegmdirs} if $gjconf{remotegmdirs};
152
%config = ( %config, $parser->get_section('cluster') );
154
if (! exists $config{hostname}){
155
chomp ($config{hostname} = `/bin/hostname -f`);
159
my @users = $parser->list_subsections('grid-manager');
160
$gmusers{$_} = { $parser->get_section("grid-manager/$_") } for @users;
162
post_process_config(\%config);
164
############################################################
166
start_logging($config{loglevel});
168
############################################################
170
############################################################
171
# Lot's of stuff that just need to be figured out
172
# Scripting, scripting, scripting, oh hay, oh hay...
173
############################################################
176
my ($globus_location) ||= $ENV{GLOBUS_LOCATION} ||= "/usr";
177
$ENV{LD_LIBRARY_PATH}.=":" if $ENV{LD_LIBRARY_PATH};
178
$ENV{LD_LIBRARY_PATH}.="$config{arc_location}/@libsubdir@:$globus_location/lib";
181
#my ($hostname) = `/bin/hostname -f`;
183
my ($hostname) = $config{hostname};
184
# Hostcert issuer CA, trustedca, issuercahash
186
my $openssl_command = '';
187
for my $path (split ':', "$ENV{PATH}:$globus_location/bin") {
188
$openssl_command = "$path/openssl" and last if -x "$path/openssl";
190
error("Could not find openssl command") unless $openssl_command;
193
my $certfile = shift;
195
# assuming here that the file exists and is a well-formed certificate.
196
chomp (my $stdout=`$openssl_command x509 -noout -enddate -in $certfile`);
198
my %mon = (Jan=>1,Feb=>2,Mar=>3,Apr=>4,May=>5,Jun=>6,Jul=>7,Aug=>8,Sep=>9,Oct=>10,Nov=>11,Dec=>12);
199
if ($stdout =~ m/notAfter=(\w{3}) ?(\d\d?) (\d\d):(\d\d):(\d\d) (\d{4}) GMT/ and $mon{$1}) {
200
return sprintf "%4d%02d%02d%02d%02d%02dZ",$6,$mon{$1},$2,$3,$4,$5;
202
warning("Unexpected -enddate from openssl for $certfile");
207
my $issuerca=`$openssl_command x509 -noout -issuer -in $config{x509_user_cert} 2>/dev/null`;
209
error("error in executing $openssl_command x509 -noout -issuer -in $config{x509_user_cert}");}
210
$issuerca =~ s/issuer= //;
212
my $hostcertenddate = enddate($config{x509_user_cert});
217
# List certs and elliminate duplication in case 2 soft links point to the same file.
218
opendir(CERTDIR, $config{x509_cert_dir}) || error("failed listing certificates directory $config{x509_cert_dir}: $!");
220
for (readdir CERTDIR) {
221
next unless m/\.\d$/;
222
my $file = $config{x509_cert_dir}."/".$_;
223
my $link = -l $file ? readlink $file : $_;
224
$certfiles{$link} = $file;
227
foreach my $cert ( sort values %certfiles ) {
228
my $ca_sn = `$openssl_command x509 -checkend 60 -noout -subject -in $cert`;
229
$ca_sn =~ s/subject= //;
231
if ( $ca_sn eq $issuerca) {
232
$issuerca_hash = `$openssl_command x509 -noout -hash -in $cert`;
233
chomp ($issuerca_hash);
234
$cacertenddate = enddate($cert);
237
$config{loglevel} and warning("CA $ca_sn is expired");
240
$trustedca{$ca_sn} = 1;
243
# the earliest of hostcert and cacert enddates.
245
if ($cacertenddate and $hostcertenddate) {
246
$credenddate = ($hostcertenddate lt $cacertenddate) ? $hostcertenddate : $cacertenddate;
249
###############################################################
250
# Information from Grid Manager via the gm-jobs command
251
###############################################################
253
#read the gm-jobs information about the number of jobs in different gm states
255
my (%controldirs, %sessiondirs);
256
$controldirs{$_} = 1 for map {$_->{controldir}} values %gmusers;
258
# only interested in shared session disks
260
$sessiondirs{$_} = 1 for map { my ($path, $drain) = split /\s+/, $_; $path; }
261
split /\[separator\]/, $gmusers{'.'}{sessiondir};
264
if ($config{remotegmdirs}) {
265
my @remotedirs = split /\[separator\]/, $config{remotegmdirs};
266
for my $dir (@remotedirs) {
267
my ($ctrl, @sessions) = split ' ', $dir;
268
$controldirs{$ctrl} = 1;
269
$sessiondirs{$_} = 1 for grep { $_ ne 'drain' } @sessions;
272
error("No control directories configured") unless %controldirs;
274
#nordugrid-cluster-sessiondirusage
275
my %session_stats = diskspaces(keys %sessiondirs);
276
my $session_disktotal = $session_stats{totalsum};
277
my $session_diskfree = $session_stats{freesum};
278
warning("Cannot determine sessiondir disk space") if $session_disktotal == 0;
280
#nordugrid-cluster-cacheusage
284
# only report central cache and not private caches
285
if (my $centralcfg = $gmusers{'.'}) {
286
if (my $dirs = $centralcfg->{cachedir}) {
287
my @pairs = split /\[separator\]/, $dirs;
288
$cachedirs{$_} = 1 for map { my @p = split ' ',$_; $p[0]; } @pairs;
291
if (my $dirs = $centralcfg->{remotecachedir}) {
292
my @pairs = split /\[separator\]/, $dirs;
293
$cachedirs{$_} = 1 for map { my @p = split ' ',$_; $p[0]; } @pairs;
297
my %cache_stats = diskspaces(keys %cachedirs);
299
my $cache_disktotal = $cache_stats{totalsum};
300
warning("Cannot determine cache disk space") if $cache_stats{errors};
302
# Set total free cache to a value proportional to the least free space among
303
# all cache disks. A value of 0 or close to 0 might mean that something is
304
# misconfigured or there was a malfunction (disk not nounted, cache cleaning
306
my $cache_free_min = $no_cache ? 0 : $cache_stats{freemin};
307
my $cache_diskfree = $cache_stats{freesum};
309
#NorduGrid middleware
310
my ($ngversion) = '@VERSION@';
312
#Globus Toolkit version
313
#globuslocation/share/doc/VERSION
314
my $globusversion = undef;
315
if (-r "$globus_location/share/doc/VERSION" ) {
316
if ( ! open(GVERSION,"<$globus_location/share/doc/VERSION")) {
317
warning ("$!: error in reading the globus version file");
320
# The first line is presume to contain the version as a text string
321
$globusversion = <GVERSION>;
322
chomp($globusversion);
327
#globuslocation/bin/globus-version, try if the previous has failed
328
if (!defined($globusversion) and -x "$globus_location/bin/globus-version" ) {
329
chomp ( $globusversion = `$globus_location/bin/globus-version 2>/dev/null`);
330
if ($?) { warning ("error in executing the $globus_location/bin/globus-version command")}
333
#nordugrid-cluster-runtimeenvironment
334
if ($config{runtimedir}){
335
if (opendir DIR, $config{runtimedir}) {
336
@runtimeenvironment = `find $config{runtimedir} -type f ! -name ".*" ! -name "*~"` ;
338
foreach my $listentry (@runtimeenvironment) {
340
$listentry=~s/$config{runtimedir}\/*//;
344
warning("Can't access $config{runtimedir}");
348
for my $controldir (keys %controldirs) {
350
my $conf_file = $config{conf_file};
351
unless (open GMJOBSOUTPUT,
352
"$config{arc_location}/@pkglibexecsubdir@/gm-jobs -c $conf_file -d $controldir 2>/dev/null |") {
353
error("Error in executing gm-jobs")
356
while (my $line= <GMJOBSOUTPUT>) {
357
if ($line =~ /^Job:/) {next};
358
($line =~ /Jobs total: (\d+)/) and $gm_info{"totaljobs"}+=$1;
359
($line =~ /ACCEPTED: (\d+)/) and $gm_info{"accepted"}+=$1;
360
($line =~ /PREPARING: (\d+)/) and $gm_info{"preparing"}+=$1;
361
($line =~ /SUBMIT: (\d+)/) and $gm_info{"submit"}+=$1;
362
($line =~ /INLRMS: (\d+)/) and $gm_info{"inlrms"}+=$1;
363
($line =~ /FINISHING: (\d+)/) and $gm_info{"finishing"}+=$1;
364
($line =~ /FINISHED: (\d+)/) and $gm_info{"finished"}+=$1;
365
($line =~ /DELETED: (\d+)/) and $gm_info{"deleted"}+=$1;
366
($line =~ /CANCELING: (\d+)/) and $gm_info{"canceling"}+=$1;
370
my $status = $? >> 8;
371
error("$config{arc_location}/@pkglibexecsubdir@/gm-jobs returned with non-zero exit status $status")
375
##################################################
377
##################################################
378
select_lrms(\%config);
379
###########################################
380
# Ask LRMS to fill %lrms_cluster
381
###########################################
383
my (%lrms_cluster) = cluster_info( \%config );
384
debug("LRMS_cluster info retrieved");
385
################################################################
386
# arc.conf config-file data overrides the values given by LRMS
387
################################################################
389
if ($config{totalcpus}) {
390
$lrms_cluster{totalcpus} = $config{totalcpus}}
391
if ($config{cpudistribution}) {
392
$lrms_cluster{cpudistribution} = $config{cpudistribution}}
394
#######################################
396
#######################################
398
# Constract the ldif data (hash of arrays)
400
$c{'dn'} = [ "$config{dn}" ];
401
$c{'objectClass'} = [ 'Mds', 'nordugrid-cluster' ];
402
$c{'nordugrid-cluster-name'} = [ "$hostname" ];
403
$c{'nordugrid-cluster-aliasname'} = [ "$config{cluster_alias}" ];
404
if ( defined $config{comment} ) {
405
$c{'nordugrid-cluster-comment'} = [ "$config{comment}" ];
407
$c{'nordugrid-cluster-owner'} =
408
[ split /\[separator\]/, $config{cluster_owner} ];
409
my @cluster_acl = split /\[separator\]/, $config{authorizedvo};
410
foreach my $listentry (@cluster_acl) {
411
push @{$c{'nordugrid-cluster-acl'}}, "VO:$listentry";
413
$c{'nordugrid-cluster-location'} = [ $config{cluster_location} ];
414
$c{'nordugrid-cluster-issuerca'} = [ "$issuerca" ];
415
$c{'nordugrid-cluster-issuerca-hash'} = [ "$issuerca_hash" ];
416
$c{'nordugrid-cluster-credentialexpirationtime'} = [ "$credenddate" ] if $credenddate;
417
foreach my $listentry (sort keys %trustedca) {
418
push @{$c{'nordugrid-cluster-trustedca'}}, $listentry;
420
$c{'nordugrid-cluster-contactstring'} =
421
["gsiftp://$hostname:$config{gm_port}$config{gm_mount_point}"];
422
if ($config{interactive_contactstring}) {
423
$c{'nordugrid-cluster-interactive-contactstring'} =
424
[ split /\[separator\]/, $config{interactive_contactstring} ];
426
$c{'nordugrid-cluster-interactive-contactstring'} = [ "" ];
428
$c{'nordugrid-cluster-support'} =
429
[ split /\[separator\]/, $config{clustersupport} ];
430
$c{'nordugrid-cluster-lrms-type'} = [ "$lrms_cluster{lrms_type}" ];
431
$c{'nordugrid-cluster-lrms-version'} = [ "$lrms_cluster{lrms_version}" ];
432
$c{'nordugrid-cluster-lrms-config'} = [ "$config{lrmsconfig}" ];
433
if ( defined $config{architecture} ) {
434
$c{'nordugrid-cluster-architecture'} = [ "$config{architecture}" ];
436
$c{'nordugrid-cluster-opsys'} = [ split /\[separator\]/, $config{opsys} ];
438
$c{'nordugrid-cluster-benchmark'} = [];
439
if ( defined $config{benchmark} ) {
440
foreach my $listentry (split /\[separator\]/, $config{benchmark}) {
441
my ($bench_name,$bench_value) = split(/\s+/, $listentry);
442
push @{$c{'nordugrid-cluster-benchmark'}}, "$bench_name \@ $bench_value";}
444
$c{'nordugrid-cluster-homogeneity'} = [ "$config{homogeneity}" ];
445
$c{'nordugrid-cluster-nodecpu'} = [ "$config{nodecpu}" ];
446
$c{'nordugrid-cluster-nodememory'} = [ "$config{nodememory}" ];
447
$c{'nordugrid-cluster-nodeaccess'} =
448
[ split /\[separator\]/, $config{nodeaccess} ];
450
$c{'nordugrid-cluster-totalcpus'} = [ "$lrms_cluster{totalcpus}" ];
451
$c{'nordugrid-cluster-usedcpus'} = [ "$lrms_cluster{usedcpus}" ];
452
$c{'nordugrid-cluster-cpudistribution'} =
453
[ "$lrms_cluster{cpudistribution}" ];
454
$c{'nordugrid-cluster-prelrmsqueued'} =
455
[ ($gm_info{accepted} + $gm_info{preparing} + $gm_info{submit}) ];
456
$c{'nordugrid-cluster-totaljobs'} =
457
[ ($gm_info{totaljobs} - $gm_info{finishing} - $gm_info{finished} - $gm_info{deleted}
458
+ $lrms_cluster{queuedjobs} + $lrms_cluster{runningjobs} - $gm_info{inlrms}) ];
460
if ($config{localse}) {
461
$c{'nordugrid-cluster-localse'} =
462
[ split /\[separator\]/, $config{localse} ];
464
$c{'nordugrid-cluster-localse'} = [ "" ];
466
$c{'nordugrid-cluster-sessiondir-free'} = [ "$session_diskfree" ];
467
$c{'nordugrid-cluster-sessiondir-total'} =
468
[ "$session_disktotal" ];
469
$config{defaultttl} =~ /(\d+)/;
470
$c{'nordugrid-cluster-sessiondir-lifetime'} = [ int $1/60 ];
472
$c{'nordugrid-cluster-cache-free'} = [ "$cache_diskfree" ];
473
$c{'nordugrid-cluster-cache-total'} = [ "$cache_disktotal" ];
475
if ( defined $ngversion ) {
476
push @{$c{'nordugrid-cluster-middleware'}}, "nordugrid-arc-$ngversion";
479
if ( $globusversion ) {
480
push @{$c{'nordugrid-cluster-middleware'}}, "globus-$globusversion";
483
@{$c{'nordugrid-cluster-runtimeenvironment'}} =
486
if ( defined $config{middleware} ) {
487
foreach my $listentry (split /\[separator\]/, $config{middleware}) {
488
next if ($ngversion and ($listentry =~ /nordugrid/i));
489
push @{$c{'nordugrid-cluster-middleware'}}, $listentry;
493
my ( $valid_from, $valid_to ) =
494
Shared::mds_valid($config{ttl});
495
$c{'Mds-validfrom'} = [ "$valid_from" ];
496
$c{'Mds-validto'} = [ "$valid_to" ];
498
###################################################
500
###################################################
502
print_ldif_data(\@cen,\%c);
506
$totaltime = time - $totaltime;
507
debug("TOTALTIME in cluster.pl: $totaltime");