656 lines
18 KiB
Perl
656 lines
18 KiB
Perl
|
package xCAT_plugin::tree;
|
||
|
|
||
|
BEGIN
|
||
|
{
|
||
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
||
|
}
|
||
|
use lib "$::XCATROOT/lib/perl";
|
||
|
|
||
|
use xCAT::NodeRange;
|
||
|
use Data::Dumper;
|
||
|
use xCAT::Utils;
|
||
|
use Sys::Syslog;
|
||
|
use xCAT::GlobalDef;
|
||
|
use xCAT::Table;
|
||
|
use Getopt::Long;
|
||
|
use xCAT::SvrUtils;
|
||
|
#use strict;
|
||
|
|
||
|
sub handled_commands
|
||
|
{
|
||
|
# currently, only for lstree command.
|
||
|
return {
|
||
|
lstree => "tree",
|
||
|
};
|
||
|
}
|
||
|
|
||
|
sub usage
|
||
|
{
|
||
|
my $command = shift;
|
||
|
my $callback = shift;
|
||
|
|
||
|
if($command eq "lstree")
|
||
|
{
|
||
|
&usage_lstree($callback);
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------------
|
||
|
|
||
|
=head3 usage_lstree
|
||
|
|
||
|
=cut
|
||
|
|
||
|
#-----------------------------------------------------------------------------
|
||
|
sub usage_lstree
|
||
|
{
|
||
|
my $callback = shift;
|
||
|
|
||
|
my $rsp;
|
||
|
push @{$rsp->{data}},
|
||
|
"\n lstree - Display the tree of service node hierarchy, hardware hierarchy, or VM hierarchy.";
|
||
|
push @{$rsp->{data}}, " Usage: ";
|
||
|
push @{$rsp->{data}}, "\tlstree [-h | --help]";
|
||
|
push @{$rsp->{data}}, "or";
|
||
|
push @{$rsp->{data}}, "\tlstree [-s | --servicenode] [-H | --hardwaremgmt] [-v | --virtualmachine] [noderange]";
|
||
|
|
||
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------------
|
||
|
|
||
|
=head3 process_request
|
||
|
|
||
|
=cut
|
||
|
|
||
|
#-----------------------------------------------------------------------------
|
||
|
sub process_request
|
||
|
{
|
||
|
my $request = shift;
|
||
|
my $callback = shift;
|
||
|
my @nodes=();
|
||
|
|
||
|
if($request->{node})
|
||
|
{
|
||
|
@nodes = @{$request->{node}};
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
# handle all nodes by default.
|
||
|
my $nodelist = xCAT::Table->new('nodelist');
|
||
|
unless ($nodelist)
|
||
|
{
|
||
|
my $rsp = {};
|
||
|
$rsp->{data}->[0] = "Can not open nodelist table.\n";
|
||
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
||
|
}
|
||
|
|
||
|
my @entries = ($nodelist->getAllNodeAttribs([qw(node)]));
|
||
|
foreach (@entries)
|
||
|
{
|
||
|
push @nodes, $_->{node};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $command = $request->{command}->[0];
|
||
|
if($command eq "lstree")
|
||
|
{
|
||
|
&lstree($request, $callback, \@nodes);
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
$callback->({error=>["error in code..."], errorcode=>[127]});
|
||
|
$request = {};
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------------
|
||
|
|
||
|
=head3 lstree
|
||
|
|
||
|
=cut
|
||
|
|
||
|
#-----------------------------------------------------------------------------
|
||
|
sub lstree
|
||
|
{
|
||
|
my $request = shift;
|
||
|
my $callback = shift;
|
||
|
my $nodelist = shift;
|
||
|
|
||
|
unless($request->{arg} || defined $nodelist)
|
||
|
{
|
||
|
&usage_lstree($callback);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
# parse the options
|
||
|
Getopt::Long::Configure("no_pass_through");
|
||
|
Getopt::Long::Configure("bundling");
|
||
|
|
||
|
if ($request->{arg})
|
||
|
{
|
||
|
@ARGV = @{$request->{arg}};
|
||
|
|
||
|
if (
|
||
|
!GetOptions(
|
||
|
'h|help' => \$::HELP,
|
||
|
's|servicenode' => \$::SVCNODE,
|
||
|
'H|hardwaremgmt' => \$::HDWR,
|
||
|
'v|virtualmachine' => \$::VMACHINE,
|
||
|
)
|
||
|
)
|
||
|
{
|
||
|
&usage_lstree($callback);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($::HELP)
|
||
|
{
|
||
|
&usage_lstree($callback);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (!$::SVCNODE && !$::HDWR && !$::VMACHINE)
|
||
|
{
|
||
|
# show both vmtree and hwtree by default.
|
||
|
$::SHOWALL = 1;
|
||
|
}
|
||
|
|
||
|
my %hwtrees;
|
||
|
my %vmtrees;
|
||
|
my %sntrees;
|
||
|
|
||
|
# servicenode hierarchy
|
||
|
if ($::SVCNODE)
|
||
|
{
|
||
|
# build up sn tree hash.
|
||
|
my $snhash;
|
||
|
my @entries;
|
||
|
my $restab = xCAT::Table->new('noderes');
|
||
|
if ($restab)
|
||
|
{
|
||
|
$snhash = $restab->getNodesAttribs($nodelist, ['servicenode']);
|
||
|
@entries = $restab->getAllNodeAttribs(['node','servicenode']);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
my $rsp = {};
|
||
|
$rsp->{data}->[0] = "Can not open noderes table.\n";
|
||
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
||
|
}
|
||
|
|
||
|
foreach my $node (@$nodelist)
|
||
|
{
|
||
|
# servicenode defined for this node
|
||
|
if ($snhash->{$node}->[0]->{'servicenode'})
|
||
|
{
|
||
|
unless (grep(/$node/, @{$sntrees{$snhash->{$node}->[0]->{'servicenode'}}}))
|
||
|
{
|
||
|
push @{$sntrees{$snhash->{$node}->[0]->{'servicenode'}}}, $node;
|
||
|
}
|
||
|
}
|
||
|
else # need to know if itself is service node
|
||
|
{
|
||
|
foreach my $ent (@entries)
|
||
|
{
|
||
|
if ($ent->{servicenode} eq $node)
|
||
|
{
|
||
|
unless (grep(/$ent->{node}/, @{$sntrees{$node}}))
|
||
|
{
|
||
|
push @{$sntrees{$node}}, $ent->{node};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
#print Dumper(\%sntreehash);
|
||
|
|
||
|
# show service node tree
|
||
|
&showtree(\%sntrees, 0, 0, $callback);
|
||
|
}
|
||
|
|
||
|
# get hwtree hash from each plugin
|
||
|
if ($::HDWR || $::SHOWALL)
|
||
|
{
|
||
|
# classify the nodes
|
||
|
# read nodehm.mgt
|
||
|
my $hmhash;
|
||
|
my $hmtab = xCAT::Table->new('nodehm');
|
||
|
if ($hmtab)
|
||
|
{
|
||
|
$hmhash = $hmtab->getNodesAttribs($nodelist, ['mgt']);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
my $rsp = {};
|
||
|
$rsp->{data}->[0] = "Can not open nodehm table.\n";
|
||
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
||
|
}
|
||
|
|
||
|
# may add new support later.
|
||
|
my @supportedhw = ("hmc", "fsp", "blade", "ipmi");
|
||
|
my %hwnodes;
|
||
|
|
||
|
foreach my $node (@$nodelist)
|
||
|
{
|
||
|
# mgt defined for this node
|
||
|
unless ($hmhash->{$node}->[0]->{'mgt'})
|
||
|
{
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
if (grep(/$hmhash->{$node}->[0]->{'mgt'}/, @supportedhw))
|
||
|
{
|
||
|
push @{$hwnodes{$hmhash->{$node}->[0]->{'mgt'}}}, $node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (%hwnodes)
|
||
|
{
|
||
|
foreach my $type (keys %hwnodes)
|
||
|
{
|
||
|
$hwtrees{$type} = ${"xCAT_plugin::".$type."::"}{genhwtree}->(\@{$hwnodes{$type}}, $callback);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#print Dumper(\%hwtrees);
|
||
|
}
|
||
|
|
||
|
if ($::HDWR && !$::VMACHINE)
|
||
|
{
|
||
|
&showtree(0, \%hwtrees, 0, $callback);
|
||
|
}
|
||
|
|
||
|
# generate vmtree from xcat vm table
|
||
|
if ($::VMACHINE || $::SHOWALL)
|
||
|
{
|
||
|
|
||
|
# here is a special case for zvm.
|
||
|
########### start ################
|
||
|
# read nodehm.mgt
|
||
|
my $hmhash;
|
||
|
my $hmtab = xCAT::Table->new('nodehm');
|
||
|
if ($hmtab)
|
||
|
{
|
||
|
$hmhash = $hmtab->getNodesAttribs($nodelist, ['mgt']);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
my $rsp = {};
|
||
|
$rsp->{data}->[0] = "Can not open nodehm table.\n";
|
||
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
||
|
}
|
||
|
|
||
|
my @znodes;
|
||
|
|
||
|
foreach my $node (@$nodelist)
|
||
|
{
|
||
|
# mgt defined for this node
|
||
|
unless ($hmhash->{$node}->[0]->{'mgt'})
|
||
|
{
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
if ($hmhash->{$node}->[0]->{'mgt'} =~ /zvm/)
|
||
|
{
|
||
|
push @znodes, $node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $ret = xCAT_plugin::zvm::listTree($callback, \@znodes);
|
||
|
|
||
|
########### end ################
|
||
|
|
||
|
# read vm.host
|
||
|
my $vmhash;
|
||
|
|
||
|
my $vmtab = xCAT::Table->new('vm');
|
||
|
if ($vmtab)
|
||
|
{
|
||
|
$vmhash = $vmtab->getNodesAttribs($nodelist, ['host']);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
my $rsp = {};
|
||
|
$rsp->{data}->[0] = "Can not open vm table.\n";
|
||
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
||
|
}
|
||
|
|
||
|
my @entries = $vmtab->getAllNodeAttribs(['node','host']);
|
||
|
|
||
|
foreach my $node (@$nodelist)
|
||
|
{
|
||
|
foreach my $ent (@entries)
|
||
|
{
|
||
|
if ($ent->{host} =~ /$node/) # host
|
||
|
{
|
||
|
push @{$vmtrees{$node}}, $ent->{node};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($vmhash && $vmhash->{$node}->[0]->{'host'}) # vm
|
||
|
{
|
||
|
unless (grep(/$node/, @{$vmtrees{$vmhash->{$node}->[0]->{'host'}}}))
|
||
|
{
|
||
|
push @{$vmtrees{$vmhash->{$node}->[0]->{'host'}}}, $node;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#print Dumper(\%vmtrees);
|
||
|
}
|
||
|
|
||
|
# vm tree output
|
||
|
if (!$::HDWR && $::VMACHINE)
|
||
|
{
|
||
|
&showtree(0, 0, \%vmtrees, $callback);
|
||
|
}
|
||
|
|
||
|
if ($::SHOWALL || ($::HDWR && $::VMACHINE))
|
||
|
{
|
||
|
&showtree(0, \%hwtrees, \%vmtrees, $callback);
|
||
|
}
|
||
|
return;
|
||
|
|
||
|
} # lstree end
|
||
|
|
||
|
#----------------------------------------------------------------------------
|
||
|
|
||
|
=head3 showtree
|
||
|
|
||
|
=cut
|
||
|
|
||
|
#-----------------------------------------------------------------------------
|
||
|
sub showtree
|
||
|
{
|
||
|
my $snthash = shift;
|
||
|
my $hwthash = shift;
|
||
|
my $vmthash = shift;
|
||
|
my $callback = shift;
|
||
|
|
||
|
my %sntrees = %$snthash;
|
||
|
my %hwtrees = %$hwthash;
|
||
|
my %vmtrees = %$vmthash;
|
||
|
|
||
|
# temp workaround before we integrate LPARs into vm table
|
||
|
my $lparinvm = 0;
|
||
|
my @entries;
|
||
|
|
||
|
if (!$lparinvm)
|
||
|
{
|
||
|
# read ppc table
|
||
|
my $ppctab = xCAT::Table->new('ppc');
|
||
|
unless ($ppctab)
|
||
|
{
|
||
|
my $rsp = {};
|
||
|
$rsp->{data}->[0] = "Can not open ppc table.\n";
|
||
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
||
|
}
|
||
|
|
||
|
@entries = $ppctab->getAllNodeAttribs(['node','id','parent']);
|
||
|
}
|
||
|
|
||
|
if (%sntrees)
|
||
|
{
|
||
|
my $rsp;
|
||
|
|
||
|
foreach my $sn (sort(keys %sntrees))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "Service Node: $sn";
|
||
|
foreach my $cn (sort(@{$sntrees{$sn}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "|__$cn";
|
||
|
}
|
||
|
push @{$rsp->{data}},
"\n";
|
||
|
}
|
||
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
||
|
}
|
||
|
|
||
|
# show hardware hierarchy
|
||
|
if (%hwtrees)
|
||
|
{
|
||
|
my $rsp;
|
||
|
|
||
|
# hmc tree output
|
||
|
foreach my $hmc (sort(keys %{$hwtrees{hmc}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "HMC: $hmc";
|
||
|
foreach my $frame (sort(keys %{$hwtrees{hmc}{$hmc}}))
|
||
|
{
|
||
|
if ($frame eq '0')
|
||
|
{
|
||
|
# no frame
|
||
|
push @{$rsp->{data}}, "|__Frame: n/a";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
# get bpas for frame.
|
||
|
my $bpas = xCAT::DBobjUtils->getchildren($frame);
|
||
|
my $bpalist = join ',', @$bpas;
|
||
|
push @{$rsp->{data}}, "|__Frame: $frame $bpalist";
|
||
|
}
|
||
|
|
||
|
foreach my $cec (sort @{$hwtrees{hmc}{$hmc}{$frame}})
|
||
|
{
|
||
|
|
||
|
# get fsps for cec.
|
||
|
my $fsps = xCAT::DBobjUtils->getchildren($cec);
|
||
|
my $fsplist = join ',', @$fsps;
|
||
|
push @{$rsp->{data}}, " |__CEC: $cec $fsplist";
|
||
|
|
||
|
if ($lparinvm)
|
||
|
{
|
||
|
# if show both, tailing with vmtree.
|
||
|
if (%vmtrees)
|
||
|
{
|
||
|
foreach my $host (sort(keys %vmtrees))
|
||
|
{
|
||
|
if ($host =~ /$cec/)
|
||
|
{
|
||
|
foreach my $vm (sort(@{$vmtrees{$host}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, " |__ $vm";
|
||
|
}
|
||
|
|
||
|
# remove it as shown
|
||
|
undef $vmtrees{$host};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
elsif ($::VMACHINE || $::SHOWALL) # temp workaround before we integrate LPARs into vm table
|
||
|
{
|
||
|
my %vm;
|
||
|
# get all lpars in this cec.
|
||
|
foreach my $ent (@entries)
|
||
|
{
|
||
|
if ($ent->{parent} =~ /$cec/)
|
||
|
{
|
||
|
$vm{$ent->{id}} = $ent->{node};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach my $id (sort(keys %vm))
|
||
|
{
|
||
|
push @{$rsp->{data}}, " |__LPAR $id: $vm{$id}";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
push @{$rsp->{data}}, "\n";
|
||
|
}
|
||
|
|
||
|
# DFM tree output
|
||
|
foreach my $sfp (sort(keys %{$hwtrees{fsp}}))
|
||
|
{
|
||
|
if ($sfp eq '0')
|
||
|
{
|
||
|
# no frame
|
||
|
push @{$rsp->{data}}, "Service Focal Point: n/a";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
push @{$rsp->{data}}, "Service Focal Point: $sfp";
|
||
|
}
|
||
|
|
||
|
foreach my $frame (sort(keys %{$hwtrees{fsp}{$sfp}}))
|
||
|
{
|
||
|
if ($frame eq '0')
|
||
|
{
|
||
|
# no frame
|
||
|
push @{$rsp->{data}}, "|__Frame: n/a";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
# get bpas for frame.
|
||
|
my $bpas = xCAT::DBobjUtils->getchildren($frame);
|
||
|
my $bpalist = join ',', @$bpas;
|
||
|
push @{$rsp->{data}}, "|__Frame: $frame $bpalist";
|
||
|
}
|
||
|
|
||
|
foreach my $cec (sort @{$hwtrees{fsp}{$sfp}{$frame}})
|
||
|
{
|
||
|
|
||
|
# get fsps for cec.
|
||
|
my $fsps = xCAT::DBobjUtils->getchildren($cec);
|
||
|
my $fsplist = join ',', @$fsps;
|
||
|
push @{$rsp->{data}}, " |__CEC: $cec $fsplist";
|
||
|
|
||
|
if ($lparinvm)
|
||
|
{
|
||
|
# if show both, tailing with vmtree.
|
||
|
if (%vmtrees)
|
||
|
{
|
||
|
foreach my $host (sort(keys %vmtrees))
|
||
|
{
|
||
|
if ($host =~ /$cec/)
|
||
|
{
|
||
|
foreach my $vm (sort(@{$vmtrees{$host}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, " |__ $vm";
|
||
|
}
|
||
|
# remove it as shown
|
||
|
undef $vmtrees{$host};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
elsif ($::VMACHINE || $::SHOWALL) # temp workaround before we integrate LPARs into vm table
|
||
|
{
|
||
|
my %vm;
|
||
|
# get all lpars in this cec.
|
||
|
foreach my $ent (@entries)
|
||
|
{
|
||
|
if ($ent->{parent} =~ /$cec/)
|
||
|
{
|
||
|
$vm{$ent->{id}} = $ent->{node};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach my $id (sort(keys %vm))
|
||
|
{
|
||
|
push @{$rsp->{data}}, " |__LPAR $id: $vm{$id}";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
push @{$rsp->{data}}, "\n";
|
||
|
}
|
||
|
|
||
|
# blade tree output
|
||
|
foreach my $mm (sort(keys %{$hwtrees{blade}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "Management Module: $mm";
|
||
|
|
||
|
foreach my $slot (sort(keys %{$hwtrees{blade}{$mm}}))
|
||
|
{
|
||
|
my $blade = $hwtrees{blade}{$mm}{$slot};
|
||
|
push @{$rsp->{data}}, "|__Blade $slot: $blade";
|
||
|
|
||
|
# if show both, tailing with vmtree.
|
||
|
if (%vmtrees)
|
||
|
{
|
||
|
foreach my $host (sort(keys %vmtrees))
|
||
|
{
|
||
|
if ($host =~ /$blade/)
|
||
|
{
|
||
|
foreach my $vm (sort(@{$vmtrees{$host}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, " |__ $vm";
|
||
|
}
|
||
|
# remove it as shown
|
||
|
undef $vmtrees{$host};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
push @{$rsp->{data}}, "\n";
|
||
|
}
|
||
|
|
||
|
# ipmi tree output
|
||
|
foreach my $bmc (sort(keys %{$hwtrees{ipmi}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "BMC: $bmc";
|
||
|
foreach my $svr (sort(@{$hwtrees{ipmi}{$bmc}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "|__Server: $svr";
|
||
|
|
||
|
# if show both, tailing with vmtree.
|
||
|
if (%vmtrees)
|
||
|
{
|
||
|
foreach my $host (sort(keys %vmtrees))
|
||
|
{
|
||
|
if ($host =~ /$svr/)
|
||
|
{
|
||
|
foreach my $vm (sort(@{$vmtrees{$host}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, " |__ $vm";
|
||
|
}
|
||
|
# remove it as shown
|
||
|
undef $vmtrees{$host};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
push @{$rsp->{data}}, "\n";
|
||
|
}
|
||
|
|
||
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
||
|
}
|
||
|
|
||
|
# show VM hierarchy
|
||
|
if (%vmtrees)
|
||
|
{
|
||
|
my $rsp;
|
||
|
foreach my $host (sort(keys %vmtrees))
|
||
|
{
|
||
|
if (defined $vmtrees{$host})
|
||
|
{
|
||
|
push @{$rsp->{data}}, "Server: $host";
|
||
|
foreach my $vm (sort(@{$vmtrees{$host}}))
|
||
|
{
|
||
|
push @{$rsp->{data}}, "|__ $vm";
|
||
|
}
|
||
|
}
|
||
|
push @{$rsp->{data}}, "\n";
|
||
|
}
|
||
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
||
|
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
1;
|