2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-08-01 02:29:41 +00:00

Merge pull request #7647 from VersatusHPC/refactor/probe-netplan-command-capture

refactor(probe): reuse command capture for netplan
This commit is contained in:
Daniel Hilst
2026-07-27 12:27:36 -03:00
committed by GitHub
2 changed files with 173 additions and 15 deletions
+29 -15
View File
@@ -160,16 +160,15 @@ sub get_os {
sub _netplan_get {
my $key = shift;
my $pid = open(my $fh, '-|');
return unless defined $pid;
if ($pid == 0) {
open(STDERR, '>', '/dev/null');
exec 'netplan', 'get', $key;
exit 1;
}
my $val = <$fh>;
close $fh;
return if $?;
my ($val, $error) = _capture_command(
sub {
my $fh = shift;
return scalar <$fh>;
},
1,
'netplan', 'get', $key
);
return if defined $error;
chomp $val if defined $val;
return $val;
}
@@ -183,8 +182,8 @@ sub _command_available {
return 0;
}
sub _capture_command_output {
my @command = @_;
sub _capture_command {
my ($read_output, $exec_failure_status, @command) = @_;
my $pid = open(my $fh, '-|');
unless (defined $pid) {
my $error = "unable to start '$command[0]': $!";
@@ -193,11 +192,10 @@ sub _capture_command_output {
if ($pid == 0) {
open(STDERR, '>', '/dev/null');
exec @command;
exit 127;
exit $exec_failure_status;
}
local $/;
my $output = <$fh>;
my $output = $read_output->($fh);
close $fh;
my $status = $?;
if ($status) {
@@ -213,6 +211,22 @@ sub _capture_command_output {
return wantarray ? (undef, $error) : undef;
}
return wantarray ? ($output, undef) : $output;
}
sub _capture_command_output {
my @command = @_;
my ($output, $error) = _capture_command(
sub {
my $fh = shift;
local $/;
return scalar <$fh>;
},
127,
@command
);
return wantarray ? (undef, $error) : undef if defined $error;
$output = '' unless defined $output;
return wantarray ? ($output, undef) : $output;
}
+144
View File
@@ -0,0 +1,144 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../xCAT-probe/lib/perl";
use File::Temp qw(tempdir);
use Test::More;
require probe_utils;
sub write_file {
my ($file, $contents) = @_;
open(my $fh, '>', $file) or die "Unable to write $file: $!";
print $fh $contents;
close $fh;
}
sub read_file {
my $file = shift;
open(my $fh, '<', $file) or die "Unable to read $file: $!";
local $/;
my $contents = <$fh>;
close $fh;
return $contents;
}
my $fake_bin = tempdir(CLEANUP => 1);
my $argv_file = "$fake_bin/argv";
my $fake_netplan = "$fake_bin/netplan";
write_file($fake_netplan, <<'EOF');
#!/usr/bin/env perl
use strict;
use warnings;
open(my $fh, '>', $ENV{XCAT_TEST_NETPLAN_ARGV}) or die "Unable to record arguments: $!";
print $fh join("\n", @ARGV), "\n";
close $fh;
my $mode = $ENV{XCAT_TEST_NETPLAN_MODE} || '';
if ($mode eq 'multiple-lines') {
print "first line\nsecond line\n";
} elsif ($mode eq 'continued-output') {
local $| = 1;
print "first line\n";
local $SIG{PIPE} = 'IGNORE';
for (1 .. 4096) {
exit 7 unless print 'x' x 4096;
}
} elsif ($mode eq 'empty-first-line') {
print "\nsecond line\n";
} elsif ($mode eq 'no-trailing-newline') {
print "single line";
} elsif ($mode eq 'empty-output') {
exit 0;
} elsif ($mode eq 'failure') {
print "ignored output\n";
print STDERR "netplan get failed\n";
exit 7;
} else {
die "Unknown test mode: $mode";
}
EOF
chmod oct('755'), $fake_netplan;
local $ENV{PATH} = "$fake_bin:$ENV{PATH}";
local $ENV{XCAT_TEST_NETPLAN_ARGV} = $argv_file;
{
local $ENV{XCAT_TEST_NETPLAN_MODE} = 'multiple-lines';
is(
probe_utils::_netplan_get('ethernets.eth0.addresses'),
'first line',
'netplan get returns only the first output line'
);
is(
read_file($argv_file),
"get\nethernets.eth0.addresses\n",
'netplan get receives the exact subcommand and key arguments'
);
}
{
local $ENV{XCAT_TEST_NETPLAN_MODE} = 'continued-output';
ok(
!defined(probe_utils::_netplan_get('ethernets.eth0')),
'a command failure after the first line still returns undef'
);
}
{
local $ENV{XCAT_TEST_NETPLAN_MODE} = 'empty-first-line';
is(
probe_utils::_netplan_get('ethernets.eth0'),
'',
'an empty first line remains a defined empty value'
);
}
{
local $ENV{XCAT_TEST_NETPLAN_MODE} = 'no-trailing-newline';
is(
probe_utils::_netplan_get('ethernets.eth0'),
'single line',
'output without a trailing newline is preserved'
);
}
{
local $ENV{XCAT_TEST_NETPLAN_MODE} = 'empty-output';
ok(
!defined(probe_utils::_netplan_get('ethernets.eth0')),
'successful empty output returns undef'
);
my @values = probe_utils::_netplan_get('ethernets.eth0');
is(scalar(@values), 1, 'successful empty output returns one undef value in list context');
ok(!defined($values[0]), 'the list-context empty-output value is undef');
}
{
local $ENV{XCAT_TEST_NETPLAN_MODE} = 'failure';
ok(
!defined(probe_utils::_netplan_get('ethernets.eth0')),
'failed netplan get returns undef even when it writes output'
);
my @values = probe_utils::_netplan_get('ethernets.eth0');
is(scalar(@values), 0, 'failed netplan get returns an empty list in list context');
}
{
my $missing_bin = tempdir(CLEANUP => 1);
local $ENV{PATH} = $missing_bin;
my $value = probe_utils::_netplan_get('ethernets.eth0');
my $status = $?;
ok(!defined($value), 'netplan exec failure returns undef');
is($status >> 8, 1, 'netplan exec failure preserves its original exit status');
}
done_testing();