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;