2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-06-13 01:40:26 +00:00

PCM discover initial draft ready

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@13904 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
leiaibj
2012-09-27 08:56:19 +00:00
parent 31cafd39c4
commit 8b87922c73
3 changed files with 515 additions and 92 deletions

View File

@ -6,6 +6,7 @@ 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;
@ -67,6 +68,7 @@ sub get_allocable_staticips_innet
=head3 genhosts_with_numric_tmpl
Description : Generate numric hostnames using numric template name.
Arguments : $format - The hostname format string..
$rank - The start number.
Returns : numric hostname list
Example :
calling genhosts_with_numric_tmpl("compute#NNnode") will return a list like:
@ -76,10 +78,10 @@ sub get_allocable_staticips_innet
#-------------------------------------------------------------------------------
sub genhosts_with_numric_tmpl
{
my ($class, $format) = @_;
my ($class, $format, $rank) = @_;
my ($prefix, $appendix, $len) = xCAT::PCMNodeMgmtUtils->split_hostname($format, 'N');
return xCAT::PCMNodeMgmtUtils->gen_numric_hostnames($prefix, $appendix, $len);
return xCAT::PCMNodeMgmtUtils->gen_numric_hostnames($prefix, $appendix, $len, $rank);
}
#-------------------------------------------------------------------------------
@ -139,10 +141,13 @@ sub split_hostname
#-------------------------------------------------------------------------------
sub gen_numric_hostnames
{
my ($class, $prefix, $appendix, $len) = @_;
my ($class, $prefix, $appendix, $len, $rank) = @_;
my @hostnames;
my $cnt = 0;
my $cnt=0;
if ($rank){
$cnt = $rank;
}
my $maxnum = 10 ** $len;
while($cnt < $maxnum)
{
@ -392,39 +397,56 @@ sub get_allnode_singleattrib_hash
#-------------------------------------------------------------------------------
=head3 acquire_lock
Description : Create lock file for node management plugin so that there is
no multi node mamangement plugins running.
The file content will be the pid of the plugin running process.
Once the plugin process terminated abnormally and lock file not removed,
next time node management plugin runs, it will read the lock file
and check whether this process is running or not. If not,
just remove this lock file and create a new one.
Arguments : N/A
Returns : 1 - create lock success.
0 - failed, there may be a node management process running.
Description : Create lock file for PCM plugins so that there is
no multi instance of plugins running at same time.
The lock file content will be the pid of the plugin running process.
Using perl's flock to achive this.
Note: we can not judge whether PCM discovering is running or only
through acquire_lock("nodemgmt")
We must also call is_discover_started()
Arguments : action name: for example: nodemgmt, imageprofile...etc We'll generate
a lock file named as /var/lock/pcm/$action.
Returns : -1 - Acquire lock failed.
fh of lock file - the filehandler of lock file.
=cut
#-------------------------------------------------------------------------------
sub acquire_lock
{
my $lockfile = "/var/lock/pcm/nodemgmt";
my $class = shift;
my $action = shift;
my $lockdir = "/var/lock/pcm";
mkdir "$lockdir", 0755 unless -d "$lockdir";
my $lockfile = "$lockdir/$action";
if (-e $lockfile) {
open LOCKFILE, "<$lockfile";
my @lines = <LOCKFILE>;
my $pid = $lines[0];
if (-d "/proc/$pid") {
return 0;
} else{
# the process already not exists, remove lock file.
File::Path->rmtree($lockfile);
}
mkdir "$lockdir", 0755 unless -d "$lockdir";
open my $fh, ">$lockfile";
# use flock, non-blocking mode while acquiring a lock.
my $lockret = flock($fh, LOCK_EX|LOCK_NB);
if(! $lockret){
close $fh;
return -1;
}
print $fh $$;
return $fh;
}
#-------------------------------------------------------------------------------
=head3 is_discover_started
Description : Judge whether PCM 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;
}
open LOCKFILE, ">$lockfile";
print LOCKFILE $$;
close LOCKFILE;
return 1;
}
@ -432,23 +454,18 @@ sub acquire_lock
=head3 release_lock
Description : Release lock for node management process.
Arguments : N/A
Returns : N/A
Arguments : fh - the lock file handler.
Returns : return value of flock.
True - release lock succeed.
False - release lock failed.
=cut
#-------------------------------------------------------------------------------
sub release_lock
{
my $lockfile = "/var/lock/pcm/nodemgmt";
if (-e $lockfile){
open LOCKFILE, "<$lockfile";
my @lines = <LOCKFILE>;
my $pid = $lines[0];
close LOCKFILE;
if ($pid ne $$){
File::Path->rmtree($lockfile);
}
}
my $class = shift;
my $lockfh = shift;
return flock($lockfh, LOCK_UN|LOCK_NB);
}
#-------------------------------------------------------------------------------

View File

@ -70,56 +70,95 @@ sub process_request {
my $nodelist = $request->{node};
my $retref;
my $rsp;
if($command eq 'kitcmd_nodemgmt_add')
{
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating hosts entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makehosts"], node=>$nodelist}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist, arg=>['-n']}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating DNS entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist}, $request_command, 0, 1);
# Work around for makedns bug, it will set umask to 0007.
#umask(0022);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update DHCP entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makekdhcp"], node=>$nodelist}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update known hosts";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makeknownhosts"], node=>$nodelist}, $request_command, 0, 1);
my $firstnode = (@$nodelist)[0];
my $profileref = xCAT::PCMNodeMgmtUtils->get_nodes_profiles([$firstnode]);
my %profilehash = %$profileref;
if (exists $profilehash{$firstnode}{"ImageProfile"}){
$rsp->{info}->[0] = "[PCM nodes mgmt]Update nodes' boot settings";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["nodeset"], node=>$nodelist, arg=>['osimage='.$profilehash{$firstnode}{"ImageProfile"}]}, $request_command, 0, 1);
}
}
elsif ($command eq 'kitcmd_nodemgmt_remove'){
$retref = xCAT::Utils->runxcmd({command=>["nodeset"], node=>$nodelist, arg=>['offline']}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update known hosts";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makeknownhosts"], node=>$nodelist, arg=>['-r']}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update DHCP entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makekdhcp"], node=>$nodelist, arg=>['-d']}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating DNS entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist, arg=>['-d']}, $request_command, 0, 1);
# Work around for makedns bug, it will set umask to 0007.
#umask(0022);
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating hosts entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makehosts"], node=>$nodelist, arg=>['-d']}, $request_command, 0, 1);
}
elsif ($command eq 'kitcmd_nodemgmt_update'){
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating hosts entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makehosts"], node=>$nodelist}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist, arg=>['-n']}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating DNS entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist}, $request_command, 0, 1);
# Work around for makedns bug, it will set umask to 0007.
#umask(0022);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update DHCP entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makekdhcp"], node=>$nodelist}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update known hosts";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makeknownhosts"], node=>$nodelist}, $request_command, 0, 1);
my $firstnode = (@$nodelist)[0];
my $profileref = xCAT::PCMNodeMgmtUtils->get_nodes_profiles([$firstnode]);
my %profilehash = %$profileref;
if (exists $profilehash{$firstnode}{"ImageProfile"}){
$rsp->{info}->[0] = "[PCM nodes mgmt]Update nodes' boot settings";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["nodeset"], node=>$nodelist, arg=>['osimage='.$profilehash{$firstnode}{"ImageProfile"}]}, $request_command, 0, 1);
}
}
elsif ($command eq 'kitcmd_nodemgmt_refresh'){
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating hosts entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makehosts"], node=>$nodelist}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist, arg=>['-n']}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating DNS entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makedns"], node=>$nodelist}, $request_command, 0, 1);
# Work around for makedns bug, it will set umask to 0007.
#umask(0022);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update DHCP entries";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makekdhcp"], node=>$nodelist}, $request_command, 0, 1);
$rsp->{info}->[0] = "[PCM nodes mgmt]Update known hosts";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makeknownhosts"], node=>$nodelist}, $request_command, 0, 1);
}
elsif ($command eq 'kitcmd_nodemgmt_finished')
{
$rsp->{info}->[0] = "[PCM nodes mgmt]Updating conserver configuration files";
$::CALLBACK->($rsp);
$retref = xCAT::Utils->runxcmd({command=>["makeconservercf"]}, $request_command, 0, 1);
}
else

