2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-05 12:37:54 +00:00
Files
xcat-core/perl-xCAT/xCAT/ProfiledNodeUtils.pm
T
Vinícius Ferrão 76a44422d5 feat(perl-xCAT): recognize riscv64 as a node and osimage architecture
riscv64 nodes boot through UEFI and grub2 only, like ppc64le PowerKVM
guests and aarch64. Teach the three places that declare which
noderes.netboot methods an architecture accepts about it:

- xCAT::Utils::lookupNetboot returns grub2,grub2-tftp,grub2-http for
  riscv64 so nodeset and rinstall accept those methods.
- the profiled-node rule table in xCAT::ProfiledNodeUtils defaults
  riscv64 nodes to grub2.
- the nodetype.arch, osimage.osarch and noderes.netboot schema
  descriptions document riscv64.

The arch token is riscv64 everywhere (rpm, dpkg and uname -m agree), so
no alias handling is added.
2026-09-01 10:50:18 -03:00

1588 lines
54 KiB
Perl

# IBM(c) 2012 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::ProfiledNodeUtils;
use strict;
use warnings;
use Socket;
use File::Path qw/mkpath/;
use File::Temp qw/tempfile/;
use Fcntl qw(:flock);
require xCAT::Table;
require xCAT::TableUtils;
require xCAT::NodeRange;
require xCAT::NetworkUtils;
require xCAT::DBobjUtils;
#--------------------------------------------------------------------------------
=head1 xCAT::ProfiledNodeUtils
=head2 Package Description
This program module file, is a set of node management utilities for Profile based nodes.
=cut
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
=head3 get_allocable_staticips_innet
Description : Get allocable IPs from a network.
Arguments : $netname - network name
$exclude_ips_ref - excluded IPs list reference.
Returns : Reference of allocable IPs list
=cut
#-------------------------------------------------------------------------------
sub get_allocable_staticips_innet
{
my $class = shift;
my $netname = shift;
my $exclude_ips_ref = shift;
my %iphash;
my @allocableips;
foreach (@$exclude_ips_ref) {
$iphash{$_} = 0;
}
my $networkstab = xCAT::Table->new('networks');
my $netentry = ($networkstab->getAllAttribsWhere("netname = '$netname'", 'ALL'))[0];
my ($startip, $endip) = split('-', $netentry->{'staticrange'});
my $incremental = $netentry->{'staticrangeincrement'};
my $netmask = $netentry->{'mask'};
my $gateway = $netentry->{'gateway'};
my $validipsref;
if ($incremental and $startip and $endip) {
$validipsref = xCAT::NetworkUtils->get_allips_in_range($startip, $endip, $incremental);
}
my $broadcastip = xCAT::NetworkUtils->getBroadcast($startip, $netmask);
foreach (@$validipsref) {
#Remove ip which is broadcast ip, exclude ip, ips ended with 0, gateway ip
if (exists($iphash{$_}) or $_ eq $broadcastip or $_ eq $gateway
or $_ =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(0)$/) {
next;
}
push @allocableips, $_;
}
return \@allocableips;
}
#-------------------------------------------------------------------------------
=head3 genhosts_with_numric_tmpl
Description : Generate numric hostnames using numric template name.
Arguments : $format - The hostname format string..
$rank - The start number.
$amount - The total hostname number to be generated.
Returns : numric hostname list
Example :
calling genhosts_with_numric_tmpl("compute#NNnode") will return a list like:
("compute00node", "compute01node", ..."compute98node", "compute99node")
=cut
#-------------------------------------------------------------------------------
sub genhosts_with_numric_tmpl
{
my ($class, $format, $rank, $amount) = @_;
my ($prefix, $appendix, $len) = xCAT::ProfiledNodeUtils->split_hostname($format, 'N');
return xCAT::ProfiledNodeUtils->gen_numric_hostnames($prefix, $appendix, $len, $rank, $amount);
}
#-------------------------------------------------------------------------------
=head3 split_hostname
Description : Split hostname format as prefix, appendix and number length.
Arguments : $format - hostname format
$patt_char - pattern char, we always use "N" to indicate numric pattern
Returns : ($prefix, $appendix, $numlen)
$prefix - the prefix string of hostname format.
$appendix - the appendix string of hostname format
$numlen - The number length in hostname format.
Example :
calling split_hostname("compute#NNnode") will return a list like:
("compute", "node", 2)
=cut
#-------------------------------------------------------------------------------
sub split_hostname
{
my ($class, $format, $patt_char) = @_;
my $idx = index $format, "#$patt_char";
my @array_format = split(//, $format);
my $pos = $idx + 2;
while ($pos <= (scalar(@array_format) - 1)) {
if ($array_format[$pos] eq "$patt_char") {
$pos++;
} else {
last;
}
}
my $ridx = $pos - 1;
my $prefix = "";
$prefix = substr $format, 0, $idx;
my $appendix = "";
if (($ridx + 1) != scalar(@array_format)) {
$appendix = substr $format, $ridx + 1;
}
return $prefix, $appendix, ($ridx - $idx);
}
#-------------------------------------------------------------------------------
=head3 gen_numric_hostnames
Description : Generate numric hostnames.
Arguments : $prefix - The prefix string of the hostname.
$appendix - The appendix string of the hostname.
$len - the numric number length in hostname.
$rank - the start number for numric part
$amount - the amount of hostnames to be generated.
Returns : numric hostname list
Example :
calling gen_numric_hostnames("compute", "node",2) will return a list like:
("compute00node", "compute01node", ..."compute98node", "compute99node")
=cut
#-------------------------------------------------------------------------------
sub gen_numric_hostnames
{
my ($class, $prefix, $appendix, $len, $rank, $amount) = @_;
my @hostnames;
my $cnt = 0;
if ($rank) {
$cnt = $rank;
}
my $maxnum = 10**$len;
while ($cnt < $maxnum)
{
my $fullnum = $maxnum + $cnt;
my $hostname = $prefix . (substr $fullnum, 1) . $appendix;
push(@hostnames, $hostname);
if ($amount && (@hostnames == $amount)) {
last;
}
$cnt++;
}
return \@hostnames;
}
#-------------------------------------------------------------------------------
=head3 get_hostname_format_type
Description : Get hostname format type.
Arguments : $format - hostname format
Returns : hostname format type value:
"numric" - numric hostname format.
"rack" - rack info hostname format.
Example :
calling get_hostname_format_type("compute#NNnode") will return "numric"
calling get_hostname_format_type("compute-#RR-#NN") will return "rack"
=cut
#-------------------------------------------------------------------------------
sub get_hostname_format_type {
my ($class, $format) = @_;
my $type;
my ($prefix, $appendix, $rlen, $nlen);
my $ridx = index $format, "#R";
my $nidx = index $format, "#N";
my $simpname = "";
if ($ridx >= 0) {
($prefix, $appendix, $rlen) = xCAT::ProfiledNodeUtils->split_hostname($format, 'R');
$simpname = $prefix . "0" . $appendix;
($prefix, $appendix, $nlen) = xCAT::ProfiledNodeUtils->split_hostname($simpname, 'N');
$simpname = $prefix . "0" . $appendix;
if ($rlen >= 10 || $nlen >= 10 || $nlen == 0) {
$type = "unknown";
} else {
$type = "rack";
}
} elsif ($nidx >= 0) {
($prefix, $appendix, $nlen) = xCAT::ProfiledNodeUtils->split_hostname($format, 'N');
$simpname = $prefix . "0" . $appendix;
if ($nlen >= 10) {
$type = "unknown";
} else {
$type = "numric";
}
} else {
$type = "unknown";
}
# validate whether hostname format includes other invalid characters.
if ($type ne "unknown") {
if (!xCAT::NetworkUtils->isValidHostname($simpname)) {
$type = "unknown";
}
}
return $type;
}
#-------------------------------------------------------------------------------
=head3 rackformat_to_numricformat
Description : convert rack hostname format into numric hostname format.
Arguments : $format - rack hostname format
$racknum - rack number.
Returns : numric hostname format.
Example :
calling rackformat_to_numricformat("compute-#RR-#NN", 1) will return "compute-01-#NN"
=cut
#-------------------------------------------------------------------------------
sub rackformat_to_numricformat {
my ($class, $format, $rackname) = @_;
my ($prefix, $appendix, $len) = xCAT::ProfiledNodeUtils->split_hostname($format, 'R');
my %objhash = xCAT::DBobjUtils->getobjdefs({ $rackname, "rack" });
my $racknum = $objhash{$rackname}{"num"};
my $maxnum = 10**$len;
if ($racknum >= $maxnum) {
return undef;
}
my $fullnum = $maxnum + $racknum;
return $prefix . (substr $fullnum, 1) . $appendix;
}
#-------------------------------------------------------------------------------
=head3 get_nodes_nic_attrs
Description : Get nodes NIC attributes and return a dict.
Arguments : $nodelist - nodes list ref.
Returns : A hash ref of %nicsattrs for node's nics attributes.
keys of %nicsattrs are node names.
values of %nicsattrs are nics attrib ref.
For each nic attrib ref, the keys are nic names, like: ib0, eth0, bmc...
values are attributes of a specific nic, like:
type : nic type
hostnamesuffix: hostname suffix
hostnameprefix: hostname prefix
customscript: custom script for this nic
network: network name for this nic
ip: ip address of this nic.
=cut
#-------------------------------------------------------------------------------
sub get_nodes_nic_attrs {
my $class = shift;
my $nodes = shift;
my $nicstab = xCAT::Table->new('nics');
my $entry = $nicstab->getNodesAttribs($nodes, [ 'nictypes', 'nichostnamesuffixes', 'nichostnameprefixes', 'niccustomscripts', 'nicnetworks', 'nicips', 'nicextraparams' ]);
my %nicsattrs;
my @nicattrslist;
foreach my $node (@$nodes) {
if ($entry->{$node}->[0]->{'nictypes'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'nictypes'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'type'} = $nicattrs[1];
}
}
if ($entry->{$node}->[0]->{'nichostnamesuffixes'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'nichostnamesuffixes'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'hostnamesuffix'} = $nicattrs[1];
}
}
if ($entry->{$node}->[0]->{'nichostnameprefixes'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'nichostnameprefixes'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'hostnameprefix'} = $nicattrs[1];
}
}
if ($entry->{$node}->[0]->{'niccustomscripts'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'niccustomscripts'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'customscript'} = $nicattrs[1];
}
}
if ($entry->{$node}->[0]->{'nicnetworks'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'nicnetworks'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'network'} = $nicattrs[1];
}
}
if ($entry->{$node}->[0]->{'nicips'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'nicips'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'ip'} = $nicattrs[1];
}
}
if ($entry->{$node}->[0]->{'nicextraparams'}) {
@nicattrslist = split(",", $entry->{$node}->[0]->{'nicextraparams'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
$nicsattrs{$node}{ $nicattrs[0] }{'extraparams'} = $nicattrs[1];
}
}
}
return \%nicsattrs;
}
#-------------------------------------------------------------------------------
=head3 get_netprofile_bmcnet
Description : Get bmc network name of a network profile.
Arguments : $nettmpl - network profile name
Returns : bmc network name of this network profile.
=cut
#-------------------------------------------------------------------------------
sub get_netprofile_bmcnet {
my ($class, $netprofilename) = @_;
my $netprofile_nicshash_ref = xCAT::ProfiledNodeUtils->get_nodes_nic_attrs($netprofilename)->{$netprofilename};
my %netprofile_nicshash = %$netprofile_nicshash_ref;
if (exists $netprofile_nicshash{'bmc'}{"network"}) {
return $netprofile_nicshash{'bmc'}{"network"}
} else {
return undef;
}
}
#-------------------------------------------------------------------------------
=head3 get_netprofile_provisionnet
Description : Get deployment network of a network profile.
Arguments : $nettmpl - network profile name
Returns : deployment network name of this network profile.
=cut
#-------------------------------------------------------------------------------
sub get_netprofile_provisionnet {
my ($class, $netprofilename) = @_;
my $netprofile_nicshash_ref = xCAT::ProfiledNodeUtils->get_nodes_nic_attrs([$netprofilename])->{$netprofilename};
my %netprofile_nicshash = %$netprofile_nicshash_ref;
my $restab = xCAT::Table->new('noderes');
my $installnicattr = $restab->getNodeAttribs($netprofilename, ['installnic']);
my $installnic = $installnicattr->{'installnic'};
if ($installnic) {
if (exists $netprofile_nicshash{$installnic}{"network"}) {
return $netprofile_nicshash{$installnic}{"network"}
}
}
return undef;
}
#-------------------------------------------------------------------------------
=head3 get_output_filename
Description : Generate a temp file name for placing output details for profiled node management operations.
We make this file generated under /install/ so that clients can access it through http.
Arguments : N/A
Returns : A temp filename placed under /install/pcm/work/
=cut
#-------------------------------------------------------------------------------
sub get_output_filename
{
my $installdir = xCAT::TableUtils->getInstallDir();
my $pcmworkdir = $installdir . "/pcm/work/";
if (!-d $pcmworkdir)
{
mkpath($pcmworkdir);
}
return tempfile("hostinfo_result_XXXXXXX", DIR => $pcmworkdir);
}
#-------------------------------------------------------------------------------
=head3 get_all_chassis
Description : Get all chassis in system.
Arguments : hashref: if not set, return a array ref.
if set, return a hash ref.
type : "all", get all chassis,
"cmm", get all chassis whose type is cmm
if type not specify, it is 'all'
Returns : ref for chassis list.
Example :
my $arrayref = xCAT::ProfiledNodeUtils->get_all_chassis();
my $hashref = xCAT::ProfiledNodeUtils->get_all_chassis(1);
my $hashref = xCAT::ProfiledNodeUtils->get_all_chassis(1, 'cmm');
=cut
#-------------------------------------------------------------------------------
sub get_all_chassis
{
my $class = shift;
my $hashref = shift;
my $type = shift;
my %chassishash;
my %chassistype = ('all' => '__Chassis', 'cmm' => '__Chassis_IBM_Flex_chassis');
if (not $type) {
$type = 'all';
}
my @chassis = xCAT::NodeRange::noderange($chassistype{$type});
if ($hashref) {
foreach (@chassis) {
$chassishash{$_} = 1;
}
return \%chassishash;
} else {
return \@chassis;
}
}
#-------------------------------------------------------------------------------
=head3 get_all_rack
Description : Get all rack in system.
Arguments : hashref: if not set, return a array ref.
if set, return a hash ref.
Returns : ref for rack list.
Example :
my $arrayref = xCAT::ProfiledNodeUtils->get_all_rack();
my $hashref = xCAT::ProfiledNodeUtils->get_all_rack(1);
=cut
#-------------------------------------------------------------------------------
sub get_all_rack
{
my $class = shift;
my $hashref = shift;
my %rackhash = ();
my @racklist = ();
my $racktab = xCAT::Table->new('rack');
my @racks = $racktab->getAllAttribs(('rackname'));
foreach (@racks) {
if ($_->{'rackname'}) {
if ($hashref) {
$rackhash{ $_->{'rackname'} } = 1;
} else {
push @racklist, $_->{'rackname'};
}
}
}
if ($hashref) {
return \%rackhash;
} else {
return \@racklist;
}
}
#-------------------------------------------------------------------------------
=head3 get_racks_for_chassises
Description : Get rack info for a chassis list.
Arguments : $chassislistref - chassis list reference.
Returns : A dict ref. keys are chassis name, values are rack name for each chassis.
=cut
#-------------------------------------------------------------------------------
sub get_racks_for_chassises
{
my $class = shift;
my $chassislistref = shift;
my %rackinfodict = ();
my $nodepostab = xCAT::Table->new('nodepos');
my $racksref = $nodepostab->getNodesAttribs($chassislistref, ['rack']);
foreach (@$chassislistref) {
$rackinfodict{$_} = $racksref->{$_}->[0]->{'rack'};
}
return \%rackinfodict;
}
#-------------------------------------------------------------------------------
=head3 get_allnode_singleattrib_hash
Description : Get all records of a column from a table, then return a hash.
The return hash's keys are the records of this attribute
and values are all set as 1.
Arguments : $tabname - the table name.
$attr - the attribute name.
Returns : Reference of the records hash.
=cut
#-------------------------------------------------------------------------------
sub get_allnode_singleattrib_hash
{
my $class = shift;
my $tabname = shift;
my $attr = shift;
my $table = xCAT::Table->new($tabname);
my @entries = $table->getAllNodeAttribs([$attr]);
my %allrecords;
foreach (@entries) {
if ($_->{$attr}) {
$allrecords{ $_->{$attr} } = 0;
}
}
return \%allrecords;
}
#-------------------------------------------------------------------------------
=head3 get_db_swtiches
Description : Get all records of switch config from a table, then return a string list.
Arguments : $tabname - the table name.
Returns : Reference of the records hash.
=cut
#-------------------------------------------------------------------------------
sub get_db_switches
{
my $class = shift;
my $table = xCAT::Table->new("switches");
my @attribs = ("switch");
my @entries = $table->getAllAttribs(@attribs);
$table->close();
my %allrecords;
foreach (@entries)
{
if ($_->{'switch'}) {
$allrecords{ $_->{'switch'} } = 0;
}
}
return \%allrecords;
}
#-------------------------------------------------------------------------------
=head3 get_db_swtichports
Description : Get all records of switch config from a table, then return a string list.
Arguments : $tabname - the table name.
Returns : Reference of the records hash.
=cut
#-------------------------------------------------------------------------------
sub get_db_switchports
{
my $class = shift;
my $table = xCAT::Table->new("switch");
my @attribs = ("switch", "port");
my @entries = $table->getAllAttribs(@attribs);
$table->close();
my %allrecords;
foreach (@entries)
{
$allrecords{ $_->{'switch'} . "_" . $_->{'port'} } = 0;
}
return \%allrecords;
}
#-------------------------------------------------------------------------------
=head3 get_all_cecs
Description : Get all CEC objects name in system.
Arguments : hashref: if not set, return a array ref.
if set, return a hash ref.
Returns : ref for CECs list.
Example :
my $arrayref = xCAT::ProfiledNodeUtils->get_all_cecs();
my $hashref = xCAT::ProfiledNodeUtils->get_all_cecs(1);
=cut
#-------------------------------------------------------------------------------
sub get_all_cecs
{
my $hashref = shift;
my %cecshash;
my @cecslist;
my $ppctab = xCAT::Table->new('ppc');
my @cecs = $ppctab->getAllAttribsWhere("nodetype = 'cec'", 'node');
foreach (@cecs) {
if ($_->{'node'}) {
if ($hashref) {
$cecshash{ $_->{'node'} } = 1;
} else {
push @cecslist, $_->{'node'};
}
}
}
$ppctab->close();
# Return the ref accordingly
if ($hashref) {
return \%cecshash;
} else {
return \@cecslist;
}
}
#-------------------------------------------------------------------------------
=head3 get_all_lparids
Description : Get all LPAR ids in system.
Arguments : ref of all cecs
Returns : ref for LPAR ids hash.
Example :
my $arrayref = xCAT::ProfiledNodeUtils->get_all_lparids(\%allcecs);
=cut
#-------------------------------------------------------------------------------
sub get_all_lparids
{
my $class = shift;
my $cecsref = shift;
my %allcecs = %$cecsref;
my %lparids;
my $ppctab = xCAT::Table->new('ppc');
foreach my $cec (keys %allcecs) {
my @ids = $ppctab->getAllAttribsWhere("hcp = '$cec'", 'id');
foreach (@ids) {
if ($_->{'id'}) {
$lparids{$cec}{ $_->{'id'} } = 0;
}
}
}
$ppctab->close();
return \%lparids;
}
#-------------------------------------------------------------------------------
=head3 is_discover_started
Description : Judge whether profiled nodes discovering is running or not.
Arguments : NA
Returns : 1 - Discover is running
0 - Discover is not started.
=cut
#-------------------------------------------------------------------------------
sub is_discover_started
{
my @sitevalues = xCAT::TableUtils->get_site_attribute("__PCMDiscover");
if (!$sitevalues[0]) {
return 0;
}
return 1;
}
#-------------------------------------------------------------------------------
=head3 get_node_profiles
Description : Get nodelist's profile and return a hash ref.
Arguments : node list.
Returns : nodelist's profile hash.
keys are node names.
values are hash ref. This hash ref is placing the node's profile information:
keys can be followings: "NetworkProfile", "ImageProfile", "HardwareProfile"
values are the profile names.
=cut
#-------------------------------------------------------------------------------
sub get_nodes_profiles
{
my $class = shift;
my $nodelistref = shift;
my $groupnamemode = shift;
my %profile_dict;
my $nodelisttab = xCAT::Table->new('nodelist');
my $groupshashref = $nodelisttab->getNodesAttribs($nodelistref, ['groups']);
my %groupshash = %$groupshashref;
foreach (keys %groupshash) {
my $value = $groupshash{$_};
my $groups = $value->[0]->{'groups'};
# groups looks like "__Managed,__NetworkProfile_default_cn,__ImageProfile_rhels6.3-x86_64-install-compute"
my @grouplist = split(',', $groups);
my @profilelist = ("NetworkProfile", "ImageProfile", "HardwareProfile");
foreach my $group (@grouplist) {
foreach my $profile (@profilelist) {
my $idx = index($group, $profile);
# The Group starts with __, so index will be 2.
if ($idx == 2) {
# The group string will like @NetworkProfile_<profile name>
# So, index should +3, 2 for '__', 1 for _.
if ($groupnamemode) {
$profile_dict{$_}{$profile} = $group;
} else {
my $append_index = length($profile) + 3;
$profile_dict{$_}{$profile} = substr $group, $append_index;
}
last;
}
}
}
}
return \%profile_dict;
}
#-------------------------------------------------------------------------------
=head3 get_imageprofile_prov_method
Description : Get A node's provisioning method from its imageprofile attribute.
Arguments : $imgprofilename - imageprofile name
Returns : node's provisioning method: install, netboot...etc
=cut
#-------------------------------------------------------------------------------
sub get_imageprofile_prov_method
{
# For imageprofile, we can get node's provisioning method through:
# nodetype table: node (imageprofile name), provmethod (osimage name)
# osimage table: imagename (osimage name), provmethod (node deploy method: install, netboot...)
my $class = shift;
my $imgprofilename = shift;
my $nodetypestab = xCAT::Table->new('nodetype');
my $entry = ($nodetypestab->getAllAttribsWhere("node = '$imgprofilename'", 'ALL'))[0];
return $entry->{'provmethod'};
#my $osimgtab = xCAT::Table->new('osimage');
#my $osimgentry = ($osimgtab->getAllAttribsWhere("imagename = '$osimgname'", 'ALL' ))[0];
#return $osimgentry->{'provmethod'};
}
#-------------------------------------------------------------------------------
=head3 get_imageprofile_prov_osvers
Description : Get A node's provisioning os version and profile from its imageprofile attribute.
Arguments : $imgprofilename - imageprofile name
Returns : node's osversion and profile
=cut
#-------------------------------------------------------------------------------
sub get_imageprofile_prov_osvers
{
my $class = shift;
my $imgprofilename = shift;
my $osimgtab = xCAT::Table->new('osimage');
my $osimgentry = ($osimgtab->getAllAttribsWhere("imagename = '$imgprofilename'", 'ALL'))[0];
my $osversion = $osimgentry->{'osvers'};
my $profile = $osimgentry->{'profile'};
return ($osversion, $profile);
}
#-------------------------------------------------------------------------------
=head3 check_profile_consistent
Description : Check if three profile consistent
Arguments : $imageprofile - image profile name
$networkprofile - network profile name
$hardwareprofile - harware profile name
Returns : returncode, errmsg - consistent
returncode=1 - consistent
returncode=0 - not consistent
=cut
#-------------------------------------------------------------------------------
sub check_profile_consistent {
my $class = shift;
my $imageprofile = shift;
my $networkprofile = shift;
my $hardwareprofile = shift;
# Check the profiles are existing in DB.
my @nodegrps = xCAT::TableUtils->list_all_node_groups();
unless (grep { $_ eq $imageprofile } @nodegrps) {
return 0, "Image profile not defined in DB."
}
unless (grep { $_ eq $networkprofile } @nodegrps) {
return 0, "Network profile not defined in DB."
}
if ($hardwareprofile) {
unless (grep { $_ eq $hardwareprofile } @nodegrps) {
return 0, "Hardware profile not defined in DB."
}
}
# Get Imageprofile arch
my $nodetypetab = xCAT::Table->new('nodetype');
my $nodetypeentry = $nodetypetab->getNodeAttribs($imageprofile, [ 'os', 'arch' ]);
my $os = $nodetypeentry->{'os'};
my $arch = $nodetypeentry->{'arch'};
$nodetypetab->close();
# Get Imageprofile pkgdir
my $osdistroname = $os . "-" . $arch;
my $osdistrotab = xCAT::Table->new('osdistro');
my $osdistroentry = ($osdistrotab->getAllAttribsWhere("osdistroname = '$osdistroname'", 'ALL'))[0];
my $pkgdir = $osdistroentry->{'dirpaths'};
$osdistrotab->close();
# Get networkprofile netboot and installnic
my $noderestab = xCAT::Table->new('noderes');
my $noderesentry = $noderestab->getNodeAttribs($networkprofile, [ 'netboot', 'installnic' ]);
my $netboot = $noderesentry->{'netboot'};
my $installnic = $noderesentry->{'installnic'};
$noderestab->close();
# Get networkprofile nictypes
my $netprofile_nicshash_ref = xCAT::ProfiledNodeUtils->get_nodes_nic_attrs([$networkprofile])->{$networkprofile};
my %netprofile_nicshash = %$netprofile_nicshash_ref;
my $nictype = undef;
foreach (keys %netprofile_nicshash) {
my $value = $netprofile_nicshash{$_}{'type'};
if (($value eq 'FSP') or ($value eq 'BMC')) {
$nictype = $value;
}
}
#Get hardwareprofile mgt
my $nodehmtab = xCAT::Table->new('nodehm');
my $mgtentry = $nodehmtab->getNodeAttribs($hardwareprofile, ['mgt']);
my $mgt = undef;
$mgt = $mgtentry->{'mgt'} if ($mgtentry->{'mgt'});
$nodehmtab->close();
#Get hardwareprofile nodetype
my $ppctab = xCAT::Table->new('ppc');
my $ntentry = $ppctab->getNodeAttribs($hardwareprofile, ['nodetype']);
my $nodetype = undef;
$nodetype = $ntentry->{'nodetype'} if ($ntentry->{'nodetype'});
$ppctab->close();
# Checking whether netboot initrd image for Ubuntu ppc64
# This image should be downloaded from internet
if ($arch =~ /ppc64/i and $os =~ /ubuntu/i and !(-e "$pkgdir/install/netboot/initrd.gz")) {
return 0, "The netboot initrd is not found in $pkgdir/install/netboot, please download it firstly.";
}
# Check if exists provision network
if (not($installnic and exists $netprofile_nicshash{$installnic}{"network"})) {
return 0, "Provisioning network not defined for network profile."
}
# Remove check mechanism about arch and netboot attribute
# Attribute 'neboot' will be generated based on arch, management method, os
# Profile consistent keys, arch=>netboot, mgt=>nictype
#my $ppc_netboot = 'yaboot';
#if( $os =~ /rhels7/ ){
# $ppc_netboot = 'grub2';
#}
#my %profile_dict = ('x86' => 'xnba','x86_64' => 'xnba', 'ppc64' => $ppc_netboot,
# 'ppc64el' => $ppc_netboot,
# 'fsp' => 'FSP', 'ipmi' => 'BMC');
# Check if imageprofile is consistent with networkprofile
#if ($profile_dict{$arch} ne $netboot) {
# return 0, "Imageprofile's arch is not consistent with networkprofile's netboot."
#}
# Check if networkprofile is consistent with hardwareprofile
if (not $hardwareprofile) { # Not define hardwareprofile
if (not $nictype) { # Networkprofile is not fsp or bmc
return 1, "";
} elsif ($nictype eq 'FSP' or $nictype eq 'BMC') {
return 0, "$nictype networkprofile must use with hardwareprofile.";
}
}
my %mgt_dict = ('fsp' => 'FSP', 'ipmi' => 'BMC', 'kvm' => '');
if ($mgt eq 'vm') {
return 1, "";
}
if ($nodetype eq 'lpar') {
if ($nictype) {
# Can not associate FSP/BMC network if the node type is lpar
return 0, "The node with hardware type $nodetype can not use with $nictype networkprofile.";
}
return 1, ""
}
if ($mgt and $mgt_dict{$mgt} ne $nictype) {
my $errmsg = "$mgt hardwareprofile must use with $mgt_dict{$mgt} networkprofile.";
if ($mgt eq 'kvm') {
$errmsg = "$mgt hardwareprofile must use with non-BMC and non-FSP networkprofile."
}
return 0, $errmsg;
}
return 1, "";
}
#-------------------------------------------------------------------------------
=head3 is_fsp_node
Description : Judge whether nodes use fsp.
Arguments : $node - node name
Returns : 1 - Use fsp
0 - Not use fsp
=cut
#-------------------------------------------------------------------------------
sub is_fsp_node
{
my $class = shift;
my $node = shift;
my $nicstab = xCAT::Table->new('nics');
my $entry = $nicstab->getNodeAttribs($node, ['nictypes']);
$nicstab->close();
if ($entry->{'nictypes'}) {
my @nicattrslist = split(",", $entry->{'nictypes'});
foreach (@nicattrslist) {
my @nicattrs;
if ($_ =~ /!/) {
@nicattrs = split("!", $_);
} else {
@nicattrs = split(":", $_);
}
if ($nicattrs[1] eq 'FSP') {
return 1;
}
}
}
return 0;
}
#-------------------------------------------------------------------------------
=head3 is_kvm_node
Description : Judge whether nodes are KVM nodes.
Arguments : $hardwareprofile - hardwareprofile name
Returns : 1 - KVM nodes
0 - Not KVM nodes
=cut
#-------------------------------------------------------------------------------
sub is_kvm_node
{
my $class = shift;
my $hardwareprofile = shift;
if (not $hardwareprofile) {
return 0;
}
#Get hardwareprofile mgt
my $nodehmtab = xCAT::Table->new('nodehm');
my $mgtentry = $nodehmtab->getNodeAttribs($hardwareprofile, ['mgt']);
my $mgt = undef;
$mgt = $mgtentry->{'mgt'} if ($mgtentry->{'mgt'});
$nodehmtab->close();
if ($mgt eq 'kvm') {
return 1;
}
return 0;
}
#-------------------------------------------------------------------------------
=head3 is_kvm_hypv_node
Description : Judge whether nodes are KVM nodes.
Arguments : $imageprofile - imageprofile name
Returns : 1 - KVM hypervisor nodes
0 - Not KVM hypervisor nodes
=cut
#-------------------------------------------------------------------------------
sub is_kvm_hypv_node
{
my $class = shift;
my $imageprofile = shift;
# Get provmethod
my $provmethod = xCAT::ProfiledNodeUtils->get_imageprofile_prov_method($imageprofile);
unless ($provmethod) {
return 0;
}
my $osimage_tab = xCAT::Table->new('osimage');
my $osimage_tab_entry = $osimage_tab->getAttribs({ 'imagename' => $provmethod }, ('osdistroname'));
my $osdistroname = $osimage_tab_entry->{'osdistroname'};
$osimage_tab->close();
if ($osdistroname and $osdistroname =~ /^pkvm/) {
return 1;
}
return 0;
}
#-------------------------------------------------------------------------------
=head3 get_nodes_cmm
Description : Get the CMM of nodelist
Arguments : $nodelist - the ref of node list array
Returns : $cmm - the ref of hash like
{
"cmm1" => 1,
"cmm2" => 1
}
=cut
#-------------------------------------------------------------------------------
sub get_nodes_cmm
{
my $class = shift;
my $nodelistref = shift;
my @nodes = @$nodelistref;
my %returncmm;
my $mptab = xCAT::Table->new('mp');
my $entry = $mptab->getNodesAttribs($nodelistref, ['mpa']);
$mptab->close();
foreach (@nodes) {
my $mpa = $entry->{$_}->[0]->{'mpa'};
if ($mpa and not exists $returncmm{$mpa}) {
$returncmm{$mpa} = 1;
}
}
return \%returncmm
}
#-------------------------------------------------------------------------------
=head3 parse_nodeinfo_file
Description: Parse node info file content. And put node info into 2 global
vals: @::profiledNodeObjNames and %::profiledNodeAttrs.
@::profiledNodeObjNames: recording all nodes' names.
%::profiledNodeAttrs: recording all nodes' attributes.
Arguments: $filedata: node info file content string.
Returns: ($retcode, $msgstr).
$retcode = 1. Parse success, the format of this file is OK.
$retcode = 0. Parse failed, there are some errors in this file.
Detailed errors will be set in $msgstr.
=cut
#-------------------------------------------------------------------------------
sub parse_nodeinfo_file
{
my ($class, $filedata) = @_;
@::profiledNodeObjNames = ();
%::profiledNodeAttrs = ();
my @lines = split /\n/, $filedata;
my $obj_found = 0;
my $attr_found = 0;
my $null_obj;
my ($objname, $append);
foreach my $line (@lines) {
# skip blank and comment lines
next if ($line =~ /^\s*$/ || $line =~ /^\s*#/);
# The line ends with :
if (grep(/:\s*$/, $line)) {
$attr_found = 0;
$null_obj = $line;
($objname, $append) = split(/:/, $line);
$objname =~ s/^\s*//; # Remove any leading whitespace
$objname =~ s/\s*$//; # Remove any trailing whitespace
# OK we've found one object.
if ($objname) {
$obj_found = 1;
push(@::profiledNodeObjNames, $objname);
} else {
return 0, "No node name defined in line \'$line\'";
}
} # The line has =
elsif (($line =~ /^\s*(.*?)\s*=\s*(.*)\s*/)) {
# No one object clarified yet. So this file format is illegal.
if (!$obj_found) {
return 0, "No node defined before line \'$line\'";
}
$attr_found = 1;
my $attr = $1;
my $val = $2;
$attr =~ s/^\s*//; # Remove any leading whitespace
$attr =~ s/\s*$//; # Remove any trailing whitespace
$val =~ s/^\s*//;
$val =~ s/\s*$//;
# remove spaces and quotes
$val =~ s/^\s*"\s*//;
$val =~ s/\s*"\s*$//;
if ($attr && $val) {
$::profiledNodeAttrs{$objname}{$attr} = $val;
} else {
return 0, "Line \'$line\' does not contain a valid key and value";
}
} #invalid line.
else {
return 0, "Invalid Line \'$line\' found";
}
}
# Defined object has no attributes
if (!$attr_found) {
return 0, "Invalid Line \'$null_obj\' found";
}
return 1, "";
}
#-------------------------------------------------------
=head3 update the table prodkey, in order to support windows
per node license key
Returns: $retcode.
$retcode = 1. update failed, the value is undef
$retcode = 0. save into db is OK..
=cut
#-------------------------------------------------------
sub update_windows_prodkey
{
my $class = shift;
my $node = shift;
my $product = shift;
my $key = shift;
unless (defined($node) && defined($product) && defined($key))
{
return 1;
}
# please notice this db usage
my %keyhash;
my %updates;
$keyhash{'node'} = $node;
$updates{'product'} = $product;
$updates{'key'} = $key;
my $tab = xCAT::Table->new('prodkey', -create => 1, -autocommit => 0);
$tab->setAttribs(\%keyhash, \%updates);
$tab->commit;
$tab->close;
return 0;
}
#-------------------------------------------------------------------------------
=head3 check_nicips
Description: Check if the nicips defined in MAC file is correct
format
Arguments: $installnic: the installnic defined in networkprofile
$netprofileattrsref: the attributes of all nics in networkprofile
$freeipshash: the hash of networks' staticrange
$nicips: the string of nicips defined in MAC file
Returns: ($retcode, $output, $errmsg).
$retcode = 1. Parse failed, there are some errors in nicips string. Detailed errors will be set in $errmsg.
$retcode = 0. Parse success, the format of nicips is OK..
=cut
#-------------------------------------------------------------------------------
sub check_nicips {
my $class = shift;
my $installnic = shift;
my $netprofileattrsref = shift;
my $freeipshash = shift;
my $othernics = shift;
my $errmsg = "";
my %nics_hash = ();
my %netprofileattr = %$netprofileattrsref;
foreach my $nic_ips (split(/,/, $othernics)) {
my @nic_and_ips = ();
my $nic = "";
my $nic_ip = "";
if ($nic_ips =~ /!/ and $nic_ips !~ /!$/) {
@nic_and_ips = split(/!/, $nic_ips);
my $len = @nic_and_ips;
$nic = $nic_and_ips[0];
$nic_ip = $nic_and_ips[1];
if (exists $nics_hash{$nic} or $len != 2) {
$errmsg = "The specified nicips is incorrect. It must be formatted correctly, in the form: <nic1>!<nic-ip1>,<nic2>!<nic-ip2>,...";
return (1, "", $errmsg);
}
# Check whether other interfaces contain provision nic
if ($nic eq $installnic) {
$errmsg = "The specified nicips cannot contain NICs used for provisioning.";
return (1, "", $errmsg);
}
# Check whether this interface is defined in networkprofile
unless (exists $netprofileattr{$nic}) {
$errmsg = "The specified nicips contains NICs that are not defined in the network profile.";
return (1, "", $errmsg);
}
# Check whether specified IP is in each network's static range
my $nicnetwork = $netprofileattr{$nic}{'network'};
my $freeipsref = $freeipshash->{$nicnetwork};
unless (grep { $_ eq $nic_ip } @$freeipsref) {
$errmsg = "Specified IP address $nic_ip not in static range of network $netprofileattr{$nic}{'network'}";
return (1, "", $errmsg);
}
} else {
$errmsg = "The specified nicips is incorrect. It must be formatted correctly, in the form: <nic1>!<nic-ip1>,<nic2>!<nic-ip2>,...";
return (1, "", $errmsg);
}
$nics_hash{$nic} = $nic_ip;
}
return (0, \%nics_hash, "");
}
#-------------------------------------------------------------------------------
=head3 gen_chain_for_profiles
Description: Generate a chain string based on Network/Hardware/Image profiles.
Arguments: $profiles_hash: The reference for profiles hash.
For example:
$profiles_hash = { 'HardwareProfile' => 'IBM_NeXtScale_M4',
'ImageProfile' => 'rhels6.5-x86_64-stateful-compute',
'NetworkProfile' => 'default_network_profile',
}
$hw_reconfig: the flag shows whether we need re-configure all hardware
relative settings or not: like runcmds, runimg...etc
Returns: ($retcode, $chain)
$retcode = 1. Generate chain failed, $chain stands for error message.
$retcode = 0. Generate chain OK. $chain stands for the chain string.
=cut
#-------------------------------------------------------------------------------
sub gen_chain_for_profiles {
my $class = shift;
my $profiles_hashref = shift;
my $hw_reconfig = shift;
my $final_chain = "";
if (!$profiles_hashref) {
return (1, "Missing parameter for gen_chain_for_profiles.");
}
# A node must have at least imageprofile and network profile.
unless (defined $profiles_hashref->{'ImageProfile'}) {
return (1, "No imageprofile specified in profiles hash.");
}
unless (defined $profiles_hashref->{'NetworkProfile'}) {
return (1, "No networkprofile specified in profiles hash.");
}
my $hwprofile = $profiles_hashref->{'HardwareProfile'};
my $imgprofile = $profiles_hashref->{'ImageProfile'};
my $netprofile = $profiles_hashref->{'NetworkProfile'};
# Get node's provisioning method
my $provmethod = xCAT::ProfiledNodeUtils->get_imageprofile_prov_method($imgprofile);
unless ($provmethod) {
return (1, "Can not get provisioning method for image profile $imgprofile");
}
my $netprofileattr = xCAT::ProfiledNodeUtils->get_nodes_nic_attrs([$netprofile])->{$netprofile};
unless ($netprofileattr) {
return (1, "Can not get attributes for network profile $netprofile");
}
# Get node's netboot attribute
my ($retcode, $retval) = xCAT::ProfiledNodeUtils->get_netboot_attr($imgprofile, $hwprofile);
if (not $retcode) {
return (1, $retval);
}
my $netboot = $retval;
$final_chain = 'osimage=' . $provmethod . ":--noupdateinitrd";
# get the chain attribute from hardwareprofile and insert it to node.
if (defined $hwprofile and $hwprofile and $hw_reconfig) {
my $chaintab = xCAT::Table->new('chain');
my $chain = $chaintab->getNodeAttribs($hwprofile, ['chain']);
if (exists $chain->{'chain'}) {
my $hw_chain = $chain->{'chain'};
$final_chain = $hw_chain . ',osimage=' . $provmethod . ":--noupdateinitrd";
}
}
#run bmcsetups.
#PowerNV nodes can't use 'runcmd=bmcsetup' to set BMC.
#But OpenPOWER need to support bmcsetup
my $nodehmtab = xCAT::Table->new('nodehm');
my $comments = "";
my $nodehmtab_entry = $nodehmtab->getNodeAttribs($hwprofile, ['comments']);
if (defined $nodehmtab_entry->{'comments'}) {
$comments = $nodehmtab_entry->{'comments'};
}
if ((exists $netprofileattr->{"bmc"}) and $hw_reconfig) {
if ((($netboot eq 'petitboot') and ($comments eq 'openpower')) or ($netboot ne 'petitboot'))
{
if (index($final_chain, "runcmd=bmcsetup") == -1) {
$final_chain = 'runcmd=bmcsetup,' . $final_chain . ':reboot4deploy';
}
else {
$final_chain = $final_chain . ':reboot4deploy';
}
}
}
return (0, $final_chain);
}
#-------------------------------------------------------------------------------
=head3 get_all_vmhosts
Description : Get all vm hosts/hypervisor from DB.
Arguments : N/A
Returns : ref for vm hosts/hypervisor hash.
Example :
my $hashref = xCAT::ProfiledNodeUtils->get_all_vmhosts();
=cut
#-------------------------------------------------------------------------------
sub get_all_vmhosts
{
my %vmhostshash;
my $nodelisttab = xCAT::Table->new('nodelist');
# groups like '__Hypervisor_pkvm' means this node is Power KVM hypervisor
my @vmhosts = $nodelisttab->getAllAttribsWhere("groups like '%__Hypervisor_kvm%'", 'node');
foreach (@vmhosts) {
if ($_->{'node'}) {
$vmhostshash{ $_->{'node'} } = 1;
}
}
$nodelisttab->close();
# Return the ref accordingly
return \%vmhostshash;
}
#-------------------------------------------------------------------------------
=head3 get_netboot_attr
Description : Get netboot attribute for node
Arguments : $imageprofile - image profile name, mandatory. e.g. "__ImageProfile_rhels7.0-x86_64-stateful-mgmtnode"
$hardwareprofile - harware profile name, optional. e.g. "__HardwareProfile_IBM_System_x_M4"
Returns : (returncode, netboot)
returncode=0 - can not get netboot value,netboot is the error message
returncode=1 - can get netboot value,netboot is the right value
=cut
#-------------------------------------------------------------------------------
our %NETBOOT_RULES = (
'x86_64' => 'xnba',
'riscv64' => 'grub2',
'ppc64' => {
'rhels' => {
'7' => 'grub2',
'*' => 'yaboot',
},
'pkvm' => 'petitboot',
'*' => 'yaboot',
},
'ppc64le' => {
'*' => {
'*' => {
'*' => 'grub2',
'ipmi' => 'petitboot',
},
},
},
);
sub get_netboot_attr {
my $class = shift;
my $imageprofile = shift;
my $hardwareprofile = shift;
my $netboot;
my @nodegrps = xCAT::TableUtils->list_all_node_groups();
unless (grep { $_ eq $imageprofile } @nodegrps)
{
return 0, "Image profile not defined in DB."
}
$imageprofile =~ s/^__ImageProfile_//;
if ($hardwareprofile) {
unless (grep { $_ eq $hardwareprofile } @nodegrps)
{
return 0, "Hardware profile not defined in DB."
}
}
else
{
$hardwareprofile = '*';
}
# Get os name, os major version, osarch
my $osimage_tab = xCAT::Table->new('osimage');
my $osimage_tab_entry = $osimage_tab->getAttribs({ 'imagename' => $imageprofile }, ('osdistroname'));
my $osdistroname = $osimage_tab_entry->{'osdistroname'};
$osimage_tab->close();
my $osdistro_tab = xCAT::Table->new('osdistro');
my $osdistro_tab_entry = $osdistro_tab->getAttribs({ 'osdistroname' => $osdistroname }, ('basename', 'majorversion', 'arch'));
my $os_name = $osdistro_tab_entry->{'basename'};
my $os_major_version = $osdistro_tab_entry->{'majorversion'};
my $os_arch = $osdistro_tab_entry->{'arch'};
$osdistro_tab->close;
# Treate os name rhel,centos,rhelhpc,rocky same as rhels
if ($os_name eq 'centos' || $os_name eq 'rhelhpc' || $os_name eq 'rhel' || $os_name eq 'rocky')
{
$os_name = 'rhels';
}
# Treate arch ppc64el same as ppc64le,x86 same as x86_64
if ($os_arch eq 'ppc64el')
{
$os_arch = 'ppc64le';
} elsif ($os_arch eq 'x86')
{
$os_arch = 'x86_64';
}
# Identify whether this node is PowerKVM or PowerNV if os arch is ppc64le
# If hardware profile is defined
my $mgt = '*';
if ($os_arch eq 'ppc64le' and $hardwareprofile ne '*') {
my $nodehmtab = xCAT::Table->new('nodehm');
my $nodehmtab_entry = $nodehmtab->getNodeAttribs($hardwareprofile, ['mgt']);
if (defined $nodehmtab_entry->{'mgt'}) {
$mgt = $nodehmtab_entry->{'mgt'};
}
}
# Rule for netboot attribute.If update the rule,just update %netboot_dict and @condition_array
# It's sequence sensitive: os arch -> os name -> os major version -> hardware profile
# Priority | Arch | OS Name | OS Major Version | Management method | Noderes.netboot |
# 1 | x86_64/x86 | * | * | * | xnba |
# 2 | ppc64 | rhels | 7 | * | grub2 |
# 2 | ppc64 | pkvm | * | * | petitboot |
# 3 | | * | * | * | yaboot |
# 4 | ppc64le/el | * | * | * | grub2
# 4 | ppc64le/el | * | * | ipmi | petitboot
# 5 | riscv64 | * | * | * | grub2 |
# arch osname version hardware netboot
my $condition_array_ref = [ $os_arch, $os_name, $os_major_version, $mgt ];
$netboot = cal_netboot(\%NETBOOT_RULES, $condition_array_ref);
if ($netboot eq '0')
{
return 0, "Can not get the netboot attribute";
}
else
{
return 1, $netboot;
}
}
#-------------------------------------------------------------------------------
=head3 cal_netboot
Description : Calculate netboot attribute by conditions recursively, internal use.
Arguments : $netboot_dict_ref
$condition_array_ref
Returns : netboot
returncode=0 - can not get netboot value
=cut
#-------------------------------------------------------------------------------
sub cal_netboot {
my $netboot_dict_ref = shift;
my $condition_array_ref = shift;
my $condition_array_len = scalar @$condition_array_ref;
if ($condition_array_len == 0) {
return 0;
}
my $condition = shift @$condition_array_ref;
if ((exists($netboot_dict_ref->{$condition})) || (exists($netboot_dict_ref->{'*'})))
{
if (!exists($netboot_dict_ref->{$condition}))
{
$condition = '*';
}
if (ref($netboot_dict_ref->{$condition}) eq 'HASH')
{
if ($condition_array_len > 1)
{
return cal_netboot($netboot_dict_ref->{$condition}, $condition_array_ref);
}
else
{
return 0;
}
}
else
{
return $netboot_dict_ref->{$condition};
}
}
else
{
return 0;
}
}