2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

Merge pull request #7796 from VersatusHPC/fix/rinv-pending-uefi-build-id

fix(rinv): report pending UEFI build ID separately
This commit is contained in:
Daniel Hilst
2026-08-31 11:20:11 -03:00
committed by GitHub
4 changed files with 248 additions and 7 deletions
@@ -152,7 +152,9 @@ Calling \ **rinv**\ for VMware will display the UUID/GUID, number of CPUs, amou
\ **firm**\
Retrieves firmware versions.
Retrieves firmware versions. For IBM and Lenovo System x systems managed through
IMM, ``UEFI Version`` reports the active firmware. If the IMM reports a pending
UEFI build ID, \ **rinv**\ reports it separately as ``Pending UEFI Build ID``.
+3 -1
View File
@@ -95,7 +95,9 @@ Retrieves serial number.
=item B<firm>
Retrieves firmware versions.
Retrieves firmware versions. For IBM and Lenovo System x systems managed through
IMM, C<UEFI Version> reports the active firmware. If the IMM reports a pending
UEFI build ID, B<rinv> reports it separately as C<Pending UEFI Build ID>.
=item B<deconfig>
+8 -5
View File
@@ -3439,13 +3439,16 @@ sub got_bios_date {
my $fru = FRU->new();
$fru->rec_type("bios,uefi,firmware");
$fru->desc("UEFI Version");
my $pending = "";
if ($sessdata->{biosbuildpending}) {
$pending = " [PENDING: $sessdata->{biosbuildpending}]";
}
my $value = $sessdata->{biosbuildversion} . " (" . $sessdata->{biosbuildid} . " " . $sessdata->{biosbuilddate} . ")$pending";
my $value = $sessdata->{biosbuildversion} . " (" . $sessdata->{biosbuildid} . " " . $sessdata->{biosbuilddate} . ")";
$fru->value($value);
$sessdata->{fru_hash}->{uefi} = $fru;
if ($sessdata->{biosbuildpending}) {
$fru = FRU->new();
$fru->rec_type("bios,uefi,firmware");
$fru->desc("Pending UEFI Build ID");
$fru->value($sessdata->{biosbuildpending});
$sessdata->{fru_hash}->{uefi_pending} = $fru;
}
get_imm_property(property => "/v2/fpga/build_id", callback => \&got_fpga_buildid, sessdata => $sessdata);
} else {
initfru_with_mprom($sessdata);
+234
View File
@@ -0,0 +1,234 @@
#!/usr/bin/env perl
use strict;
use warnings;
## no critic (Modules::RequireFilenameMatchesPackage, TestingAndDebugging::ProhibitNoStrict, TestingAndDebugging::ProhibitNoWarnings)
no warnings qw(once redefine);
use File::Spec;
use FindBin;
use Test::More;
BEGIN {
for my $module (qw(
xCAT::GlobalDef xCAT_monitoring::monitorctrl xCAT::IPMI
xCAT::BMCUtils xCAT::PasswordUtils xCAT::Utils xCAT::TableUtils
xCAT::IMMUtils xCAT::ServiceNodeUtils xCAT::NetworkUtils xCAT::Usage
xCAT::data::ibmhwtypes xCAT::data::ibmleds
xCAT::data::ipmigenericevents xCAT::data::ipmisensorevents
IBM::EnergyManager
)) {
(my $file = $module) =~ s{::}{/}g;
$INC{"$file.pm"} = __FILE__;
no strict 'refs';
*{"${module}::import"} = sub { };
}
package xCAT::SvrUtils;
our @messages;
sub import { }
sub sendmsg { push @messages, $_[0]; }
$INC{'xCAT/SvrUtils.pm'} = __FILE__;
package xCAT::SPD;
sub import {
my $caller = caller;
no strict 'refs';
*{"${caller}::decode_spd"} = sub { return; };
}
$INC{'xCAT/SPD.pm'} = __FILE__;
package File::Path;
sub import {
my $caller = caller;
no strict 'refs';
*{"${caller}::mkpath"} = sub { return; };
}
$INC{'File/Path.pm'} = __FILE__;
package Thread;
sub import {
my $caller = caller;
no strict 'refs';
*{"${caller}::yield"} = sub { return; };
}
$INC{'Thread.pm'} = __FILE__;
package LWP;
our $VERSION = 5.64;
sub import { }
$INC{'LWP.pm'} = __FILE__;
package HTTP::Request::Common;
sub import {
my $caller = caller;
no strict 'refs';
*{"${caller}::GET"} = sub { return; };
*{"${caller}::POST"} = sub { return; };
}
$INC{'HTTP/Request/Common.pm'} = __FILE__;
package main;
*CORE::GLOBAL::chmod = sub (@) { return 1; };
}
package main;
my $repo_root = File::Spec->catdir($FindBin::Bin, '..', '..');
$ENV{XCATROOT} = File::Spec->catdir($repo_root, 'xCAT-server');
my $plugin = File::Spec->catfile(
$repo_root, qw(xCAT-server lib xcat plugins ipmi.pm)
);
do $plugin or die $@ || "Unable to load $plugin: $!";
sub new_sessdata {
my ($pending) = @_;
return {
biosbuildid => 'TCE123A',
biosbuildpending => $pending,
biosbuildversion => '2.13',
bmcnum => 1,
extraargs => [],
fru_hash => {},
invtypes => ['firmware'],
isite => 0,
node => 'node01',
};
}
sub run_got_bios_date {
my ($sessdata) = @_;
my @calls;
local *xCAT_plugin::ipmi::get_imm_property = sub {
push @calls, { @_ };
};
xCAT_plugin::ipmi::got_bios_date(
data => '2026-08-30',
sessdata => $sessdata,
);
return \@calls;
}
sub assert_next_property {
my ($calls, $sessdata, $case) = @_;
is(scalar(@{$calls}), 1, "$case: one next property request");
is(
$calls->[0]->{property},
'/v2/fpga/build_id',
"$case: FPGA build ID follows",
);
is(
$calls->[0]->{callback},
\&xCAT_plugin::ipmi::got_fpga_buildid,
"$case: correct callback follows",
);
is(
$calls->[0]->{sessdata},
$sessdata,
"$case: session data is preserved",
);
}
subtest 'pending UEFI build ID is a separate inventory record' => sub {
my $sessdata = new_sessdata('TCE124A');
my $calls = run_got_bios_date($sessdata);
is(
$sessdata->{biosbuilddate},
'2026-08-30',
'BIOS build date is recorded',
);
is_deeply(
[sort keys %{ $sessdata->{fru_hash} }],
[qw(uefi uefi_pending)],
'active and pending keys are exact',
);
my $active = $sessdata->{fru_hash}->{uefi};
isa_ok($active, 'FRU', 'active inventory record');
is(
$active->rec_type,
'bios,uefi,firmware',
'active record type is unchanged',
);
is($active->desc, 'UEFI Version', 'active record label is unchanged');
is(
$active->value,
'2.13 (TCE123A 2026-08-30)',
'active value does not associate the pending build with this bank',
);
my $pending = $sessdata->{fru_hash}->{uefi_pending};
isa_ok($pending, 'FRU', 'pending inventory record');
is(
$pending ? $pending->rec_type : undef,
'bios,uefi,firmware',
'pending record has firmware inventory types',
);
is(
$pending ? $pending->desc : undef,
'Pending UEFI Build ID',
'pending record identifies the value as a build ID',
);
is(
$pending ? $pending->value : undef,
'TCE124A',
'pending record contains the OEM pending build ID',
);
assert_next_property($calls, $sessdata, 'pending');
local @xCAT::SvrUtils::messages = ();
{
local $SIG{__WARN__} = sub {
my ($warning) = @_;
return
if $warning =~
/\AArgument "uefi(?:_pending)?" isn't numeric in numeric comparison \(<=>\)/;
die $warning;
};
xCAT_plugin::ipmi::fru_initted($sessdata);
}
is_deeply(
\@xCAT::SvrUtils::messages,
[
sprintf(
'%-20s %s',
'UEFI Version:',
'2.13 (TCE123A 2026-08-30)',
),
sprintf('%-20s %s', 'Pending UEFI Build ID:', 'TCE124A'),
],
'active UEFI output precedes pending UEFI output',
);
};
subtest 'no pending UEFI build leaves inventory unchanged' => sub {
my $sessdata = new_sessdata(0);
my $calls = run_got_bios_date($sessdata);
is_deeply(
[sort keys %{ $sessdata->{fru_hash} }],
['uefi'],
'only the active key is present',
);
my $active = $sessdata->{fru_hash}->{uefi};
is(
$active->rec_type,
'bios,uefi,firmware',
'active record type remains unchanged',
);
is($active->desc, 'UEFI Version', 'active record label remains unchanged');
is(
$active->value,
'2.13 (TCE123A 2026-08-30)',
'active record value remains unchanged',
);
ok(
!exists $sessdata->{fru_hash}->{uefi_pending},
'pending record is omitted',
);
assert_next_property($calls, $sessdata, 'no pending');
};
done_testing();