Skip to content

Commit

Permalink
Enhanced a textual listing of instruments.
Browse files Browse the repository at this point in the history
Added a column for recently used staging servers so that
the loaders can easily spot instruments, which write to the
same server.
  • Loading branch information
mgcam committed May 30, 2024
1 parent 718720e commit 9649c4d
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 42 deletions.
2 changes: 2 additions & 0 deletions data/templates/instrument_list_textual.tt2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<th>Current Status</th>
<th>Status Comment</th>
<th>Laboratory</th>
<th>Staging Server</th>
</tr>
</thead>
<tbody>
Expand All @@ -26,6 +27,7 @@
<td>[% instrument.current_instrument_status.instrument_status_dict.description %]</td>
<td>[% instrument.current_instrument_status.comment %]</td>
<td>[% instrument.lab %]</td>
<td>[% instrument.join(', ') %]</td>
</tr>
[% END %]
</tbody>
Expand Down
100 changes: 62 additions & 38 deletions lib/npg/model/instrument.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ package npg::model::instrument;

use strict;
use warnings;
use base qw(npg::model);
use English qw(-no_match_vars);
use File::Spec;
use Carp;
use DateTime;
use DateTime::Duration;
use DateTime::Format::MySQL;
use List::MoreUtils qw(any uniq);
use base qw(npg::model);

use npg::model::user;
use npg::model::run;
use npg::model::instrument_format;
Expand All @@ -15,10 +21,6 @@ use npg::model::instrument_annotation;
use npg::model::annotation;
use npg::model::instrument_designation;
use npg::model::designation;
use DateTime;
use DateTime::Duration;
use DateTime::Format::MySQL;
use List::MoreUtils qw/any/;

our $VERSION = '0';

Expand Down Expand Up @@ -380,6 +382,46 @@ sub latest_annotation {
return $self->{latest_annotation};
}

sub recent_staging_servers {
my $self = shift;

my $run_status = q[run in progress];
my $query = q[SELECT folder_path_glob FROM instrument
JOIN run USING(id_instrument)
JOIN run_status USING(id_run)
JOIN run_status_dict USING(id_run_status_dict)
WHERE folder_path_glob IS NOT NULL
AND LENGTH(folder_path_glob) != 0
AND id_instrument=? AND description=?
ORDER BY date DESC];
my $dbh = $self->util->dbh();
# Four rather than two latest runs since NovaSeq(X) instruments have
# two sides, which write to the same staging server.
my $rows = $dbh->selectall_arrayref($query, {RaiseError => 1, MaxRows => 4},
$self->id_instrument(), $run_status);
my @globs = uniq map { $_->[0] } @{$rows};
# We do not need more that two unique globs.
while (scalar @globs > 2) {
pop @globs
}

my @servers = ();
foreach my $area (@globs) {
my @dirs = File::Spec->splitdir($area);
# Current (May 2024) folder path globs look like
# /{export,nfs}/esa-sv-20201215-03/IL_seq_data/*/
##no critic (ValuesAndExpressions::ProhibitMagicNumbers)
if (@dirs >= 3 and $dirs[0] eq q[]) {
push @servers, $dirs[2];
} else {
push @servers, $area;
}
##use critic
}

return @servers;
}

