2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-07-31 18:19:40 +00:00

Merge pull request #7588 from VersatusHPC/fix/issue-6495-nfs-root-options

feat: add configurable NFS root options for statelite images
This commit is contained in:
Daniel Hilst
2026-07-17 23:46:14 -03:00
committed by GitHub
12 changed files with 273 additions and 36 deletions
@@ -136,3 +136,16 @@ noderes
``noderes.nfsdir`` can be set. If this is not set, the default is ``/install``
NFS root mount options
----------------------
For dracut-based NFS statelite images, additional NFS root mount options can
be set on the osimage. For example, to disable attribute caching::
chdef -t osimage -o rhels9-ppc64le-statelite-compute nfsrootopts=noac
nodeset compute osimage=rhels9-ppc64le-statelite-compute
The value is a comma-separated list, such as ``noac,actimeo=0``. xCAT always
includes ``ro`` and does not accept ``rw`` or ``defaults`` because the shared
statelite root filesystem must remain read-only. The ``statelite.mntopts``
attribute continues to control only the separate persistent directory.
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **osimage Attributes:**\ \ *imagename*\ , \ *groups*\ , \ *profile*\ , \ *imagetype*\ , \ *description*\ , \ *provmethod*\ , \ *rootfstype*\ , \ *osdistroname*\ , \ *osupdatename*\ , \ *cfmdir*\ , \ *osname*\ , \ *osvers*\ , \ *osarch*\ , \ *synclists*\ , \ *postscripts*\ , \ *postbootscripts*\ , \ *serverrole*\ , \ *isdeletable*\ , \ *kitcomponents*\ , \ *environvar*\ , \ *comments*\ , \ *disable*\
\ **osimage Attributes:**\ \ *imagename*\ , \ *groups*\ , \ *profile*\ , \ *imagetype*\ , \ *description*\ , \ *provmethod*\ , \ *rootfstype*\ , \ *nfsrootopts*\ , \ *osdistroname*\ , \ *osupdatename*\ , \ *cfmdir*\ , \ *osname*\ , \ *osvers*\ , \ *osarch*\ , \ *synclists*\ , \ *postscripts*\ , \ *postbootscripts*\ , \ *serverrole*\ , \ *isdeletable*\ , \ *kitcomponents*\ , \ *environvar*\ , \ *comments*\ , \ *disable*
***********
@@ -78,6 +78,11 @@ osimage Attributes:
\ **nfsrootopts**
A comma-separated list of additional NFS mount options for the root filesystem of a dracut-based statelite image. The root filesystem is always mounted read-only; rw and defaults are not allowed.
\ **osdistroname**\
The name of the OS distro definition. This attribute can be used to specify which OS distro to use, instead of using the osname,osvers,and osarch attributes. For \*kit commands, the attribute will be used to read the osdistro table for the osname, osvers, and osarch attributes. If defined, the osname, osvers, and osarch attributes defined in the osimage table will be ignored.
@@ -175,4 +180,3 @@ SEE ALSO
\ **nodels(1)**\ , \ **chtab(8)**\ , \ **tabdump(8)**\ , \ **tabedit(8)**\
@@ -19,7 +19,7 @@ SYNOPSIS
********
\ **osimage Attributes:**\ \ *addkcmdline*\ , \ *boottarget*\ , \ *bosinst_data*\ , \ *cfmdir*\ , \ *configdump*\ , \ *crashkernelsize*\ , \ *description*\ , \ *driverupdatesrc*\ , \ *dump*\ , \ *environvar*\ , \ *exlist*\ , \ *fb_script*\ , \ *groups*\ , \ *home*\ , \ *image_data*\ , \ *imagename*\ , \ *imagetype*\ , \ *installp_bundle*\ , \ *installto*\ , \ *isdeletable*\ , \ *kerneldir*\ , \ *kernelver*\ , \ *kitcomponents*\ , \ *krpmver*\ , \ *lpp_source*\ , \ *mksysb*\ , \ *netdrivers*\ , \ *nimmethod*\ , \ *nimtype*\ , \ *nodebootif*\ , \ *osarch*\ , \ *osdistroname*\ , \ *osname*\ , \ *osupdatename*\ , \ *osvers*\ , \ *otherifce*\ , \ *otherpkgdir*\ , \ *otherpkglist*\ , \ *otherpkgs*\ , \ *paging*\ , \ *partitionfile*\ , \ *permission*\ , \ *pkgdir*\ , \ *pkglist*\ , \ *postbootscripts*\ , \ *postinstall*\ , \ *postscripts*\ , \ *profile*\ , \ *provmethod*\ , \ *resolv_conf*\ , \ *root*\ , \ *rootfstype*\ , \ *rootimgdir*\ , \ *script*\ , \ *serverrole*\ , \ *shared_home*\ , \ *shared_root*\ , \ *spot*\ , \ *synclists*\ , \ *template*\ , \ *tmp*\ , \ *usercomment*\ , \ *winpepath*\
\ **osimage Attributes:**\ \ *addkcmdline*\ , \ *boottarget*\ , \ *bosinst_data*\ , \ *cfmdir*\ , \ *configdump*\ , \ *crashkernelsize*\ , \ *description*\ , \ *driverupdatesrc*\ , \ *dump*\ , \ *environvar*\ , \ *exlist*\ , \ *fb_script*\ , \ *groups*\ , \ *home*\ , \ *image_data*\ , \ *imagename*\ , \ *imagetype*\ , \ *installp_bundle*\ , \ *installto*\ , \ *isdeletable*\ , \ *kerneldir*\ , \ *kernelver*\ , \ *kitcomponents*\ , \ *krpmver*\ , \ *lpp_source*\ , \ *mksysb*\ , \ *netdrivers*\ , \ *nfsrootopts*\ , \ *nimmethod*\ , \ *nimtype*\ , \ *nodebootif*\ , \ *osarch*\ , \ *osdistroname*\ , \ *osname*\ , \ *osupdatename*\ , \ *osvers*\ , \ *otherifce*\ , \ *otherpkgdir*\ , \ *otherpkglist*\ , \ *otherpkgs*\ , \ *paging*\ , \ *partitionfile*\ , \ *permission*\ , \ *pkgdir*\ , \ *pkglist*\ , \ *postbootscripts*\ , \ *postinstall*\ , \ *postscripts*\ , \ *profile*\ , \ *provmethod*\ , \ *resolv_conf*\ , \ *root*\ , \ *rootfstype*\ , \ *rootimgdir*\ , \ *script*\ , \ *serverrole*\ , \ *shared_home*\ , \ *shared_root*\ , \ *spot*\ , \ *synclists*\ , \ *template*\ , \ *tmp*\ , \ *usercomment*\ , \ *winpepath*
***********
@@ -204,6 +204,11 @@ osimage Attributes:
The ethernet device drivers of the nodes which will use this linux image, at least the device driver for the nodes' installnic should be included
\ **nfsrootopts**\ (osimage.nfsrootopts)
A comma-separated list of additional NFS mount options for the root filesystem of a dracut-based statelite image. The root filesystem is always mounted read-only; rw and defaults are not allowed.
\ **nimmethod**\ (nimimage.nimmethod)
+7 -1
View File
@@ -773,7 +773,7 @@ passed as argument rather than by table value',
},
},
osimage => {
cols => [qw(imagename groups profile imagetype description provmethod rootfstype osdistroname osupdatename cfmdir osname osvers osarch synclists postscripts postbootscripts serverrole isdeletable kitcomponents environvar comments disable)],
cols => [qw(imagename groups profile imagetype description provmethod rootfstype nfsrootopts osdistroname osupdatename cfmdir osname osvers osarch synclists postscripts postbootscripts serverrole isdeletable kitcomponents environvar comments disable)],
keys => [qw(imagename)],
tablespace => 'XCATTBS32K',
table_desc => 'Basic information about an operating system image that can be used to deploy cluster nodes.',
@@ -787,6 +787,7 @@ passed as argument rather than by table value',
description => 'OS Image Description',
provmethod => 'The provisioning method for node deployment. The valid values are install, netboot,statelite,boottarget,dualboot,sysclone. If boottarget is set, you must set linuximage.boottarget to the name of the boottarget definition. It is not used by AIX.',
rootfstype => 'The filesystem type for the rootfs is used when the provmethod is statelite. The valid values are nfs or ramdisk. The default value is nfs',
nfsrootopts => 'A comma-separated list of additional NFS mount options for the root filesystem of a dracut-based statelite image. The root filesystem is always mounted read-only; rw and defaults are not allowed.',
osdistroname => 'The name of the OS distro definition. This attribute can be used to specify which OS distro to use, instead of using the osname,osvers,and osarch attributes. For *kit commands, the attribute will be used to read the osdistro table for the osname, osvers, and osarch attributes. If defined, the osname, osvers, and osarch attributes defined in the osimage table will be ignored.',
osupdatename => 'A comma-separated list of OS distro updates to apply to this osimage.',
cfmdir => 'CFM directory name for PCM. Set to /install/osimages/<osimage name>/cfmdir by PCM. ',
@@ -3217,6 +3218,11 @@ push(@{ $defspec{node}->{'attrs'} }, @nodeattrs);
tabentry => 'osimage.rootfstype',
access_tabentry => 'osimage.imagename=attr:imagename',
},
{ attr_name => 'nfsrootopts',
only_if => 'imagetype=linux',
tabentry => 'osimage.nfsrootopts',
access_tabentry => 'osimage.imagename=attr:imagename',
},
{ attr_name => 'profile',
tabentry => 'osimage.profile',
access_tabentry => 'osimage.imagename=attr:imagename',
+48
View File
@@ -2415,6 +2415,54 @@ sub getplatform {
return $platform;
}
# Parse statelite NFS root options once so command-time validation and the
# dracut root=nfs renderer enforce the same rules.
sub _parse_statelite_nfsroot_options {
my ($additional_options) = @_;
my @mount_options;
if (defined($additional_options) && $additional_options ne '') {
foreach my $option (split(/,/, $additional_options, -1)) {
if ($option eq '' || $option =~ /\s/) {
return (undef, 'nfsrootopts must be a comma-separated list without whitespace or empty options');
}
my ($name) = split(/=/, $option, 2);
$name = lc($name);
if ($name eq 'rw' || $name eq 'defaults') {
return (undef, "nfsrootopts cannot contain '$name'; statelite NFS roots are always read-only");
}
next if lc($option) eq 'ro';
push @mount_options, $option;
}
}
return (\@mount_options, undef);
}
# Return an error message when statelite NFS root options violate the
# read-only root filesystem contract.
sub validate_statelite_nfsroot_options {
shift if @_ && defined($_[0]) && $_[0] eq __PACKAGE__;
my ($additional_options) = @_;
my ($mount_options, $error) = _parse_statelite_nfsroot_options($additional_options);
return $error;
}
# Build the dracut root=nfs parameter while preserving statelite's read-only
# root filesystem contract.
sub build_statelite_nfsroot_parameter {
shift if @_ && defined($_[0]) && $_[0] eq __PACKAGE__;
my ($server, $rootdir, $additional_options) = @_;
my ($additional_mount_options, $error) = _parse_statelite_nfsroot_options($additional_options);
return (undef, $error) if $error;
my @mount_options = ('ro', @{$additional_mount_options});
return ('root=nfs:' . $server . ':' . $rootdir . ':' . join(',', @mount_options), undef);
}
#--------------------------------------------------------------------------------------------------------
#searchcompressedrootimg:
#description: search the compressed rootimage for diskless or statelite osimage under specified directory
@@ -369,6 +369,19 @@ sub parse_attr_for_osimage {
return 0;
}
sub validate_osimage_nfsrootopts {
my $attr_hash = shift;
return 0 unless exists($attr_hash->{nfsrootopts});
my $validation_error = xCAT::SvrUtils->validate_statelite_nfsroot_options($attr_hash->{nfsrootopts});
return 0 unless $validation_error;
my $rsp;
$rsp->{data}->[0] = $validation_error;
xCAT::MsgUtils->message("E", $rsp, $::callback);
return 1;
}
#----------------------------------------------------------------------------
=head3 processArgs
@@ -1886,6 +1899,13 @@ sub defmk
next;
}
if (($type eq 'osimage') && validate_osimage_nfsrootopts($::FINALATTRS{$obj}))
{
$error = 1;
delete $::FINALATTRS{$obj};
next;
}
if ($object_exists && $::opt_f)
{
# remove the old object after the replacement definition is known valid
@@ -2531,6 +2551,13 @@ sub defch
$isDefined = 1;
}
if (($type eq 'osimage') && !$::opt_m && validate_osimage_nfsrootopts($::FINALATTRS{$obj}))
{
$error = 1;
delete($::FINALATTRS{$obj});
next;
}
if ($type eq 'network')
{
my $isInvalid = 0;
+19 -10
View File
@@ -261,6 +261,7 @@ sub mknetboot
my $dump; # for kdump, its format is "nfs://<nfs_server_ip>/<kdump_path>"
my $crashkernelsize;
my $rootfstype;
my $nfsrootopts;
my $tftpdir;
my $cfgpart;
my $imagename; # set it if running of 'nodeset osimage=xxx'
@@ -283,13 +284,14 @@ sub mknetboot
if (!$osimagetab) {
$osimagetab = xCAT::Table->new('osimage', -create => 1);
}
(my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'rootfstype');
(my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'rootfstype', 'nfsrootopts');
if ($ref) {
$img_hash{$imagename}->{osver} = $ref->{'osvers'};
$img_hash{$imagename}->{osarch} = $ref->{'osarch'};
$img_hash{$imagename}->{profile} = $ref->{'profile'};
$img_hash{$imagename}->{provmethod} = $ref->{'provmethod'};
$img_hash{$imagename}->{rootfstype} = $ref->{rootfstype};
$img_hash{$imagename}->{osver} = $ref->{'osvers'};
$img_hash{$imagename}->{osarch} = $ref->{'osarch'};
$img_hash{$imagename}->{profile} = $ref->{'profile'};
$img_hash{$imagename}->{provmethod} = $ref->{'provmethod'};
$img_hash{$imagename}->{rootfstype} = $ref->{rootfstype};
$img_hash{$imagename}->{nfsrootopts} = $ref->{nfsrootopts};
if (!$linuximagetab) {
$linuximagetab = xCAT::Table->new('linuximage', -create => 1);
}
@@ -343,6 +345,7 @@ sub mknetboot
$profile = $ph->{profile};
$rootfstype = $ph->{rootfstype};
$nfsrootopts = $ph->{nfsrootopts};
$rootimgdir = $ph->{rootimgdir};
unless ($rootimgdir) {
$rootimgdir = "$installroot/netboot/$osver/$arch/$profile";
@@ -382,9 +385,10 @@ sub mknetboot
}
if ($osimagetab) {
my ($ref1) = $osimagetab->getAttribs({ imagename => $imgname }, 'rootfstype');
if (($ref1) && ($ref1->{'rootfstype'})) {
$rootfstype = $ref1->{'rootfstype'};
my ($ref1) = $osimagetab->getAttribs({ imagename => $imgname }, 'rootfstype', 'nfsrootopts');
if ($ref1) {
$rootfstype = $ref1->{'rootfstype'} if $ref1->{'rootfstype'};
$nfsrootopts = $ref1->{'nfsrootopts'};
}
} else {
xCAT::MsgUtils->report_node_error($callback, $node,
@@ -634,7 +638,12 @@ sub mknetboot
# special case for redhat6, fedora12/13/14
if (&using_dracut($osver)) {
$kcmdline = "root=nfs:$nfssrv:$nfsdir/rootimg:ro STATEMNT=";
my ($nfsroot, $error) = xCAT::SvrUtils->build_statelite_nfsroot_parameter($nfssrv, "$nfsdir/rootimg", $nfsrootopts);
if ($error) {
xCAT::MsgUtils->report_node_error($callback, $node, $error);
next;
}
$kcmdline = "$nfsroot STATEMNT=";
} else {
$kcmdline = "NFSROOT=$nfssrv:$nfsdir STATEMNT=";
}
+19 -10
View File
@@ -1163,6 +1163,7 @@ sub mknetboot
my $dump; # for kdump, its format is "nfs://<nfs_server_ip>/<kdump_path>"
my $crashkernelsize;
my $rootfstype;
my $nfsrootopts;
my $tftpdir;
my $imagename; # set it if running of 'nodeset osimage=xxx'
@@ -1179,13 +1180,14 @@ sub mknetboot
if (!$osimagetab) {
$osimagetab = xCAT::Table->new('osimage', -create => 1);
}
(my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'rootfstype');
(my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'rootfstype', 'nfsrootopts');
if ($ref) {
$img_hash{$imagename}->{osver} = $ref->{'osvers'};
$img_hash{$imagename}->{osarch} = $ref->{'osarch'};
$img_hash{$imagename}->{profile} = $ref->{'profile'};
$img_hash{$imagename}->{provmethod} = $ref->{'provmethod'};
$img_hash{$imagename}->{rootfstype} = $ref->{'rootfstype'};
$img_hash{$imagename}->{osver} = $ref->{'osvers'};
$img_hash{$imagename}->{osarch} = $ref->{'osarch'};
$img_hash{$imagename}->{profile} = $ref->{'profile'};
$img_hash{$imagename}->{provmethod} = $ref->{'provmethod'};
$img_hash{$imagename}->{rootfstype} = $ref->{'rootfstype'};
$img_hash{$imagename}->{nfsrootopts} = $ref->{'nfsrootopts'};
if (!$linuximagetab) {
$linuximagetab = xCAT::Table->new('linuximage', -create => 1);
}
@@ -1215,6 +1217,7 @@ sub mknetboot
$profile = $ph->{profile};
$rootfstype = $ph->{rootfstype};
$nfsrootopts = $ph->{nfsrootopts};
$rootimgdir = $ph->{rootimgdir};
unless ($rootimgdir) {
@@ -1249,9 +1252,10 @@ sub mknetboot
}
if ($osimagetab) {
my ($ref1) = $osimagetab->getAttribs({ imagename => $imgname }, 'rootfstype');
if (($ref1) && ($ref1->{'rootfstype'})) {
$rootfstype = $ref1->{'rootfstype'};
my ($ref1) = $osimagetab->getAttribs({ imagename => $imgname }, 'rootfstype', 'nfsrootopts');
if ($ref1) {
$rootfstype = $ref1->{'rootfstype'} if $ref1->{'rootfstype'};
$nfsrootopts = $ref1->{'nfsrootopts'};
}
} else {
xCAT::MsgUtils->report_node_error($callback, $node,
@@ -1456,7 +1460,12 @@ sub mknetboot
# special case for redhat6, fedora12/13/14
if (&using_dracut($osver)) {
$kcmdline = "root=nfs:$nfssrv:$nfsdir/rootimg:ro STATEMNT=";
my ($nfsroot, $error) = xCAT::SvrUtils->build_statelite_nfsroot_parameter($nfssrv, "$nfsdir/rootimg", $nfsrootopts);
if ($error) {
xCAT::MsgUtils->report_node_error($callback, $node, $error);
next;
}
$kcmdline = "$nfsroot STATEMNT=";
} else {
$kcmdline = "NFSROOT=$nfssrv:$nfsdir STATEMNT=";
}
+19 -10
View File
@@ -137,6 +137,7 @@ sub mknetboot
my $dump; #for kdump
my $crashkernelsize;
my $rootfstype;
my $nfsrootopts;
my $cfgpart;
my $imagename; # set it if running of 'nodeset osimage=xxx'
@@ -147,13 +148,14 @@ sub mknetboot
if (!$osimagetab) {
$osimagetab = xCAT::Table->new('osimage', -create => 1);
}
(my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'rootfstype', 'provmethod');
(my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'rootfstype', 'nfsrootopts', 'provmethod');
if ($ref) {
$img_hash{$imagename}->{osver} = $ref->{'osvers'};
$img_hash{$imagename}->{osarch} = $ref->{'osarch'};
$img_hash{$imagename}->{profile} = $ref->{'profile'};
$img_hash{$imagename}->{rootfstype} = $ref->{'rootfstype'};
$img_hash{$imagename}->{provmethod} = $ref->{'provmethod'};
$img_hash{$imagename}->{osver} = $ref->{'osvers'};
$img_hash{$imagename}->{osarch} = $ref->{'osarch'};
$img_hash{$imagename}->{profile} = $ref->{'profile'};
$img_hash{$imagename}->{rootfstype} = $ref->{'rootfstype'};
$img_hash{$imagename}->{nfsrootopts} = $ref->{'nfsrootopts'};
$img_hash{$imagename}->{provmethod} = $ref->{'provmethod'};
if (!$linuximagetab) {
$linuximagetab = xCAT::Table->new('linuximage', -create => 1);
}
@@ -204,6 +206,7 @@ sub mknetboot
$arch = $ph->{osarch};
$profile = $ph->{profile};
$rootfstype = $ph->{rootfstype};
$nfsrootopts = $ph->{nfsrootopts};
$nodebootif = $ph->{nodebootif};
$provmethod = $ph->{provmethod};
$dump = $ph->{dump};
@@ -242,9 +245,10 @@ sub mknetboot
}
if ($osimagetab) {
my ($ref1) = $osimagetab->getAttribs({ imagename => $imgname }, 'rootfstype');
if (($ref1) && ($ref1->{'rootfstype'})) {
$rootfstype = $ref1->{'rootfstype'};
my ($ref1) = $osimagetab->getAttribs({ imagename => $imgname }, 'rootfstype', 'nfsrootopts');
if ($ref1) {
$rootfstype = $ref1->{'rootfstype'} if $ref1->{'rootfstype'};
$nfsrootopts = $ref1->{'nfsrootopts'};
}
} else {
xCAT::MsgUtils->report_node_error($callback, $node,
@@ -469,7 +473,12 @@ sub mknetboot
$nfsdir = $ient->{nfsdir} . "/netboot/$osver/$arch/$profile";
}
if (&using_dracut($rootimgdir)) {
$kcmdline = "root=nfs:$nfssrv:$nfsdir/rootimg:ro STATEMNT=";
my ($nfsroot, $error) = xCAT::SvrUtils->build_statelite_nfsroot_parameter($nfssrv, "$nfsdir/rootimg", $nfsrootopts);
if ($error) {
xCAT::MsgUtils->report_node_error($callback, $node, $error);
next;
}
$kcmdline = "$nfsroot STATEMNT=";
} else {
$kcmdline = "NFSROOT=$nfssrv:$nfsdir STATEMNT=";
}
+26 -1
View File
@@ -34,6 +34,32 @@ cmd:rmdef -t node testnode
check:rc==0
end
start:chdef_osimage_nfsrootopts_validation
description:Reject invalid statelite NFS root options before provisioning without changing the osimage
label:mn_only,ci_test,db,statelite,nfsrootopts
cmd:rmdef -t node -o xcatnfsoptscinode >/dev/null 2>&1; rmdef -t osimage -o xcatnfsoptsciimage >/dev/null 2>&1; rm -rf /tmp/xcat-nfsrootopts-ci-root /tftpboot/xcat/osimage/xcatnfsoptsciimage; rm -f /tftpboot/xcat/xnba/nodes/xcatnfsoptscinode*
cmd:mkdir -p /tmp/xcat-nfsrootopts-ci-root; touch /tmp/xcat-nfsrootopts-ci-root/kernel /tmp/xcat-nfsrootopts-ci-root/initrd-statelite.gz
check:rc==0
cmd:mkdef -t osimage -o xcatnfsoptsciimage imagetype=linux provmethod=statelite profile=compute osname=Linux osvers=rhels6.99 osarch=x86_64 rootfstype=nfs rootimgdir=/tmp/xcat-nfsrootopts-ci-root nfsrootopts=noac
check:rc==0
cmd:mkdef -t node -o xcatnfsoptscinode groups=all arch=x86_64 netboot=xnba os=rhels6.99 profile=compute ip=192.0.2.100 mac=02:00:00:00:00:01
check:rc==0
cmd:chdef -t osimage -o xcatnfsoptsciimage nfsrootopts=rw
check:rc!=0
check:output=~nfsrootopts cannot contain 'rw'; statelite NFS roots are always read-only
cmd:lsdef -t osimage -o xcatnfsoptsciimage -i nfsrootopts
check:rc==0
check:output=~nfsrootopts=noac
check:output!~nfsrootopts=rw
cmd:old=`lsdef -t site clustersite -i dhcpsetup | grep 'dhcpsetup=' | awk -F= '{print $2}'`; trap 'chdef -t site clustersite dhcpsetup="$old" >/dev/null 2>&1' EXIT; chdef -t site clustersite dhcpsetup=n >/dev/null 2>&1 && nodeset xcatnfsoptscinode osimage=xcatnfsoptsciimage
check:rc==0
check:output!~nfsrootopts
cmd:grep 'root=nfs:.*:ro,noac' /tftpboot/xcat/xnba/nodes/xcatnfsoptscinode
check:rc==0
cmd:rmdef -t node -o xcatnfsoptscinode; rmdef -t osimage -o xcatnfsoptsciimage; rm -rf /tmp/xcat-nfsrootopts-ci-root /tftpboot/xcat/osimage/xcatnfsoptsciimage; rm -f /tftpboot/xcat/xnba/nodes/xcatnfsoptscinode*
check:rc==0
end
start:chdef_t_network
description:chdef -t network
label:mn_only,ci_test,db
@@ -324,4 +350,3 @@ cmd:rmdef -t network -o aaaaa_not_exist
check:rc==0
cmd:rm -rf /tmp/bbbbb_not_exist.def
end
@@ -65,8 +65,15 @@ check:rc==0
cmd:lsdef -t osimage -o __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute
check:rc==0
cmd:chdef -t osimage -o __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute rootfstype=nfs
cmd:chdef -t osimage -o __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute rootfstype=nfs nfsrootopts=noac
check:rc==0
cmd:chdef -t osimage -o __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute nfsrootopts=rw
check:rc!=0
check:output=~nfsrootopts cannot contain 'rw'; statelite NFS roots are always read-only
cmd:lsdef -t osimage -o __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute -i nfsrootopts
check:rc==0
check:output=~nfsrootopts=noac
check:output!~nfsrootopts=rw
cmd:genimage __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute
check:rc==0
@@ -99,6 +106,8 @@ cmd:xdsh $$CN mount
check:rc==0
check:output=~/nodedata/$$CN on /.statelite/persistent
check:output=~compute/rootimg on / type nfs
cmd:rootimgdir=`lsdef -t osimage __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute|grep rootimgdir|awk -F'=' '{print $2}'`; if [[ "__GETNODEATTR($$CN,os)__" =~ ^(rhels|rhel|centos|alma|rocky|ol)([6-9]|10) ]] || [[ "__GETNODEATTR($$CN,os)__" =~ ^fedora(1[2-9]|[2-9][0-9]) ]] || [[ "__GETNODEATTR($$CN,os)__" =~ ^SL([6-9]|10) ]] || [ -f "$rootimgdir/rootimg/etc/dracut.conf" ]; then xdsh $$CN mount | grep 'compute/rootimg on / type nfs' | grep 'noac'; fi
check:rc==0
cmd:xdsh $$CN hostname
check:rc==0
check:output=~$$CN: $$CN
@@ -112,6 +121,8 @@ check:output=~No load hostkey warning
cmd:if [ -x /usr/bin/goconserver ]; then makegocons -d $$CN; else makeconservercf -d $$CN; fi
cmd:output=$(xdsh $$CN ls -al / |grep test.statelite);if [[ $? -eq 0 ]];then xdsh $$CN rm -rf /test.statelite;fi
cmd:chdef -t osimage -o __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute nfsrootopts=
check:rc==0
cmd:rootimgdir=`lsdef -t osimage __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-statelite-compute|grep rootimgdir|awk -F'=' '{print $2}'`; if [ -d $rootimgdir ]; then rm -rf $rootimgdir;fi
check:rc==0
end
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
use lib "$FindBin::Bin/../../perl-xCAT";
use Test::More;
use xCAT::Schema;
use xCAT::SvrUtils;
sub build_nfsroot {
return xCAT::SvrUtils->build_statelite_nfsroot_parameter('192.0.2.1', '/install/netboot/test/rootimg', shift);
}
my ($parameter, $error) = build_nfsroot(undef);
is($parameter, 'root=nfs:192.0.2.1:/install/netboot/test/rootimg:ro', 'unset options preserve the read-only default');
is($error, undef, 'unset options are valid');
($parameter, $error) = build_nfsroot('');
is($parameter, 'root=nfs:192.0.2.1:/install/netboot/test/rootimg:ro', 'empty options preserve the read-only default');
is($error, undef, 'empty options are valid');
($parameter, $error) = build_nfsroot('noac,actimeo=0');
is($parameter, 'root=nfs:192.0.2.1:/install/netboot/test/rootimg:ro,noac,actimeo=0', 'additional options follow the mandatory read-only option');
is($error, undef, 'valid additional options are accepted');
($parameter, $error) = build_nfsroot('ro,nfsvers=4.1');
is($parameter, 'root=nfs:192.0.2.1:/install/netboot/test/rootimg:ro,nfsvers=4.1', 'a redundant read-only option is normalized');
is($error, undef, 'a redundant read-only option is valid');
($parameter, $error) = build_nfsroot('clientaddr=2001:db8::1');
is($parameter, 'root=nfs:192.0.2.1:/install/netboot/test/rootimg:ro,clientaddr=2001:db8::1', 'option values may contain colons');
is($error, undef, 'an option value containing colons is valid');
foreach my $invalid ('rw', 'RW', 'noac,rw', 'defaults', 'noac, actimeo=0', 'noac,,actimeo=0') {
($parameter, $error) = build_nfsroot($invalid);
is($parameter, undef, "invalid option list '$invalid' is rejected");
like($error, qr/^nfsrootopts /, "invalid option list '$invalid' reports the attribute name");
like(
xCAT::SvrUtils->validate_statelite_nfsroot_options($invalid),
qr/^nfsrootopts /,
"command-time validation rejects '$invalid'"
);
}
is(xCAT::SvrUtils->validate_statelite_nfsroot_options(undef), undef, 'command-time validation accepts an unset value');
is(xCAT::SvrUtils->validate_statelite_nfsroot_options(''), undef, 'command-time validation accepts an empty value');
is(xCAT::SvrUtils->validate_statelite_nfsroot_options('noac,actimeo=0'), undef, 'command-time validation accepts valid options');
ok(
scalar(grep { $_ eq 'nfsrootopts' } @{ $xCAT::Schema::tabspec{osimage}->{cols} }),
'osimage table includes nfsrootopts'
);
is(
$xCAT::Schema::defspec{osimage}->{attrhash}->{nfsrootopts}->{tabentry},
'osimage.nfsrootopts',
'osimage object exposes nfsrootopts'
);
foreach my $plugin (qw(anaconda debian sles)) {
my $path = "$FindBin::Bin/../../xCAT-server/lib/xcat/plugins/$plugin.pm";
open(my $fh, '<', $path) or die "Unable to read $path: $!";
my $source = do { local $/; <$fh> };
close($fh);
like($source, qr/build_statelite_nfsroot_parameter/, "$plugin statelite renderer uses the shared NFS-root builder");
like($source, qr/'rootfstype',\s*'nfsrootopts'/, "$plugin reads nfsrootopts with the statelite root type");
}
done_testing();