View File

@ -61,6 +61,10 @@ sub handled_commands {
addhost_discover => 'pcmnodes',
removehost => 'pcmnodes',
updatehost => 'pcmnodes',
pcmdiscover_start => 'pcmnodes',
pcmdiscover_stop => 'pcmnodes',
pcmdiscover_nodels => 'pcmnodes',
findme => 'pcmnodes',
};
}
@ -76,16 +80,29 @@ sub handled_commands {
#-------------------------------------------------------
sub process_request {
my $lock = xCAT::PCMNodeMgmtUtils->acquire_lock();
unless ($lock){
setrsp_errormsg("Can not acquire lock, some process is operating node related actions.");
return;
}
$request = shift;
$callback = shift;
$::CALLBACK = $callback;
$request_command = shift;
$command = $request->{command}->[0];
$args = $request->{arg};
my $lockfh = xCAT::PCMNodeMgmtUtils->acquire_lock("nodemgmt");
if ($lockfh == -1){
setrsp_errormsg("Can not acquire lock, some process is operating node related actions.");
return;
}
# These commands should make sure no discover is running.
if (grep{ $_ eq $command} ("addhost_hostfile", "removehost", "updatehost")){
my $discover_running = xCAT::PCMNodeMgmtUtils->is_discover_started();
if ($discover_running){
setrsp_errormsg("Can not run command $command as PCM discover is running.");
xCAT::PCMNodeMgmtUtils->release_lock($lockfh);
return;
}
}
if ($command eq "addhost_hostfile"){
addhost_hostfile()
@ -93,8 +110,17 @@ sub process_request {
removehost();
} elsif ($command eq "updatehost"){
updatehost();
} elsif ($command eq "pcmdiscover_start"){
pcmdiscover_start();
} elsif ($command eq "pcmdiscover_nodels"){
pcmdiscover_nodels();
} elsif ($command eq "findme"){
findme();
} elsif ($command eq "pcmdiscover_stop"){
pcmdiscover_stop();
}
xCAT::PCMNodeMgmtUtils->release_lock($lock);
xCAT::PCMNodeMgmtUtils->release_lock($lockfh);
}
#-------------------------------------------------------
@ -157,39 +183,49 @@ sub parse_args{
sub addhost_hostfile {
# Parse arges.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Import PCM nodes through hostinfo file.\n");
setrsp_infostr("[PCM nodes mgmt]Import PCM nodes through hostinfo file.");
my $retstr = parse_args();
if ($retstr){
setrsp_errormsg($retstr);
return;
}
# Make sure the specified parameters are valid ones.
# TODO: support privisioning template.
my @enabledparams = ('file', 'groups', 'networkprofile', 'hardwareprofile', 'imageprofile');
my @enabledparams = ('file', 'groups', 'networkprofile', 'hardwareprofile', 'imageprofile', 'hostnameformat');
foreach my $argname (keys %args_dict){
if (! grep{ $_ eq $argname} @enabledparams){
setrsp_errormsg("Illegal attribute $argname specified.");
return;
}
}
# validate hostinfo file.
if (! exists $args_dict{'file'}){
setrsp_errormsg("No hostinfo file specified.");
return;
# Mandatory arguments.
foreach (('file','networkprofile', 'imageprofile', 'hostnameformat')){
if(! exists($args_dict{$_})){
setrsp_errormsg("Mandatory parameter $_ not specified.");
return;
}
}
elsif(! (-e $args_dict{'file'})){
if(! (-e $args_dict{'file'})){
setrsp_errormsg("The hostinfo file not exists.");
return;
}
# Get database records: all hostnames, all ips, all racks...
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Getting database records.\n");
setrsp_infostr("[PCM nodes mgmt]Getting database records.");
my $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('nodelist', 'node');
%allhostnames = %$recordsref;
$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('ipmi', 'bmc');
%allbmcips = %$recordsref;
$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('mac', 'mac');
%allmacs = %$recordsref;
# MAC records looks like: "01:02:03:04:05:0E!node5│01:02:03:05:0F!node6-eth1". We want to get the real mac addres.
foreach (keys %allmacs){
my @hostentries = split(/\|/, $_);
foreach my $hostandmac ( @hostentries){
my ($macstr, $machostname) = split("!", $hostandmac);
$allmacs{$macstr} = 0;
}
}
$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('hosts', 'ip');
%allinstallips = %$recordsref;
$recordsref = xCAT::NetworkUtils->get_all_nicips(1);
@ -198,13 +234,14 @@ sub addhost_hostfile {
# Merge all BMC IPs and install IPs into allips.
%allips = (%allips, %allbmcips, %allinstallips);
#my $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('rack', 'rackname');
#%allracks = %$recordsref;
#my $recordsref = xCAT::PCMNodeMgmtUtils->get_allchassis(1);
#%allchassis = %$recordsref;
#TODO: can not use getallnode to get rack infos.
#$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('rack', 'rackname');
%allracks = ();
$recordsref = xCAT::PCMNodeMgmtUtils->get_all_chassis(1);
%allchassis = %$recordsref;
# Generate temporary hostnames for hosts entries in hostfile.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Generate temporary hostnames.\n");
setrsp_infostr("[PCM nodes mgmt]Generate temporary hostnames.");
my ($retcode_read, $retstr_read) = read_and_generate_hostnames($args_dict{'file'});
if ($retcode_read != 0){
setrsp_errormsg($retstr_read);
@ -212,7 +249,7 @@ sub addhost_hostfile {
}
# Parse and validate the hostinfo string. The real hostnames will be generated here.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Parsing hostinfo string and validate it.\n");
setrsp_infostr("[PCM nodes mgmt]Parsing hostinfo string and validate it.");
my ($hostinfo_dict_ref, $invalid_records_ref) = parse_hosts_string($retstr_read);
my %hostinfo_dict = %$hostinfo_dict_ref;
my @invalid_records = @$invalid_records_ref;
@ -226,18 +263,18 @@ sub addhost_hostfile {
}
# Create the real hostinfo string in stanza file format.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Generating new hostinfo string.\n");
setrsp_infostr("[PCM nodes mgmt]Generating new hostinfo string.");
my ($retcode_gen, $retstr_gen) = gen_new_hostinfo_string(\%hostinfo_dict);
unless ($retcode_gen){
setrsp_errormsg($retstr_gen);
return;
}
# call mkdef to create hosts and then call nodemgmt for node management plugins.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call mkdef to create pcm nodes.\n");
setrsp_infostr("[PCM nodes mgmt]call mkdef to create pcm nodes.");
my $retref = xCAT::Utils->runxcmd({command=>["mkdef"], stdin=>[$retstr_gen], arg=>['-z']}, $request_command, 0, 1);
my @nodelist = keys %hostinfo_dict;
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
setrsp_infostr("[PCM nodes mgmt]call nodemgmt plugins.");
$retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_add"], node=>\@nodelist}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_finished"], node=>\@nodelist}, $request_command, 0, 1);
setrsp_success(\@nodelist);
@ -255,12 +292,12 @@ sub addhost_hostfile {
#-------------------------------------------------------
sub removehost{
my $nodes = $request->{node};
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Remove PCM nodes.\n");
setrsp_infostr("[PCM nodes mgmt]Remove PCM nodes.");
# For remove nodes, we should call 'nodemgmt' in front of 'noderm'
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
setrsp_infostr("[PCM nodes mgmt]call nodemgmt plugins.");
my $retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_remove"], node=>$nodes}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_finished"], node=>$nodes}, $request_command, 0, 1);
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call noderm to remove nodes.\n");
setrsp_infostr("[PCM nodes mgmt]call noderm to remove nodes.");
$retref = xCAT::Utils->runxcmd({command=>["noderm"], node=>$nodes}, $request_command, 0, 1);
setrsp_success($nodes);
}
@ -279,7 +316,7 @@ sub updatehost{
my $nodes = $request->{node};
my %updated_groups;
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Update PCM nodes settings.\n");
setrsp_infostr("[PCM nodes mgmt]Update PCM nodes settings.");
# Parse arges.
my $retstr = parse_args();
if ($retstr){
@ -287,7 +324,6 @@ sub updatehost{
return;
}
# Make sure the specified parameters are valid ones.
# TODO: support privisioning template.
my @enabledparams = ('networkprofile', 'hardwareprofile', 'imageprofile');
foreach my $argname (keys %args_dict){
if (! grep{ $_ eq $argname} @enabledparams){
@ -297,7 +333,7 @@ sub updatehost{
}
# Get current templates for all nodes.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Read database to get groups for all nodes.\n");
setrsp_infostr("[PCM nodes mgmt]Read database to get groups for all nodes.");
my %groupdict;
my $nodelstab = xCAT::Table->new('nodelist');
my $nodeshashref = $nodelstab->getNodesAttribs($nodes, ['groups']);
@ -326,13 +362,13 @@ sub updatehost{
}
#update DataBase.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Update database records.\n");
setrsp_infostr("[PCM nodes mgmt]Update database records.");
my $nodetab = xCAT::Table->new('nodelist',-create=>1);
$nodetab->setNodesAttribs(\%updatenodeshash);
$nodetab->close();
# call plugins
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
setrsp_infostr("[PCM nodes mgmt]call nodemgmt plugins.");
my $retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_update"], node=>$nodes}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_finished"], node=>$nodes}, $request_command, 0, 1);
setrsp_success($nodes);
@ -340,6 +376,314 @@ sub updatehost{
#-------------------------------------------------------
=head3 pcmdiscover_start
Description : Start PCM discovery. If already started, return a failure.
User should specify networkprofile, hardwareprofile,
imageprofile, hostnameformat, rack, chassis, height and u so
that node's IP address will be generated automatcially
according to networkprofile, node's hardware settings will
be set according to hardware profile, node's os settings will
be set according to image profile, node's hostname will be
set according to hostnameformat and rank. And other node's
attribs will also be set according to rack, chassis, height and u.
Arguments : N/A
=cut
#-------------------------------------------------------
sub pcmdiscover_start{
# Parse arges.
setrsp_infostr("[PCM nodes mgmt]PCM discovery started.");
my $retstr = parse_args();
if ($retstr){
setrsp_errormsg($retstr);
return;
}
my @enabledparams = ('networkprofile', 'hardwareprofile', 'imageprofile', 'hostnameformat', 'rank', 'rack', 'chassis', 'height', 'u');
foreach my $argname (keys %args_dict){
if (! grep{ $_ eq $argname} @enabledparams){
setrsp_errormsg("Illegal attribute $argname specified.");
return;
}
}
# mandatory arguments.
foreach my $key ('networkprofile', 'imageprofile', 'hostnameformat'){
if (! exists $args_dict{$key}){
setrsp_errormsg("argument $key must be specified");
return;
}
}
# Read DB to confirm the discover is not started yet.
my @sitevalues = xCAT::TableUtils->get_site_attribute("__PCMDiscover");
if ($sitevalues[0]){
setrsp_errormsg("PCM node discovery already started.");
return;
}
# save discover args into table site.
my $valuestr = "";
foreach (keys %args_dict){
if($args_dict{$_}){
$valuestr .= "$_:$args_dict{$_},";
}
}
my $sitetab = xCAT::Table->new('site',-create=>1);
$sitetab->setAttribs({"key" => "__PCMDiscover"}, {"value" => "$valuestr"});
$sitetab->close();
}
#-------------------------------------------------------
=head3 pcmdiscover_stop
Description : Stop PCM auto discover. This action will remove the
dababase flags.
Arguments : N/A
=cut
#------------------------------------------------------
sub pcmdiscover_stop{
# Read DB to confirm the discover is started.
my @sitevalues = xCAT::TableUtils->get_site_attribute("__PCMDiscover");
if (! $sitevalues[0]){
setrsp_errormsg("PCM node discovery not started yet.");
return;
}
# remove site table records: discover flag.
my $sitetab=xCAT::Table->new("site");
my %keyhash;
$keyhash{'key'} = "__PCMDiscover";
$sitetab->delEntries(\%keyhash);
$sitetab->commit();
# Update node's attributes, remove from gruop "__PCMDiscover".
# we'll call rmdef so that node's groupinfo in table nodelist will be updated automatically.
my @nodes = xCAT::NodeRange::noderange('__PCMDiscover');
if (@nodes){
# There are some nodes discvoered.
my $retref = xCAT::Utils->runxcmd({command=>["rmdef"], arg=>["-t", "group", "-o", "__PCMDiscover"]}, $request_command, 0, 1);
}
}
#-------------------------------------------------------
=head3 pcmdiscover_nodels
Description : List all discovered PCM nodes.
Arguments : N/A
=cut
#-------------------------------------------------------
sub pcmdiscover_nodels{
# Read DB to confirm the discover is started.
my @sitevalues = ();
@sitevalues = xCAT::TableUtils->get_site_attribute("__PCMDiscover");
if (! $sitevalues[0]){
setrsp_errormsg("PCM node discovery not started yet.");
return;
}
my @nodes = xCAT::NodeRange::noderange('__PCMDiscover');
my $mactab = xCAT::Table->new("mac");
my $macsref = $mactab->getNodesAttribs(\@nodes, ['mac']);
my $nodelisttab = xCAT::Table->new("nodelist");
my $statusref = $nodelisttab->getNodesAttribs(\@nodes, ['status']);
my %rsp = ();
my %rspentry = ();
foreach (@nodes){
if (! $_){
next;
}
$rspentry{"node"} = $_;
#TODO: get provisioning mac.
$rspentry{"mac"} = $macsref->{$_}->[0]->{"mac"};
if ($statusref->{$_}->[0]){
$rspentry{"status"} = $statusref->{$_}->[0];
} else{
$rspentry{"status"} = "defined";
}
$callback->(\%rspentry);
}
}
#-------------------------------------------------------
=head3 findme
Description : The default interface for node discovery.
We must implement this method so that
PCM nodes's findme request can be answered
while PCM discovery is running.
Arguments : N/A
=cut
#-------------------------------------------------------
sub findme{
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]PCM discover: Start.\n");
# Read DB to confirm the discover is started.
my @sitevalues = xCAT::TableUtils->get_site_attribute("__PCMDiscover");
if (! @sitevalues){
setrsp_errormsg("PCM node discovery not started yet.");
return;
}
# We store node profiles in site table, key is "__PCMDiscover"
my @profilerecords = split(',', $sitevalues[0]);
foreach (@profilerecords){
if ($_){
my ($profilename, $profilevalue) = split(':', $_);
if ($profilename and $profilevalue){
$args_dict{$profilename} = $profilevalue;
}
}
}
# Get database records: all hostnames, all ips, all racks...
# To improve performance, we should initalize a daemon later??
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]PCM discover: Getting database records.\n");
my $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('nodelist', 'node');
%allhostnames = %$recordsref;
$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('ipmi', 'bmc');
%allbmcips = %$recordsref;
$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('mac', 'mac');
%allmacs = %$recordsref;
foreach (keys %allmacs){
my @hostentries = split(/\|/, $_);
foreach my $hostandmac ( @hostentries){
my ($macstr, $machostname) = split("!", $hostandmac);
$allmacs{$macstr} = 0;
}
}
$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('hosts', 'ip');
%allinstallips = %$recordsref;
$recordsref = xCAT::NetworkUtils->get_all_nicips(1);
%allips = %$recordsref;
# Merge all BMC IPs and install IPs into allips.
%allips = (%allips, %allbmcips, %allinstallips);
#$recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('rack', 'rackname');
#%allracks = %$recordsref;
%allracks = ();
$recordsref = xCAT::PCMNodeMgmtUtils->get_all_chassis(1);
%allchassis = %$recordsref;
my @enabledparams = ('networkprofile', 'hardwareprofile', 'imageprofile', 'hostnameformat', 'rack', 'chassis', 'u', 'height', 'rank');
foreach my $argname (keys %args_dict){
if (! grep{ $_ eq $argname} @enabledparams){
setrsp_errormsg("Illegal attribute $argname specified.");
return;
}
}
# mandatory arguments.
foreach my $key ('networkprofile', 'imageprofile', 'hostnameformat'){
if (! exists $args_dict{$key}){
setrsp_errormsg("argument $key must be specified");
return;
}
}
# set default value for rack, startunit and height if not specified.
if (exists $args_dict{'rack'}){
if (! exists $allracks{$args_dict{'rack'}}){
setrsp_errormsg("Specified rack $args_dict{'rack'} not defined");
return;
}
}else{
# set default rack.
#TODO : how to set default rack.
}
if (!exists $args_dict{'u'}){
$args_dict{'u'} = 1;
}
if (!exists $args_dict{'height'}){
$args_dict{'height'} = 1;
}
# chassis jdugement.
if (exists $args_dict{'chassis'}){
if (! exists $allchassis{$args_dict{'chassis'}}){
setrsp_errormsg("Specified chassis $args_dict{'chassis'} not defined");
return;
}
}
# Get discovered client IP and MAC
my $ip = $request->{'_xcat_clientip'};
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]PCM discover: _xcat_clientip is $ip.\n");
my $mac = '';
my $arptable = `/sbin/arp -n`;
my @arpents = split /\n/,$arptable;
foreach (@arpents) {
if (m/^($ip)\s+\S+\s+(\S+)\s/) {
$mac=$2;
last;
}
}
if (! $mac){
setrsp_errormsg("[PCM nodes mgmt]PCM discover: Can not get mac address of this node.");
return;
}
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]PCM discover: mac is $mac.\n");
if ( exists $allmacs{$mac}){
setrsp_errormsg("Discovered MAC $mac already exists in database.");
return;
}
# Assign TMPHOSTS9999 as a temporary hostname, in parse_hsots_string,
# it will detect this and arrange a real hostname for it.
my $raw_hostinfo_str = "TMPHOSTS9999:\n mac=$mac\n";
# Append rack, chassis, unit, height into host info string.
foreach my $key ('rack', 'chassis', 'u', 'height'){
if(exists($args_dict{$key})){
$raw_hostinfo_str .= " $key=$args_dict{$key}\n";
}
}
my ($hostinfo_dict_ref, $invalid_records_ref) = parse_hosts_string($raw_hostinfo_str);
my %hostinfo_dict = %$hostinfo_dict_ref;
# Create the real hostinfo string in stanza file format.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]PCM discover: Generating new hostinfo string.\n");
my ($retcode_gen, $retstr_gen) = gen_new_hostinfo_string($hostinfo_dict_ref);
unless ($retcode_gen){
setrsp_errormsg($retstr_gen);
return;
}
# call mkdef to create hosts and then call nodemgmt for node management plugins.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call mkdef to create pcm nodes.\n");
my $retref = xCAT::Utils->runxcmd({command=>["mkdef"], stdin=>[$retstr_gen], arg=>['-z']}, $request_command, 0, 1);
# increase unit automatically.
$args_dict{'u'} = $args_dict{'u'} + $args_dict{'height'};
my @nodelist = keys %hostinfo_dict;
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
$retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_add"], node=>\@nodelist}, $request_command, 0, 1);
$retref = xCAT::Utils->runxcmd({command=>["kitcmd_nodemgmt_finished"], node=>\@nodelist}, $request_command, 0, 1);
# call discover to notify client.
xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call discovered request.\n");
$request->{"command"} = ["discovered"];
$request->{"node"} = \@nodelist;
$retref = xCAT::Utils->runxcmd($request, $request_command, 0, 1);
# Set discovered flag.
my $nodegroupstr = $hostinfo_dict{$nodelist[0]}{"groups"};
my $nodelstab = xCAT::Table->new('nodelist',-create=>1);
$nodelstab->setNodeAttribs($nodelist[0],{groups=>$nodegroupstr.",__PCMDiscover"});
$nodelstab->close();
}
#-------------------------------------------------------
=head3 replace_item_in_array
Description : Replace an item in a list with new value. This item should match specified pattern.
@ -528,9 +872,7 @@ sub parse_hosts_string{
my %hostinfo_dict;
my @invalid_records;
my $nicstab = xCAT::Table->new('nics');
my $nodehashref = $nicstab->getNodeAttribs($args_dict{'networkprofile'}, ['hostnameformat']);
my $nameformat = $nodehashref->{'hostnameformat'};
my $nameformat = $args_dict{'hostnameformat'};
my $nameformattype = xCAT::PCMNodeMgmtUtils->get_hostname_format_type($nameformat);
my %freehostnames;
@ -580,7 +922,11 @@ sub parse_hosts_string{
# Generate hostnames based on numric hostname format.
if (! exists $freehostnames{$numricformat}){
$freehostnames{$numricformat} = xCAT::PCMNodeMgmtUtils->genhosts_with_numric_tmpl($numricformat);
my $rank = 0;
if (exists($args_dict{'rank'})){
$rank = $args_dict{'rank'};
}
$freehostnames{$numricformat} = xCAT::PCMNodeMgmtUtils->genhosts_with_numric_tmpl($numricformat, $rank);
}
my $hostnamelistref = $freehostnames{$numricformat};
my $nexthostname = shift @$hostnamelistref;
@ -651,19 +997,28 @@ sub validate_node_entry{
}elsif ($_ eq "switch"){
#TODO: xCAT switch discovery enhance: verify whether switch exists.
}elsif ($_ eq "port"){
#TODO: xCAT switch discovery enhance: verify whether port exists.
}elsif ($_ eq "rack"){
if (not exists $allracks{$node_entry{$_}}){
return "Specified rack $node_entry{$_} not defined";
}
# rack must be specified with chassis or unit + height.
if (exists $node_entry{"chassis"}){
} elsif (exists $node_entry{"height"} and exists $node_entry{"u"}){
} else {
return "Rack must be specified together with chassis or height + u ";
}
}elsif ($_ eq "chassis"){
if (not exists $allchassis{$node_entry{$_}}){
return "Specified chassis $node_entry{$_} not defined";
}
}elsif ($_ eq "unit"){
# Chassis must not be specified with unit and height.
if (exists $node_entry{"height"} and exists $node_entry{"u"}){
return "Chassis should not be specified together with height + u";
}
}elsif ($_ eq "u"){
# Not a valid number.
if (!($node_entry{$_} =~ /^\d+$/)){
return "Specified unit $node_entry{$_} is a invalid number";
return "Specified u $node_entry{$_} is a invalid number";
}
}elsif ($_ eq "height"){
# Not a valid number.
@ -674,15 +1029,6 @@ sub validate_node_entry{
return "Invalid attribute $_ specified";
}
}
# For blades, don't support specify unit and height.
if(exists $node_entry{"chassis"} ){
if(exists $node_entry{"unit"}){
return "Can not specify 'unit' together with 'chassis'";
}
if(exists $node_entry{"height"}){
return "can not specify 'height' together with 'chassis'";
}
}
# push hostinfo into global dicts.
$allhostnames{$node_name} = 0;
return undef;
@ -706,6 +1052,7 @@ sub setrsp_invalidrecords
my $master=xCAT::TableUtils->get_site_Master();
# The total number of invalid records.
$rsp->{error} = "Some error records detected";
$rsp->{invalid_records_num} = scalar @$recordsref;
# We write details of invalid records into a file.
@ -740,6 +1087,26 @@ sub setrsp_errormsg
$callback->($rsp);
}
#-------------------------------------------------------
=head3 setrsp_infostr
Description : Set response for a info string.
Arguments : infostr - The info string..
=cut
#-------------------------------------------------------
sub setrsp_infostr
{
my $infostr = shift;
my $rsp;
xCAT::MsgUtils->message('S', "$infostr\n");
$rsp->{info}->[0] = $infostr;
$callback->($rsp);
}
#-------------------------------------------------------
=head3 setrsp_success