sub does_sequencing {
my $self = shift;
return ($self->instrument_format->model &&
Expand Down Expand Up @@ -595,9 +637,9 @@ npg::model::instrument
=head1 DESCRIPTION
Clearpress model for an instrument.
To be replaced by DBIx model. Contains duplicates of functions in
npg_tracking::Schema::Result::Instrument. When editing the code
of this module consider if any changes are meeded in the other module.
Contains duplicates of functions in npg_tracking::Schema::Result::Instrument.
When editing the code of this module consider if any changes are needed in
the other module.
=head1 SUBROUTINES/METHODS
Expand All @@ -621,11 +663,6 @@ npg::model::instrument
my $arAllInstruments = $oInstrument->instruments();
=head2 instrument_by_ipaddr - npg::model::instrument by its IP address
my $oInstrument = $oInstrument->instrument_by_ipaddr('127.0.0.1');
instrument_by_instrument_comp
=head2 instrument_by_instrument_comp - npg::model::instrument by its instrument_comp name
=head2 current_instruments - arrayref of all npg::model::instruments with iscurrent=1
Expand All @@ -637,16 +674,6 @@ instrument_by_instrument_comp
my $lab = 'Sulston';
my $arCurrentSulstonInstruments = $oInstrument->current_instruments_from_lab($lab);
=head2 last_wash_instrument_status - npg::model::instrument_status (or undef) corresponding to the last 'wash performed' state
my $oInstrumentStatus = $oInstrument->last_wash_instrument_status();
=head2 check_wash_status - boolean whether this instrument needs washing
Has a side-effect of updating an instrument's current instrument_status to 'wash required'
$bNeedAWash = $oInstrument->check_wash_status();
=head2 runs - arrayref of npg::model::runs for this instrument
my $arRuns = $oInstrument->runs();
Expand Down Expand Up @@ -719,6 +746,9 @@ Has a side-effect of updating an instrument's current instrument_status to 'wash
=head2 fc_slots2blocking_runs - a hash reference mapping instrument flowcell slots to blocking runs; tags for slots are used as keys
=head2 recent_staging_servers - returns a list of names of staging servers
this instrument most recently transferred data to, most recent server first.
=head2 does_sequencing - returns true is the instrument does sequencing, false otherwise
=head2 is_two_slot_instrument - returns true if this instrument has two slots, false otherwise
Expand All @@ -729,7 +759,7 @@ returns true if the instrument is a MiSeq, false otherwise
=head2 is_cbot_instrument - returns true if this instrument is CBot, false otherwise
=head2 current_run_by_id - returns one of current runs with teh argument id or nothing if a list of current runs does not contain a run with this id
=head2 current_run_by_id - returns one of current runs with the argument id or nothing if a list of current runs does not contain a run with this id
my $id_run = 22;
my $run = $oInstrument->current_run_by_id($id_run);
Expand Down Expand Up @@ -761,27 +791,21 @@ returns true if the instrument is a MiSeq, false otherwise
=item base
=item npg::model
=item File::Spec
=item English
=item Carp
=item npg::model::user
=item npg::model::run
=item npg::model::instrument_format
=item npg::model::instrument_status
=item Readonly
=item npg::model::instrument_status_dict
=item DateTime
=item npg::model::instrument_mod
=item DateTime::Duration
=item DateTime
=item DateTime::Format::MySQL
=item Readonly
=item List::MoreUtils
=back
Expand All @@ -793,15 +817,15 @@ returns true if the instrument is a MiSeq, false otherwise
=over
=item Roger Pettett, E<lt>[email protected]E<gt>
=item Roger Pettett
=item Marina Gourtovaia
=back
=head1 LICENSE AND COPYRIGHT
Copyright (C) 2006,2008,2013,2014,2016,2018,2021 Genome Research Ltd.
Copyright (C) 2006,2008,2013,2014,2016,2018,2021,2024 Genome Research Ltd.
This file is part of NPG.
Expand Down
85 changes: 81 additions & 4 deletions t/10-model-instrument.t
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use strict;
use warnings;
use t::util;
use Test::More tests => 141;
use Test::More tests => 142;
use Test::Deep;
use Test::Exception;

Expand Down Expand Up @@ -191,7 +191,6 @@ my $util = t::util->new({ fixtures => 1 });
qq[status changed automatically to "$auto_status"]);
}


