1#! /usr/bin/perl
2#
3
4#
5# sjobexitmod
6#
7# Author:        Phil Eckert
8# Date:          10/28/2010
9# Last Modified: 10/28/2010
10#
11
12BEGIN {
13    # Just dump the man page in *roff format and exit if --roff specified.
14    foreach my $arg (@ARGV) {
15	if ($arg eq "--") {
16	    last;
17	} elsif ($arg eq "--roff") {
18	    use Pod::Man;
19	    my $parser = Pod::Man->new (section => 1);
20	    $parser->parse_from_file($0, \*STDOUT);
21	    exit 0;
22	}
23    }
24}
25
26use strict;
27use Getopt::Long 2.24 qw(:config no_ignore_case);
28use autouse 'Pod::Usage' => qw(pod2usage);
29use File::Basename;
30
31my (
32	$base,   $help,   $cluster,   $code,   $execute_line,
33	$jobid,  $list,   $man,       $reason
34);
35
36#
37# Format for listing job.
38#
39my $list_format = "JobID,Account,NNodes,NodeList,State,ExitCode,DerivedExitCode,Comment";
40
41
42#
43# Get options.
44#
45getoptions();
46
47my $rval;
48
49#
50# Exexute the utility.
51#
52$rval = `$execute_line 2>&1`;
53
54#
55# Determine if Successful.
56#
57my $status = $?;
58
59if ($status == 0) {
60	printf("\n Modification of job $jobid was successful.\n\n");
61	exit(0);
62} else {
63	printf("\n $rval\n");
64	exit($status);
65}
66
67
68
69sub getoptions
70{
71	my $argct = $#ARGV;
72
73#
74#	Set default partition name.
75#
76
77	GetOptions(
78		'help|h|?'   => \$help,
79		'man'        => \$man,
80		'e=s'        => \$code,
81		'r=s'        => \$reason,
82		'c=s'        => \$cluster,
83		'l'          => \$list,
84	) or usage();
85
86#
87#	Fix the exit code (if set) to reflect the
88#	fact that it represents the leftmost 8 bits
89#	of the integer field.
90#
91	$code = 256  * ($code & 0xFF) if ($code);
92
93#
94#
95#	Display a simple help package.
96#
97	usage() if ($help);
98
99	show_man() if ($man);
100
101#
102#       Make sure there is a  job id, and make  sure it is numeric.
103#
104	if (!($jobid = shift(@ARGV)) || !isnumber($jobid)) {
105		printf("\n Job Id needed.\n\n");
106		usage();
107	}
108
109#
110#	List option was selected.
111#
112	if ($list) {
113		die(" \n  wrong use of list option, format is ' $base -l JobId'\n\n") if ($argct != 1);
114		system(" sacct -X -j $jobid -o $list_format");
115		exit(0);
116	}
117
118#
119#	Check for required options.
120#
121	if (!$reason && !$code) {
122		printf("\n Either reason string or exit code required.\n\n");
123		exit(1);
124	}
125
126#
127#	Build execute line from the options that are set.
128#
129	$execute_line = "sacctmgr -i modify job jobid=$jobid set";
130
131	$execute_line .= " Comment=\"$reason\""        if ($reason);
132	$execute_line .= " DerivedExitCode=$code"      if ($code);
133	$execute_line .= " Cluster=$cluster"           if ($cluster);
134
135	return;
136}
137
138
139#
140# Simple check to see if number is an integer,
141# retrun 0 if it is not, else return 1.
142#
143sub isnumber
144{
145	my ($var) = $_;
146
147	if ($var !~ /\D+/) {
148		return(1); #if it is just a number.
149	} else {
150		return(0); #if it is not just a number.
151	}
152}
153
154
155sub usage
156{
157	my $base = basename($0);
158
159	printf("\
160 Usage: $base [-e <exit code>] [-r <reason string>] [-c <cluster>] JobId
161        $base -l JobId
162        $base [-h]
163        $base [-man]
164
165	-e <exit code>		Modify the derived exit code to new value.
166	-r <reason string>	Modify the job's comment field to new value.
167	-c <cluster>		Name of cluster (optional).
168	-l 			List information for a completed job.
169	-h 			Show usage.
170	JobId			The identification number of the job.
171	-man 			Show man page.
172
173\n");
174
175	exit;
176}
177
178sub show_man
179{
180
181	if ($< == 0) {    # Cannot invoke perldoc as root
182		my $id = eval { getpwnam("nobody") };
183		$id = eval { getpwnam("nouser") } unless defined $id;
184		$id = -2                          unless defined $id;
185		$<  = $id;
186		printf("\n You can not do this as root!\n\n");
187		exit 1;
188	}
189	$> = $<;                         # Disengage setuid
190	$ENV{PATH} = "/bin:/usr/bin";    # Untaint PATH
191	delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
192	if ($0 =~ /^([-\/\w\.]+)$/) { $0 = $1; }    # Untaint $0
193	else { die "Illegal characters were found in \$0 ($0)\n"; }
194	pod2usage(-exitstatus => 0, -verbose => 2);
195
196	return;
197}
198
199__END__
200
201
202=head1 NAME
203
204B<sjobexitmod> - Modifies a completed job in the slurmdbd
205
206=head1 SYNOPSIS
207
208       sjobexitmod	[-e exit_code] [-r reason_string] [-c cluster_name] JobId
209       sjobexitmod	-l JobId
210       sjobexitmod	-h
211       sjobexitmod	-man
212
213=head1 DESCRIPTION
214
215 sjobexitmod is a wrapper which effectively does the same operation as using the
216 sacct utility to modify certain aspects of a completed job.
217
218	sacctmgr -i modify job jobid=1286 set DerivedExitCode=1 Comment="code error"
219
220 or to list certain aspects of a completed job.
221
222	sacct -o jobid,derivedexitcode,comment,cluster
223
224=head1 OPTIONS
225
226=over 4
227
228=item B<-h>
229
230A usage summary message is displayed, and sjobexitmod terminates.
231
232=item B<-man>
233
234Show the man page for this utility..
235
236=item B<-c> I<cluster_name>
237
238The name of the cluster the job ran on.
239
240=item B<-e> I<exit_code>
241
242The exit code (DerivedExitCode) to be used.
243
244=item B<-l> I<JobID>
245
246List selected attributes of a completed job.
247
248=item B<-r> I<reason_string>
249
250The reason (Comment) for job termination.
251
252=item B<JobId>
253
254the numeric job id.
255
256=back
257
258=head1 EXIT CONDITIONS
259
260If there is an error, sjobexitmod returns either the  exit status returned by sacctmgr,
261or a non-zero value.
262
263=head1 AUTHOR
264
265Written by Philip D. Eckert
266
267=head1 REPORTING BUGS
268
269Report bugs to <pdesr@llnl.gov>
270
271=head1 SEE ALSO
272
273sacctmgr,sacct
274
275