diff --git a/xCAT-test/unit/xcatdsklspost_mypostscript.t b/xCAT-test/unit/xcatdsklspost_mypostscript.t
new file mode 100644
index 000000000..6607adfbd
--- /dev/null
+++ b/xCAT-test/unit/xcatdsklspost_mypostscript.t
@@ -0,0 +1,184 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use File::Spec;
+use File::Temp qw(tempdir tempfile);
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+use Test::More;
+
+use XCAT::Test::File qw(repo_path);
+
+my $postscript = repo_path(
+ File::Spec->catfile( 'xCAT', 'postscripts', 'xcatdsklspost' ) );
+my $library = repo_path(
+ File::Spec->catfile( 'xCAT', 'postscripts', 'xcatlib.sh' ) );
+
+is( system( 'bash', '-n', $postscript ), 0,
+ 'xcatdsklspost retains valid Bash syntax' );
+is( system( 'bash', '-n', $library ), 0,
+ 'xcatlib retains valid Bash syntax' );
+
+my ( $runner_fh, $runner ) = tempfile( UNLINK => 1 );
+print {$runner_fh} <<'BASH';
+source "$POST_TEST_LIBRARY"
+xcatpost=$POST_TEST_ROOT
+GETPOSTSCRIPT_ARGS=${POST_TEST_NODE-}
+
+if [ "$POST_TEST_MODE" = "twice" ]; then
+ first=$(fetch_mypostscript "$xcatpost" $GETPOSTSCRIPT_ARGS)
+ first_status=$?
+ second=$(fetch_mypostscript "$xcatpost" $GETPOSTSCRIPT_ARGS)
+ second_status=$?
+ printf 'first_status=%s\nfirst=%s\n' "$first_status" "$first"
+ printf 'second_status=%s\nsecond=%s\n' "$second_status" "$second"
+ exit 0
+fi
+
+fetch_mypostscript "$xcatpost" $GETPOSTSCRIPT_ARGS
+BASH
+close($runner_fh);
+
+sub run_fetch {
+ my (%options) = @_;
+ my $root = tempdir( CLEANUP => 1 );
+ my $responses = File::Spec->catdir( $root, 'responses' );
+ mkdir($responses) or die "Unable to create $responses: $!";
+
+ my $fetcher = File::Spec->catfile( $root, 'getpostscript.awk' );
+ write_file(
+ $fetcher,
+ <<'SH'
+#!/bin/sh
+count=0
+if [ -r "$POST_TEST_COUNTER" ]; then
+ IFS= read -r count < "$POST_TEST_COUNTER"
+fi
+count=$((count + 1))
+printf '%s\n' "$count" > "$POST_TEST_COUNTER"
+printf 'argc=%s argv=%s\n' "$#" "$*" >> "$POST_TEST_ARGV"
+cat "$POST_TEST_RESPONSES/$count"
+SH
+ );
+ chmod( 0755, $fetcher ) or die "Unable to make $fetcher executable: $!";
+
+ my $index = 0;
+ for my $response ( @{ $options{responses} } ) {
+ $index++;
+ write_file( File::Spec->catfile( $responses, $index ), $response );
+ }
+
+ my $target = File::Spec->catfile( $root, 'mypostscript' );
+ write_file( $target, $options{preexisting} )
+ if exists $options{preexisting};
+ my $argv = File::Spec->catfile( $root, 'argv' );
+ my $counter = File::Spec->catfile( $root, 'counter' );
+
+ local %ENV = (
+ %ENV,
+ POST_TEST_ARGV => $argv,
+ POST_TEST_COUNTER => $counter,
+ POST_TEST_LIBRARY => $library,
+ POST_TEST_MODE => $options{mode} // 'single',
+ POST_TEST_NODE => $options{node} // '',
+ POST_TEST_RESPONSES => $responses,
+ POST_TEST_ROOT => $root,
+ );
+
+ open( my $output_fh, '-|', 'bash', '--noprofile', '--norc', $runner )
+ or die "Unable to run xcatdsklspost helper: $!";
+ my $output = do { local $/; <$output_fh> };
+ close($output_fh);
+ my $status = $? >> 8;
+
+ return {
+ argv => -e $argv ? read_file($argv) : '',
+ output => $output,
+ status => $status,
+ target => -e $target ? read_file($target) : undef,
+ };
+}
+
+sub write_file {
+ my ( $path, $contents ) = @_;
+ open( my $fh, '>:raw', $path ) or die "Unable to write $path: $!";
+ print {$fh} $contents;
+ close($fh) or die "Unable to close $path: $!";
+}
+
+sub read_file {
+ my ($path) = @_;
+ open( my $fh, '<:raw', $path ) or die "Unable to read $path: $!";
+ my $contents = do { local $/; <$fh> };
+ close($fh) or die "Unable to close $path: $!";
+ return $contents;
+}
+
+my $decoded = run_fetch(
+ node => 'node01',
+ responses => [ <<'XML' ],
+
+ MASTER=192.0.2.1
+ COMMAND=<tag> & "quoted" 'single'
+ LITERAL=<
+
+ignored
+
+XML
+);
+is( $decoded->{status}, 0, 'a response containing MASTER succeeds' );
+is( $decoded->{output}, "MASTER=192.0.2.1\n",
+ 'the helper returns the MASTER content used by the caller' );
+is(
+ $decoded->{target},
+ "MASTER=192.0.2.1\nCOMMAND= & \"quoted\" 'single'\nLITERAL=<\n",
+ 'the helper strips XML, empty lines, indentation, and decodes entities'
+);
+is( $decoded->{argv}, "argc=1 argv=node01\n",
+ 'the short node name is passed to getpostscript.awk' );
+
+my $without_node = run_fetch(
+ responses => [ "MASTER=198.51.100.8\n" ],
+);
+is( $without_node->{status}, 0, 'a fetch without a node name succeeds' );
+is( $without_node->{argv}, "argc=0 argv=\n",
+ 'an empty node name does not add an argument' );
+
+my $overwrite = run_fetch(
+ preexisting => "MASTER=stale\n",
+ responses => [ "POSTSCRIPT=ready\n" ],
+);
+isnt( $overwrite->{status}, 0, 'a response without MASTER is incomplete' );
+is( $overwrite->{output}, '', 'an incomplete response returns no MASTER content' );
+is( $overwrite->{target}, "POSTSCRIPT=ready\n",
+ 'each fetch overwrites the previous mypostscript' );
+
+my $empty = run_fetch( responses => [''] );
+isnt( $empty->{status}, 0, 'an empty response is incomplete' );
+is( $empty->{output}, '', 'an empty response returns no MASTER content' );
+is( $empty->{target}, '', 'an empty response leaves an empty output file' );
+
+my $retry = run_fetch(
+ mode => 'twice',
+ node => 'node02',
+ responses => [
+ "POSTSCRIPT=not-ready\n",
+ "MASTER=203.0.113.7\nPOSTSCRIPT=ready\n",
+ ],
+);
+is( $retry->{status}, 0, 'two consecutive fetches complete' );
+is(
+ $retry->{output},
+ "first_status=1\nfirst=\nsecond_status=0\nsecond=MASTER=203.0.113.7\n",
+ 'a later response supplies the MASTER content used to stop retries'
+);
+is(
+ $retry->{target},
+ "MASTER=203.0.113.7\nPOSTSCRIPT=ready\n",
+ 'the successful retry replaces the incomplete response'
+);
+is( $retry->{argv}, "argc=1 argv=node02\nargc=1 argv=node02\n",
+ 'each fetch retry passes the same short node name' );
+
+done_testing();
diff --git a/xCAT/postscripts/xcatdsklspost b/xCAT/postscripts/xcatdsklspost
index b0bc6d248..13110575d 100755
--- a/xCAT/postscripts/xcatdsklspost
+++ b/xCAT/postscripts/xcatdsklspost
@@ -182,7 +182,6 @@ download_mypostscript()
}
-
# pmatch determines if 1st argument string is matched by 2nd argument pattern
pmatch ()
@@ -680,6 +679,7 @@ fi
# We need to call getpostscript.awk .
if [ ! -x /$xcatpost/mypostscript ]; then
+ . /$xcatpost/xcatlib.sh
echolog "debug" "no pre-generated mypostscript., trying to get it with getpostscript.awk..."
GETPOSTSCRIPT_ARGS=""
if [ -n "$node_short" ]; then
@@ -699,10 +699,7 @@ if [ ! -x /$xcatpost/mypostscript ]; then
useflowcontrol=0
fi
fi
- /$xcatpost/getpostscript.awk $GETPOSTSCRIPT_ARGS | egrep '' | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' | sed -e 's/<//g' -e 's/&/\&/g' -e 's/"/"/g' -e "s/'/'/g" > /$xcatpost/mypostscript;
-
-
- MYCONT=`grep MASTER /$xcatpost/mypostscript`
+ MYCONT=`fetch_mypostscript "$xcatpost" $GETPOSTSCRIPT_ARGS`
MAX_RETRIES=10
RETRY=0
while [ -z "$MYCONT" ]; do
@@ -733,8 +730,7 @@ if [ ! -x /$xcatpost/mypostscript ]; then
useflowcontrol=0
fi
fi
- /$xcatpost/getpostscript.awk $GETPOSTSCRIPT_ARGS | egrep '' | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' | sed -e 's/<//g' -e 's/&/\&/g' -e 's/"/"/g' -e "s/'/'/g" > /$xcatpost/mypostscript;
- MYCONT=`grep MASTER /$xcatpost/mypostscript`
+ MYCONT=`fetch_mypostscript "$xcatpost" $GETPOSTSCRIPT_ARGS`
if [ ! -z "$MYCONT" ]; then
break;
fi
diff --git a/xCAT/postscripts/xcatlib.sh b/xCAT/postscripts/xcatlib.sh
index 5ddbc6663..b06838589 100755
--- a/xCAT/postscripts/xcatlib.sh
+++ b/xCAT/postscripts/xcatlib.sh
@@ -832,3 +832,19 @@ function msgutil_r {
function msgutil {
msgutil_r "" "$@"
}
+
+function fetch_mypostscript {
+ local postroot
+ postroot=$1
+ shift
+
+ /$postroot/getpostscript.awk "$@" |
+ egrep '' |
+ sed -e 's/<[^>]*>//g' |
+ egrep -v '^ *$' |
+ sed -e 's/^ *//' |
+ sed -e 's/<//g' -e 's/&/\&/g' \
+ -e 's/"/"/g' -e "s/'/'/g" > /$postroot/mypostscript
+
+ grep MASTER /$postroot/mypostscript
+}