diff --git a/docs/source/guides/admin-guides/references/man5/nodehm.5.rst b/docs/source/guides/admin-guides/references/man5/nodehm.5.rst index ef568e90f..aa12ce4b2 100644 --- a/docs/source/guides/admin-guides/references/man5/nodehm.5.rst +++ b/docs/source/guides/admin-guides/references/man5/nodehm.5.rst @@ -19,7 +19,7 @@ SYNOPSIS ******** -\ **nodehm Attributes:**\ \ *node*\ , \ *power*\ , \ *mgt*\ , \ *cons*\ , \ *termserver*\ , \ *termport*\ , \ *conserver*\ , \ *serialport*\ , \ *serialspeed*\ , \ *serialflow*\ , \ *getmac*\ , \ *cmdmapping*\ , \ *consoleondemand*\ , \ *comments*\ , \ *disable*\ +\ **nodehm Attributes:**\ \ *node*\ , \ *power*\ , \ *mgt*\ , \ *cons*\ , \ *termserver*\ , \ *termport*\ , \ *conserver*\ , \ *serialport*\ , \ *serialspeed*\ , \ *serialflow*\ , \ *getmac*\ , \ *cmdmapping*\ , \ *consoleondemand*\ , \ *consoleenabled*\ , \ *comments*\ , \ *disable*\ *********** @@ -114,6 +114,12 @@ nodehm Attributes: +\ **consoleenabled**\ + + A flag field to indicate whether the node is registered in the console server. If '1', console is enabled, if not set, console is not enabled. + + + \ **comments**\ Any user-written notes. diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm index 2639cba81..d06d4c780 100755 --- a/perl-xCAT/xCAT/Schema.pm +++ b/perl-xCAT/xCAT/Schema.pm @@ -594,7 +594,7 @@ passed as argument rather than by table value', }, }, nodehm => { - cols => [qw(node power mgt cons termserver termport conserver serialport serialspeed serialflow getmac cmdmapping consoleondemand comments disable)], + cols => [qw(node power mgt cons termserver termport conserver serialport serialspeed serialflow getmac cmdmapping consoleondemand consoleenabled comments disable)], keys => [qw(node)], tablespace => 'XCATTBS16K', table_desc => "Settings that control how each node's hardware is managed. Typically, an additional table that is specific to the hardware type of the node contains additional info. E.g. the ipmi, mp, and ppc tables.", @@ -612,6 +612,7 @@ passed as argument rather than by table value', getmac => 'The method to use to get MAC address of the node with the getmac command. If not set, the mgt attribute will be used. Valid values: same as values for mgmt attribute.', cmdmapping => 'The fully qualified name of the file that stores the mapping between PCM hardware management commands and xCAT/third-party hardware management commands for a particular type of hardware device. Only used by PCM.', consoleondemand => "This overrides the value from site.consoleondemand. Set to 'yes', 'no', '1' (equivalent to 'yes'), or '0' (equivalent to 'no'). If not set, the default is the value from site.consoleondemand.", + consoleenabled => "A flag field to indicate whether the node is registered in the console server. If '1', console is enabled, if not set, console is not enabled.", comments => 'Any user-written notes.', disable => "Set to 'yes' or '1' to comment out this row.", }, @@ -2184,6 +2185,10 @@ my @nodeattrs = ( tabentry => 'nodehm.consoleondemand', access_tabentry => 'nodehm.node=attr:node', }, + { attr_name => 'consoleenabled', + tabentry => 'nodehm.consoleenabled', + access_tabentry => 'nodehm.node=attr:node', + }, ################## # vpd table # ################## diff --git a/xCAT-server/lib/perl/xCAT/Goconserver.pm b/xCAT-server/lib/perl/xCAT/Goconserver.pm index 835ee4e3e..0e3906def 100644 --- a/xCAT-server/lib/perl/xCAT/Goconserver.pm +++ b/xCAT-server/lib/perl/xCAT/Goconserver.pm @@ -21,6 +21,7 @@ use IO::Socket::SSL qw( SSL_VERIFY_PEER ); my $go_api_port = 12429; my $go_cons_port = 12430; +my $bmc_cons_port = "2200"; use constant CONSOLE_LOG_DIR => "/var/log/consoles"; use constant PRINT_FORMAT => "%-32s %-32s %-64s"; @@ -56,11 +57,210 @@ sub http_request { return ""; } +sub gen_request_data { + my ($cons_map, $siteondemand, $isSN, $callback) = @_; + my (@openbmc_nodes, $data); + while (my ($k, $v) = each %{$cons_map}) { + my $ondemand; + if ($siteondemand) { + $ondemand = \1; + } else { + $ondemand = \0; + } + my $cmd; + my $cmeth = $v->{cons}; + if ($cmeth eq "openbmc") { + push @openbmc_nodes, $k; + } else { + $cmd = $::XCATROOT . "/share/xcat/cons/$cmeth"." ".$k; + if (!(!$isSN && $v->{conserver} && xCAT::NetworkUtils->thishostisnot($v->{conserver}))) { + my $env; + my $locerror = $isSN ? "PERL_BADLANG=0 " : ''; + if (defined($ENV{'XCATSSLVER'})) { + $env = "XCATSSLVER=$ENV{'XCATSSLVER'} "; + } + $cmd = $locerror.$env.$cmd; + } + $data->{$k}->{driver} = "cmd"; + $data->{$k}->{params}->{cmd} = $cmd; + $data->{$k}->{name} = $k; + } + if (defined($v->{consoleondemand})) { + # consoleondemand attribute for node can be "1", "yes", "0" and "no" + if (($v->{consoleondemand} eq "1") || lc($v->{consoleondemand}) eq "yes") { + $ondemand = \1; + } + elsif (($v->{consoleondemand} eq "0") || lc($v->{consoleondemand}) eq "no") { + $ondemand = \0; + } + } + $data->{$k}->{ondemand} = $ondemand; + } + if (@openbmc_nodes) { + my $passwd_table = xCAT::Table->new('passwd'); + my $passwd_hash = $passwd_table->getAttribs({ 'key' => 'openbmc' }, qw(username password)); + $passwd_table->close(); + my $openbmc_table = xCAT::Table->new('openbmc'); + my $openbmc_hash = $openbmc_table->getNodesAttribs(\@openbmc_nodes, ['bmc','consport', 'username', 'password']); + $openbmc_table->close(); + foreach my $node (@openbmc_nodes) { + if (defined($openbmc_hash->{$node}->[0])) { + if (!$openbmc_hash->{$node}->[0]->{'bmc'}) { + if($callback) { + xCAT::SvrUtils::sendmsg("Error: Unable to get attribute bmc", $callback, $node); + } else { + xCAT::MsgUtils->message("S", "$node: Error: Unable to get attribute bmc"); + } + delete $data->{$node}; + next; + } + $data->{$node}->{params}->{host} = $openbmc_hash->{$node}->[0]->{'bmc'}; + if ($openbmc_hash->{$node}->[0]->{'username'}) { + $data->{$node}->{params}->{user} = $openbmc_hash->{$node}->[0]->{'username'}; + } elsif ($passwd_hash and $passwd_hash->{username}) { + $data->{$node}->{params}->{user} = $passwd_hash->{username}; + } else { + if ($callback) { + xCAT::SvrUtils::sendmsg("Error: Unable to get attribute username", $callback, $node) + } else { + xCAT::MsgUtils->message("S", "$node: Error: Unable to get attribute username"); + } + delete $data->{$node}; + next; + } + if ($openbmc_hash->{$node}->[0]->{'password'}) { + $data->{$node}->{params}->{password} = $openbmc_hash->{$node}->[0]->{'password'}; + } elsif ($passwd_hash and $passwd_hash->{password}) { + $data->{$node}->{params}->{password} = $passwd_hash->{password}; + } else { + if ($callback) { + xCAT::SvrUtils::sendmsg("Error: Unable to get attribute password", $callback, $node) + } else { + xCAT::MsgUtils->message("S", "$node: Error: Unable to get attribute password"); + } + delete $data->{$node}; + next; + } + if ($openbmc_hash->{$node}->[0]->{'consport'}) { + $data->{$node}->{params}->{consport} = $openbmc_hash->{$node}->[0]->{'consport'}; + } else { + $data->{$node}->{params}->{port} = $bmc_cons_port; + } + $data->{$node}->{name} = $node; + $data->{$node}->{driver} = "ssh"; + } + } + } + return $data; +} + +#------------------------------------------------------------------------------- + +=head3 init_local_console + Init console nodes on service node locally. + + Globals: + none + Example: + my $ready=(xCAT::Goconserver::init_local_console() + Comments: + none + +=cut + +#------------------------------------------------------------------------------- +sub init_local_console { + my @hostinfo = xCAT::NetworkUtils->determinehostname(); + my %iphash = (); + my %cons_map; + my $ret; + my $host = $hostinfo[-1]; + foreach (@hostinfo) { + $iphash{$_} = 1; + } + my $retry = 0; + my $api_url = "https://$host:". get_api_port(); + my $response = http_request("GET", $api_url."/nodes"); + while(!defined($response) && $retry < 3) { + $response = http_request("GET", $api_url."/nodes"); + $retry ++; + sleep 1; + } + if (!defined($response)) { + xCAT::MsgUtils->message("S", "Could not connect to goconserver after trying 3 times."); + return; + } + if ($response->{nodes}->[0]) { + # node data exist, maybe this is not diskless sn. + return; + } + my $nodehmtab = xCAT::Table->new('nodehm', -create => 1); + if (!$nodehmtab) { + return; + } + my @cons_nodes = $nodehmtab->getAllNodeAttribs([ 'node', 'cons', 'serialport', 'mgt', 'conserver', 'consoleondemand', 'consoleenabled' ]); + $nodehmtab->close(); + my @nodes = (); + foreach (@cons_nodes) { + if ($_->{consoleenabled} && ($_->{cons} or defined($_->{'serialport'}))) { + unless ($_->{cons}) { + $_->{cons} = $_->{mgt}; + } + if ($_->{conserver} && exists($iphash{ $_->{conserver} })) { + $cons_map{ $_->{node} } = $_; + } + } + } + my @entries = xCAT::TableUtils->get_site_attribute("consoleondemand"); + my $site_entry = $entries[0]; + my $siteondemand = 0; + if (defined($site_entry)) { + if (lc($site_entry) eq "yes") { + $siteondemand = 1; + } + elsif (lc($site_entry) ne "no") { + xCAT::MsgUtils->message("S", $host.": Unexpected value $site_entry for consoleondemand attribute in site table"); + } + } + my $data = gen_request_data(\%cons_map, $siteondemand, 1, undef); + if (! $data) { + xCAT::MsgUtils->message("S", $host.": Could not generate the request data"); + return; + } + if (create_nodes($api_url, $data, undef)) { + xCAT::MsgUtils->message("S", $host.": Failed to create console entry in goconserver. "); + } +} + +sub disable_nodes_in_db { + my $nodes = shift; + my $nodehmtab = xCAT::Table->new('nodehm', -create => 1); + if (!$nodehmtab) { + return 1; + } + my $updateattribs->{consoleenabled} = undef; + $nodehmtab->setNodesAttribs($nodes, $updateattribs); + $nodehmtab->close(); + return 0; +} + +sub enable_nodes_in_db { + my $nodes = shift; + my $nodehmtab = xCAT::Table->new('nodehm', -create => 1); + if (!$nodehmtab) { + return 1; + } + my $updateattribs->{consoleenabled} = '1'; + $nodehmtab->setNodesAttribs($nodes, $updateattribs); + $nodehmtab->close(); + return 0; +} + sub delete_nodes { my ($api_url, $node_map, $delmode, $callback) = @_; my $url = "$api_url/bulk/nodes"; my @a = (); - my ($data, $rsp, $ret); + my ($data, $rsp, $ret, @update_nodes); $data->{nodes} = \@a; foreach my $node (keys %{$node_map}) { my $temp; @@ -70,18 +270,39 @@ sub delete_nodes { $ret = 0; my $response = http_request("DELETE", $url, $data); if (!defined($response)) { - $rsp->{data}->[0] = "Failed to send delete request."; - xCAT::MsgUtils->message("E", $rsp, $callback); + if ($callback) { + $rsp->{data}->[0] = "Failed to send delete request."; + xCAT::MsgUtils->message("E", $rsp, $callback) + } else { + xCAT::MsgUtils->message("S", "Failed to send delete request."); + } return 1; } elsif ($delmode) { while (my ($k, $v) = each %{$response}) { if ($v ne "Deleted") { - $rsp->{data}->[0] = "$k: Failed to delete entry in goconserver: $v"; - xCAT::MsgUtils->message("E", $rsp, $callback); + if ($callback) { + $rsp->{data}->[0] = "$k: Failed to delete entry in goconserver: $v"; + xCAT::MsgUtils->message("E", $rsp, $callback) + } else { + xCAT::MsgUtils->message("S", "$k: Failed to delete entry in goconserver: $v"); + } $ret = 1; } else { - $rsp->{data}->[0] = "$k: $v"; - xCAT::MsgUtils->message("I", $rsp, $callback); + if ($callback) { + $rsp->{data}->[0] = "$k: $v"; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + push(@update_nodes, $k); + } + } + } + if (@update_nodes) { + if (disable_nodes_in_db(\@update_nodes)) { + if ($callback) { + $rsp->{data}->[0] = "Failed to update consoleenabled status in db."; + xCAT::MsgUtils->message("E", $rsp, $callback); + } else { + xCAT::MsgUtils->message("S", "Failed to update consoleenabled status in db."); } } } @@ -91,7 +312,7 @@ sub delete_nodes { sub create_nodes { my ($api_url, $node_map, $callback) = @_; my $url = "$api_url/bulk/nodes"; - my ($data, $rsp, @a, $ret); + my ($data, $rsp, @a, $ret, @update_nodes); $data->{nodes} = \@a; while (my ($k, $v) = each %{$node_map}) { push @a, $v; @@ -99,18 +320,37 @@ sub create_nodes { $ret = 0; my $response = http_request("POST", $url, $data); if (!defined($response)) { - $rsp->{data}->[0] = "Failed to send create request."; - xCAT::MsgUtils->message("E", $rsp, $callback); + if ($callback) { + $rsp->{data}->[0] = "Failed to send create request."; + xCAT::MsgUtils->message("E", $rsp, $callback) + } else { + xCAT::MsgUtils->message("S", "Failed to send create request."); + } return 1; } elsif ($response) { while (my ($k, $v) = each %{$response}) { if ($v ne "Created") { - $rsp->{data}->[0] = "$k: Failed to create console entry in goconserver: $v"; - xCAT::MsgUtils->message("E", $rsp, $::callback); + if ($callback) { + $rsp->{data}->[0] = "$k: Failed to create console entry in goconserver: $v"; + xCAT::MsgUtils->message("E", $rsp, $callback); + } else { + xCAT::MsgUtils->message("S", "$k: Failed to create console entry in goconserver: $v"); + } $ret = 1; } else { $rsp->{data}->[0] = "$k: $v"; - xCAT::MsgUtils->message("I", $rsp, $::callback); + xCAT::MsgUtils->message("I", $rsp, $callback) if $callback; + push(@update_nodes, $k); + } + } + } + if (@update_nodes) { + if (enable_nodes_in_db(\@update_nodes)) { + if ($callback) { + $rsp->{data}->[0] = "Failed to update consoleenabled status in db."; + xCAT::MsgUtils->message("E", $rsp, $callback); + } else { + CAT::MsgUtils->message("S", "Failed to update consoleenabled status in db."); } } } @@ -133,7 +373,7 @@ sub list_nodes { return 0; } $rsp->{data}->[0] = sprintf("\n".PRINT_FORMAT, "NODE", "SERVER", "STATE"); - xCAT::MsgUtils->message("I", $rsp, $::callback); + xCAT::MsgUtils->message("I", $rsp, $callback); foreach my $node (sort {$a->{name} cmp $b->{name}} @{$response->{nodes}}) { if (!$node_map->{$node->{name}}) { next; @@ -145,7 +385,7 @@ sub list_nodes { next; } $rsp->{data}->[0] = sprintf(PRINT_FORMAT, $node->{name}, $node->{host}, $node->{state}); - xCAT::MsgUtils->message("I", $rsp, $::callback); + xCAT::MsgUtils->message("I", $rsp, $callback); } my %node_hash = %{$node_map}; for my $node (sort keys %node_hash) { diff --git a/xCAT-server/lib/xcat/plugins/AAsn.pm b/xCAT-server/lib/xcat/plugins/AAsn.pm index e941c12fc..d7c63fa02 100755 --- a/xCAT-server/lib/xcat/plugins/AAsn.pm +++ b/xCAT-server/lib/xcat/plugins/AAsn.pm @@ -587,6 +587,7 @@ sub setup_GOCONS xCAT::MsgUtils->message("S", "Error: failed to start goconserver service."); return 1; } + xCAT::Goconserver::init_local_console(); return 0; } diff --git a/xCAT-server/lib/xcat/plugins/goconserver.pm b/xCAT-server/lib/xcat/plugins/goconserver.pm index 7fb243168..b3487e81a 100644 --- a/xCAT-server/lib/xcat/plugins/goconserver.pm +++ b/xCAT-server/lib/xcat/plugins/goconserver.pm @@ -17,7 +17,6 @@ use Data::Dumper; my $isSN; my $host; -my $bmc_cons_port = "2200"; my $usage_string =" makegocons [-V|--verbose] [-d|--delete] noderange -h|--help Display this usage statement. -v|--version Display the version number. @@ -183,91 +182,6 @@ sub get_cons_map { return %cons_map; } -sub gen_request_data { - my ($cons_map, $siteondemand) = @_; - my (@openbmc_nodes, $data); - while (my ($k, $v) = each %{$cons_map}) { - my $ondemand; - if ($siteondemand) { - $ondemand = \1; - } else { - $ondemand = \0; - } - my $cmd; - my $cmeth = $v->{cons}; - if ($cmeth eq "openbmc") { - push @openbmc_nodes, $k; - } else { - $cmd = $::XCATROOT . "/share/xcat/cons/$cmeth"." ".$k; - if (!(!$isSN && $v->{conserver} && xCAT::NetworkUtils->thishostisnot($v->{conserver}))) { - my $env; - my $locerror = $isSN ? "PERL_BADLANG=0 " : ''; - if (defined($ENV{'XCATSSLVER'})) { - $env = "XCATSSLVER=$ENV{'XCATSSLVER'} "; - } - $cmd = $locerror.$env.$cmd; - } - $data->{$k}->{driver} = "cmd"; - $data->{$k}->{params}->{cmd} = $cmd; - $data->{$k}->{name} = $k; - } - if (defined($v->{consoleondemand})) { - # consoleondemand attribute for node can be "1", "yes", "0" and "no" - if (($v->{consoleondemand} eq "1") || lc($v->{consoleondemand}) eq "yes") { - $ondemand = \1; - } - elsif (($v->{consoleondemand} eq "0") || lc($v->{consoleondemand}) eq "no") { - $ondemand = \0; - } - } - $data->{$k}->{ondemand} = $ondemand; - } - if (@openbmc_nodes) { - my $passwd_table = xCAT::Table->new('passwd'); - my $passwd_hash = $passwd_table->getAttribs({ 'key' => 'openbmc' }, qw(username password)); - $passwd_table->close(); - my $openbmc_table = xCAT::Table->new('openbmc'); - my $openbmc_hash = $openbmc_table->getNodesAttribs(\@openbmc_nodes, ['bmc','consport', 'username', 'password']); - $openbmc_table->close(); - foreach my $node (@openbmc_nodes) { - if (defined($openbmc_hash->{$node}->[0])) { - if (!$openbmc_hash->{$node}->[0]->{'bmc'}) { - xCAT::SvrUtils::sendmsg("Error: Unable to get attribute bmc", $::callback, $node); - delete $data->{$node}; - next; - } - $data->{$node}->{params}->{host} = $openbmc_hash->{$node}->[0]->{'bmc'}; - if ($openbmc_hash->{$node}->[0]->{'username'}) { - $data->{$node}->{params}->{user} = $openbmc_hash->{$node}->[0]->{'username'}; - } elsif ($passwd_hash and $passwd_hash->{username}) { - $data->{$node}->{params}->{user} = $passwd_hash->{username}; - } else { - xCAT::SvrUtils::sendmsg("Error: Unable to get attribute username", $::callback, $node); - delete $data->{$node}; - next; - } - if ($openbmc_hash->{$node}->[0]->{'password'}) { - $data->{$node}->{params}->{password} = $openbmc_hash->{$node}->[0]->{'password'}; - } elsif ($passwd_hash and $passwd_hash->{password}) { - $data->{$node}->{params}->{password} = $passwd_hash->{password}; - } else { - xCAT::SvrUtils::sendmsg("Error: Unable to get attribute password", $::callback, $node); - delete $data->{$node}; - next; - } - if ($openbmc_hash->{$node}->[0]->{'consport'}) { - $data->{$node}->{params}->{consport} = $openbmc_hash->{$node}->[0]->{'consport'}; - } else { - $data->{$node}->{params}->{port} = $bmc_cons_port; - } - $data->{$node}->{name} = $node; - $data->{$node}->{driver} = "ssh"; - } - } - } - return $data; -} - sub start_goconserver { my ($rsp, $running, $ready, $ret); unless (-x "/usr/bin/goconserver") { @@ -357,7 +271,7 @@ sub makegocons { } } my (@nodes); - my $data = gen_request_data(\%cons_map, $siteondemand); + my $data = xCAT::Goconserver::gen_request_data(\%cons_map, $siteondemand, $isSN, $::callback); if (! $data) { xCAT::SvrUtils::sendmsg([ 1, "Could not generate the request data" ], $::callback); return 1;