File Coverage

blib/lib/NBI/Queue.pm
Criterion Covered Total %
statement 21 106 19.8
branch 0 42 0.0
condition 0 13 0.0
subroutine 7 13 53.8
pod 4 4 100.0
total 32 178 17.9


line stmt bran cond sub pod time code
1             #ABSTRACT: NBI::Queue, to filter jobs in the queue
2             #
3             # NBI::Queue - Queries the live SLURM queue and returns a filtered job list.
4             #
5             # DESCRIPTION:
6             # Wraps a call to `squeue` and parses its output into a list of
7             # NBI::QueuedJob objects. Key responsibilities:
8             # - new() : accepts -username, -jobid, -queue, -state, -name filters;
9             # immediately runs squeue and populates $self->{jobs}
10             # - len() : returns the number of matching jobs
11             # - ids() : returns an array (or arrayref) of job IDs
12             # - remove() : removes a job by ID from the in-memory list
13             # Internal helpers:
14             # - _squeue() : builds and runs the squeue command, splits
15             # fields on a custom separator, applies name
16             # filtering, and instantiates NBI::QueuedJob objects
17             # - _make_format_string() : substitutes human-readable field names for
18             # squeue %-format codes using %NBI::Slurm::FORMAT_STRINGS
19             #
20             # RELATIONSHIPS:
21             # - Uses %NBI::Slurm::FORMAT_STRINGS to translate field names to squeue codes.
22             # - Creates NBI::QueuedJob instances for each row returned by squeue.
23             # - $NBI::Queue::VERSION is set from $NBI::Slurm::VERSION.
24             # - Used by the lsjobs and waitjobs bin scripts.
25             #
26 2     2   1438 use strict;
  2         4  
  2         90  
27 2     2   11 use warnings;
  2         4  
  2         159  
28             package NBI::Queue;
29 2     2   14 use Carp qw(croak confess);
  2         4  
  2         207  
30 2     2   18 use NBI::Slurm;
  2         3  
  2         385  
31 2     2   721 use NBI::QueuedJob;
  2         6  
  2         168  
32 2     2   15 use Data::Dumper qw(Dumper);
  2         3  
  2         162  
33             $NBI::Queue::VERSION = $NBI::Slurm::VERSION;
34              
35              
36              
37             # Export QueuedJob
38 2     2   13 use base qw(Exporter);
  2         5  
  2         3635  
39             our @EXPORT = qw(NBI::QueuedJob new);
40             sub new {
41 0     0 1   my $class = shift;
42 0           my $self = bless {}, $class;
43            
44              
45             # -username
46             # -jobid
47 0           my $username;
48             my $jobid;
49 0           my $queue;
50 0           my $state_short;
51 0           my $partitions_csv;
52 0           my $jobname;
53 0 0 0       if (defined $_[0] and substr($_[0], 0, 1) eq '-') {
54 0           my %data = @_;
55 0           for my $i (keys %data) {
56 0 0         if ($i =~ /^-user/) {
    0          
    0          
    0          
    0          
57 0 0         next unless defined $data{$i};
58 0           $username = $data{$i};
59             } elsif ($i =~ /^-jobid/) {
60 0 0         next unless defined $data{$i};
61 0 0         if ($data{$i} =~ /^\d+$/) {
62 0           $jobid = $data{$i};
63             } else {
64 0           confess "ERROR NBI::Queue: -jobid expects an integer\n";
65             }
66             } elsif ($i =~ /^-queue/) {
67 0 0         next unless defined $data{$i};
68 0           $queue = $data{$i};
69             } elsif ($i =~ /^-state/) {
70 0 0         next unless defined $data{$i};
71 0           my @valid_states = qw(PD R CG CF CA CD F TO NF SE ST RV S SO PR NF RV S SO PR);
72 0 0         if (grep {$_ eq uc($data{$i})} @valid_states) {
  0            
73 0           $state_short = uc($data{$i});
74             } else {
75 0           confess "ERROR NBI::Queue: -state expects one of the following values: @valid_states\n";
76             }
77             } elsif ($i =~ /^-name/) {
78 0 0         $jobname = $data{$i} if defined $data{$i};
79             } else {
80 0           confess "ERROR NBI::Queue: Unknown option/parameter $i\n";
81             }
82             }
83             }
84 0           my $jobs = _squeue($username, $jobid, $state_short, $partitions_csv, $jobname);
85 0   0       $self->{username} = $username // undef;
86 0   0       $self->{jobid} = $jobid // undef;
87 0   0       $self->{queue} = $queue // undef;
88 0   0       $self->{state_short} = $state_short // undef;
89 0           $self->{jobs} = $jobs;
90 0   0       $self->{jobname} = $jobname // undef;
91 0           return $self;
92             }
93              
94             sub remove {
95 0     0 1   my $self = shift;
96 0           my $jobid = shift;
97 0           my @jobs = grep {$_->jobid != $jobid} @{$self->{jobs}};
  0            
  0            
98 0           $self->{jobs} = \@jobs;
99             }
100             sub _squeue {
101 0     0     my ($username, $jobid, $state_short, $partitions_csv, $jobname) = @_;
102 0           my $field_sep = ':/:';
103 0           my @field_names = qw(jobid user jobname cpus memory queue status start_time end_time total_time time_left command workdir account reason);
104 0           my $format = join $field_sep, @field_names;
105 0           $format = _make_format_string($format);
106              
107             # Prepare command
108 0           my $cmd = "squeue --format '$format' --noheader ";
109 0 0         $cmd .= " -u $username " if defined $username;
110 0 0         $cmd .= " -j $jobid " if defined $jobid;
111 0 0         $cmd .= " -t $state_short " if defined $state_short;
112 0 0         $cmd .= " -p $partitions_csv " if defined $partitions_csv;
113              
114             # Prepend '-' to @field_names
115 0           @field_names = map { "-$_" } @field_names;
  0            
116              
117 0           my @output = `$cmd 2>/dev/null`;
118 0 0         if ($? != 0) {
119 0           Carp::croak "ERROR NBI::Queue: squeue failed. Are you in a SLURM cluster?\n";
120             }
121 0           my @header;
122 0           my $c = 0;
123 0           my @jobs;
124 0           for my $line (@output) {
125 0           $c++;
126 0           chomp $line;
127            
128 0           my @fields = split /$field_sep/, $line;
129              
130             # Make a hash of @fields_names and @fields
131 0           my %job;
132 0           @job{@field_names} = @fields;
133            
134             ## FILTER FURTHER
135 0 0         if (defined $jobname) {
136 0 0         next unless $job{-"jobname"} =~ /$jobname/;
137             }
138              
139 0           my $submitted_job = NBI::QueuedJob->new(%job);
140              
141            
142              
143 0           push @jobs, $submitted_job;
144             }
145 0           return \@jobs;
146             }
147              
148             sub len {
149 0     0 1   my $self = shift;
150 0           return scalar @{$self->{jobs}};
  0            
151             }
152              
153             sub ids {
154 0     0 1   my $self = shift;
155 0           my @ids = map {$_->jobid} @{$self->{jobs}};
  0            
  0            
156             # If scalar
157 0 0         if (wantarray) {
158 0           return @ids;
159             } else {
160 0           return \@ids;
161             }
162             }
163             sub _make_format_string {
164 0     0     my $string = shift;
165            
166 0           for my $key (keys %NBI::Slurm::FORMAT_STRINGS) {
167 0           my $val = $NBI::Slurm::FORMAT_STRINGS{$key};
168 0           $string =~ s/$key/$val/;
169             }
170              
171 0           return $string;
172             }
173             1;
174              
175             __END__