{
my $instr = npg::model::instrument->new({
util => $util,
Expand Down Expand Up @@ -312,7 +311,6 @@ lives_ok {$util->fixtures_path(q[t/data/fixtures]); $util->load_fixtures;} 'a fr
ok (!$model->autochange_status_if_needed('analysis in progress'), 'no autochange status');
}


{
my $model = npg::model::instrument->new({util => $util, id_instrument => 36,});
ok($model->is_two_slot_instrument, 'is two_slot instrument');
Expand Down Expand Up @@ -351,7 +349,6 @@ lives_ok {$util->fixtures_path(q[t/data/fixtures]); $util->load_fixtures;} 'a fr
cmp_deeply($model->fc_slots2blocking_runs, {fc_slotA => [], fc_slotB => [],}, 'empty mapping of both slots to blocking runs');
}


{
my $run = npg::model::run->new({util => $util, id_run => 9950,});
$run->id_instrument(36);
Expand Down Expand Up @@ -421,4 +418,84 @@ lives_ok {$util->fixtures_path(q[t/data/fixtures]); $util->load_fixtures;} 'a fr
is (scalar @{$model->instrument_statuses()}, 3, 'number of statuses in total');
}

subtest 'recent staging servers list' => sub {
plan tests => 14;

my $util4updates = t::util->new(); # need a new db handle
lives_ok {$util4updates->load_fixtures;} 'a fresh set of fixtures is loaded';
my $dbh = $util4updates->dbh;
$dbh->{AutoCommit} = 1;
$dbh->{RaiseError} = 1;

my $status = 'run in progress';

my $model = npg::model::instrument->new({
util => $util,
id_instrument => 3,
});
is (join(q[ ], $model->recent_staging_servers()), q[esa-sv-20201215-03],
qq[server name for a single run that is associated with the "$status" status]);

$model = npg::model::instrument->new({
util => $util,
id_instrument => 14,
});
is (scalar $model->recent_staging_servers(), 0,
'empty list since no glob is available for a run that is associated with ' .
qq[the "$status" status]);

$model = npg::model::instrument->new({
util => $util,
id_instrument => 13,
});
is (join(q[,], $model->recent_staging_servers()), 'esa-sv-20201215-02',
'a list with one server name');

my $new_glob = q[{export,nfs}/esa-sv-20201215-02/IL_seq_data/*/];
my $update = qq[update run set folder_path_glob='$new_glob' where id_run=15];
ok($dbh->do($update), 'folder path glob is updated');
$model = npg::model::instrument->new({
util => $util,
id_instrument => 13,
});
is (join(q[,], $model->recent_staging_servers()), $new_glob,
'a full glob is returned');

$new_glob = q[/{export,nfs}];
$update = qq[update run set folder_path_glob='$new_glob' where id_run=15];
ok($dbh->do($update), 'folder path glob is updated');
$model = npg::model::instrument->new({
util => $util,
id_instrument => 13,
});
is (join(q[,], $model->recent_staging_servers()), $new_glob,
'a full glob is returned');

$update = qq[update run set folder_path_glob='' where id_run=15];
ok($dbh->do($update), 'folder path glob is updated');
$model = npg::model::instrument->new({
util => $util,
id_instrument => 13,
});
is (scalar $model->recent_staging_servers(), 0,
'an empty list is returned for a zero length glob');

$update = q[update run_status set id_run_status_dict=2 where ] .
q[id_run in (3,4,5) and id_run_status_dict=4];
ok($dbh->do($update), 'run statuses are updated');
$update = qq[update run set folder_path_glob='server5' where id_run=15];
ok($dbh->do($update), 'folder path glob is updated');
$update = qq[update run set id_instrument=3 where id_run=15];
ok($dbh->do($update), 'assign one more run to the instrument');

$model = npg::model::instrument->new({
util => $util,
id_instrument => 3,
});
is (join(q[, ], $model->recent_staging_servers()), q[server5, /{export,nfs}],
'latest servers list');

$dbh->disconnect;
};

1;
Loading

0 comments on commit 9649c4d

Please sign in to comment.