2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-06-12 08:10:12 +00:00

Add consoleenabled column to help store the console status

On diskless SN, the nodes file of goconserver is missing when
reinstalling. This patch add a column in nodehm table to help
recover the console information on service node.

```
[root@c910f03c09k04 ~]# makegocons -q

NODE                             SERVER                           STATE
c910f03c09k05                    c910f03c09k04.pok.stglabs.ibm.com error
node-7912ac1-06vag36             c910f03c09k04.pok.stglabs.ibm.com error

NODE                             SERVER                           STATE
c910f03c09k04                    c910f03c09k03.pok.stglabs.ibm.com connected
[root@c910f03c09k04 ~]# rm /var/lib/goconserver/*
rm: remove regular file ‘/var/lib/goconserver/nodes.json’? y
rm: remove regular file ‘/var/lib/goconserver/nodes.json.bak’? y
[root@c910f03c09k04 ~]# service xcatd restart
Restarting xcatd (via systemctl):                          [  OK  ]
[root@c910f03c09k04 ~]# makegocons -q

NODE                             SERVER                           STATE
c910f03c09k05                    c910f03c09k04.pok.stglabs.ibm.com error
node-7912ac1-06vag36             c910f03c09k04.pok.stglabs.ibm.com error

NODE                             SERVER                           STATE
c910f03c09k04                    c910f03c09k03.pok.stglabs.ibm.com connected
```
This commit is contained in:
chenglch
2018-02-07 19:06:37 +08:00
parent 28a84fa997
commit dd7e1d51df
5 changed files with 270 additions and 104 deletions

View File

@ -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.

View File

@ -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 #
##################

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;