* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.

* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent f636e399d7
commit 818ef23634
  1. 3
      Anvil/Tools.pm
  2. 2
      Anvil/Tools/Account.pm
  3. 67
      Anvil/Tools/Database.pm
  4. 17
      Anvil/Tools/Striker.pm
  5. 152
      cgi-bin/striker
  6. 122
      html/skins/alteeve/anvil.html
  7. BIN
      html/skins/alteeve/images/fence.png
  8. 5
      html/skins/alteeve/main.css
  9. 94
      notes
  10. 9
      share/words.xml
  11. 13
      tools/anvil-daemon
  12. 3
      tools/striker-parse-fence-agents
  13. 63
      tools/test.pl

@ -1078,7 +1078,7 @@ sub _set_paths
network_cache => "/tmp/network_cache.anvil", network_cache => "/tmp/network_cache.anvil",
passwd => "/etc/passwd", passwd => "/etc/passwd",
'redhat-release' => "/etc/redhat-release", 'redhat-release' => "/etc/redhat-release",
fences_unified_metadata => "/tmp/fences_unified_metadata.xml", fences_unified_metadata => "/var/www/html/fences_unified_metadata.xml",
}, },
directories => { directories => {
anvil => "/etc/anvil", anvil => "/etc/anvil",
@ -1190,6 +1190,7 @@ sub _set_paths
'striker-initialize-host' => "/usr/sbin/striker-initialize-host", 'striker-initialize-host' => "/usr/sbin/striker-initialize-host",
'striker-manage-install-target' => "/usr/sbin/striker-manage-install-target", 'striker-manage-install-target' => "/usr/sbin/striker-manage-install-target",
'striker-manage-peers' => "/usr/sbin/striker-manage-peers", 'striker-manage-peers' => "/usr/sbin/striker-manage-peers",
'striker-parse-fence-agents' => "/usr/sbin/striker-parse-fence-agents",
'striker-parse-oui' => "/usr/sbin/striker-parse-oui", 'striker-parse-oui' => "/usr/sbin/striker-parse-oui",
'striker-prep-database' => "/usr/sbin/striker-prep-database", 'striker-prep-database' => "/usr/sbin/striker-prep-database",
'striker-scan-network' => "/usr/sbin/striker-scan-network", 'striker-scan-network' => "/usr/sbin/striker-scan-network",

@ -569,7 +569,7 @@ AND
$anvil->data->{sys}{users}{user_name} = $results->[0]->[0]; $anvil->data->{sys}{users}{user_name} = $results->[0]->[0];
$anvil->data->{sessions}{session_salt} = $results->[0]->[1]; $anvil->data->{sessions}{session_salt} = $results->[0]->[1];
$anvil->data->{sessions}{session_salt} = "" if not defined $anvil->data->{sessions}{session_salt}; $anvil->data->{sessions}{session_salt} = "" if not defined $anvil->data->{sessions}{session_salt};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"sys::users::user_name" => $anvil->data->{sys}{users}{user_name}, "sys::users::user_name" => $anvil->data->{sys}{users}{user_name},
"sessions::session_salt" => $anvil->data->{sessions}{session_salt}, "sessions::session_salt" => $anvil->data->{sessions}{session_salt},
}}); }});

@ -9333,14 +9333,32 @@ sub resync_databases
"db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'}, "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'},
"db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen}, "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen},
}}); }});
next; next;
} }
# TODO: Remove these or make them proper errors # If we failed to get a modified_date, something went very wrong.
die $THIS_FILE." ".__LINE__."; This row's modified_date wasn't the first column returned in query: [$query]\n" if not $modified_date; if (not $modified_date)
die $THIS_FILE." ".__LINE__."; This row's UUID column: [$uuid_column] wasn't the second column returned in query: [$query]\n" if not $row_uuid; {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0114", variables => { query => $query }});
$anvil->nice_exit({code => 1});
die;
}
# If we don't have a row uuid, something has also gone wrong...
if (not $row_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0115", variables => {
uuid_column => $uuid_column,
query => $query,
}});
$anvil->nice_exit({code => 1});
die;
}
# Record this in the unified and local hashes. # Record this in the unified and local hashes.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { row_uuid => $row_uuid }});
$anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; $anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value;
$anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -9372,19 +9390,21 @@ sub resync_databases
# \- If we have seen, see if it exists at the current timestamp. # \- If we have seen, see if it exists at the current timestamp.
# \- If not, _INSERT_ it into history schema. # \- If not, _INSERT_ it into history schema.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen},
}}); }});
$anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} = 0 if not defined $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen};
if (not $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen}) if (not $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen})
{ {
# Mark this record as now having been seen. # Mark this record as now having been seen.
$anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} = 1; $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen} "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::seen" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{seen},
}}); }});
# Does it exist? # Does it exist?
$anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'} = 0 if not defined $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'} "db_data::${uuid}::${table}::${uuid_column}::${row_uuid}::exists" => $anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'},
}}); }});
if ($anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'}) if ($anvil->data->{db_data}{$uuid}{$table}{$uuid_column}{$row_uuid}{'exists'})
{ {
@ -9447,8 +9467,37 @@ sub resync_databases
} }
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0460", variables => { uuid => $anvil->data->{database}{$uuid}{host}, query => $query }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0460", variables => { uuid => $anvil->data->{database}{$uuid}{host}, query => $query }});
# Now record the query in the array ### NOTE: On some occasions, for as-yet unknown
### reasons, a record can end up in the public
### schema while nothing exists in the history
### schema (which is what we read during a
### resync). To deal with this, we'll do an
### explicit check before confirming the
### INSERT)
my $count_query = "SELECT COUNT(*) FROM public.".$table." WHERE ".$uuid_column." = ".$anvil->Database->quote($row_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count_query => $count_query }});
my $count = $anvil->Database->query({debug => $debug, uuid => $uuid, query => $count_query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
if ($count)
{
# Already in, redirect to the history schema.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0029", variables => {
table => $table,
host_name => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}),
host_uuid => $uuid,
column => $uuid_column,
uuid => $row_uuid,
query => $query,
}});
$query =~ s/INSERT INTO public./INSERT INTO history./;
push @{$anvil->data->{db_resync}{$uuid}{history}{sql}}, $query;
}
else
{
# No problem, record the query in the array
push @{$anvil->data->{db_resync}{$uuid}{public}{sql}}, $query; push @{$anvil->data->{db_resync}{$uuid}{public}{sql}}, $query;
}
} # if not exists } # if not exists
} # if not seen } # if not seen
else else
@ -9460,6 +9509,7 @@ sub resync_databases
# We've seen this row_uuid before, so it is just a # We've seen this row_uuid before, so it is just a
# question of whether the entry for the current # question of whether the entry for the current
# timestamp exists in the history schema. # timestamp exists in the history schema.
$anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid} = 0 if not defined $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}, "db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid},
}}); }});
@ -9499,7 +9549,7 @@ sub resync_databases
push @{$anvil->data->{db_resync}{$uuid}{history}{sql}}, $query; push @{$anvil->data->{db_resync}{$uuid}{history}{sql}}, $query;
} # if not exists - timestamp } # if not exists - timestamp
} # if seen } # if seen
} # foreach $id } # foreach $uuid
} # foreach $row_uuid } # foreach $row_uuid
} # foreach $modified_date ... } # foreach $modified_date ...
@ -10476,6 +10526,7 @@ sub _test_access
# No connections are left, die. # No connections are left, die.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0196"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0196"});
$anvil->nice_exit({code => 1}); $anvil->nice_exit({code => 1});
# In case we're still alive, die. # In case we're still alive, die.
die $THIS_FILE." ".__LINE__."; exiting on DB connection error.\n"; die $THIS_FILE." ".__LINE__."; exiting on DB connection error.\n";
} }

@ -95,6 +95,11 @@ sub get_fence_data
my $parsed_xml = ""; my $parsed_xml = "";
my $xml_body = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{fences_unified_metadata}}); my $xml_body = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{fences_unified_metadata}});
# Globally replace \fI (opening underline) with '[' and \fP (closing underline) with ']'.
$xml_body =~ s/\\fI/[/gs;
$xml_body =~ s/\\fP/]/gs;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { xml_body => $xml_body }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { xml_body => $xml_body }});
if ($xml_body =~ /<\?xml version="1.0" \?>/gs) if ($xml_body =~ /<\?xml version="1.0" \?>/gs)
{ {
@ -117,7 +122,6 @@ sub get_fence_data
return(1); return(1);
} }
#print Dumper $parsed_xml;
foreach my $agent_ref (@{$parsed_xml->{agent}}) foreach my $agent_ref (@{$parsed_xml->{agent}})
{ {
my $fence_agent = $agent_ref->{name}; my $fence_agent = $agent_ref->{name};
@ -161,6 +165,7 @@ sub get_fence_data
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{deprecated} = $deprecated; $anvil->data->{fences}{$fence_agent}{parameters}{$name}{deprecated} = $deprecated;
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{obsoletes} = $obsoletes; $anvil->data->{fences}{$fence_agent}{parameters}{$name}{obsoletes} = $obsoletes;
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{description} = $hash_ref->{shortdesc}->{content}; $anvil->data->{fences}{$fence_agent}{parameters}{$name}{description} = $hash_ref->{shortdesc}->{content};
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{description} =~ s/\n/ /g;
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{switches} = defined $hash_ref->{getopt}->{mixed} ? $hash_ref->{getopt}->{mixed} : ""; $anvil->data->{fences}{$fence_agent}{parameters}{$name}{switches} = defined $hash_ref->{getopt}->{mixed} ? $hash_ref->{getopt}->{mixed} : "";
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{content_type} = $hash_ref->{content}->{type}; $anvil->data->{fences}{$fence_agent}{parameters}{$name}{content_type} = $hash_ref->{content}->{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -215,6 +220,16 @@ sub get_fence_data
"fences::${fence_agent}::parameters::${name}::default" => $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'}, "fences::${fence_agent}::parameters::${name}::default" => $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'},
}}); }});
} }
# If this obsoletes another parameter, mark it as such.
$anvil->data->{fences}{$fence_agent}{parameters}{$name}{replacement} = "" if not exists $anvil->data->{fences}{$fence_agent}{parameters}{$name}{replacement};
if ($obsoletes)
{
$anvil->data->{fences}{$fence_agent}{parameters}{$obsoletes}{replacement} = $name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"fences::${fence_agent}::parameters::${obsoletes}::replacement" => $anvil->data->{fences}{$fence_agent}{parameters}{$obsoletes}{replacement},
}});
}
} }
$anvil->data->{fences}{$fence_agent}{actions} = []; $anvil->data->{fences}{$fence_agent}{actions} = [];

@ -1502,6 +1502,10 @@ sub process_anvil_menu
{ {
process_prep_network($anvil); process_prep_network($anvil);
} }
elsif ($anvil->data->{cgi}{task}{value} eq "fences")
{
process_fences($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "create") elsif ($anvil->data->{cgi}{task}{value} eq "create")
{ {
if ($anvil->data->{cgi}{subtask}{value} eq "manifest") if ($anvil->data->{cgi}{subtask}{value} eq "manifest")
@ -1533,6 +1537,154 @@ sub handle_new_manifest
return(0); return(0);
} }
# This allows the user to tell us about fence devices.
sub process_fences
{
my ($anvil) = @_;
# Read/process the unified fences metadata.
$anvil->Striker->get_fence_data({debug => 2});
$anvil->data->{cgi}{fence_agent}{value} = "" if not defined $anvil->data->{cgi}{fence_agent}{value};
$anvil->data->{cgi}{fence_count}{value} = 2 if not defined $anvil->data->{cgi}{fence_count}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::fence_agent::value" => $anvil->data->{cgi}{fence_agent}{value},
"cgi::fence_count::value" => $anvil->data->{cgi}{fence_count}{value},
}});
# For each agent, we'll create a <div> with it's options that will be shown/hidden basen on the agent
# select box.
my $agents = [];
my $description_form = "";
foreach my $fence_agent (sort {$a cmp $b} keys %{$anvil->data->{fences}})
{
# We don't care about IPMI-based fence agents here.
next if $fence_agent eq "fence_drac5";
next if $fence_agent eq "fence_idrac";
next if $fence_agent =~ /^fence_ilo/;
next if $fence_agent eq "fence_imm";
next if $fence_agent eq "fence_ipmilan";
next if $fence_agent eq "fence_redfish";
next if $fence_agent eq "fence_rsa";
push @{$agents}, $fence_agent;
my $agent_description = $anvil->data->{fences}{$fence_agent}{description};
$agent_description =~ s/\n/<br \/>/gs;
$agent_description =~ s/<br \/>/<br \/>\n/gs;
$agent_description =~ s/(http:\/\/.*)\n/<a href target="_new" target="$1">$1<\/a>/gs;
$agent_description =~ s/(https:\/\/.*)\n/<a href target="_new" target="$1">$1<\/a>/gs;
$agent_description =~ s/(http:\/\/.*) /<a href target="_new" target="$1">$1<\/a> /gs;
$agent_description =~ s/(https:\/\/.*) /<a href target="_new" target="$1">$1<\/a> /gs;
# There's a table in the fence_azure_arm agent, this formats it
if ($fence_agent eq "fence_azure_arm")
{
my $in_pre = 0;
my $break_number = 0;
my $new_desctiption = "";
foreach my $line (split/\n/, $agent_description)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /\+---/)
{
$line =~ s/<br \/>//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { break_number => $break_number }});
if (not $break_number)
{
$in_pre = 1;
$new_desctiption .= "<pre>\n";
$new_desctiption .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_desctiption => $new_desctiption }});
}
elsif ($break_number == 2)
{
$in_pre = 0;
$new_desctiption .= $line."\n";
$new_desctiption .= "</pre>\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_desctiption => $new_desctiption }});
}
else
{
$new_desctiption .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_desctiption => $new_desctiption }});
}
$break_number++;
}
else
{
if ($in_pre)
{
$line =~ s/<br \/>//g;
}
$new_desctiption .= $line."\n";
}
}
$agent_description = $new_desctiption;
}
$description_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-description", variables => {
fence_agent => $fence_agent,
description => $agent_description,
}});
=cut
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fences}{$fence_agent}{parameters}})
{
# We don't show deprecated or replaced options.
next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{replacement};
next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{deprecated};
my $unique = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{unique};
my $required = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{required};
my $description = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{description};
my $switches = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{switches};
my $type = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{content_type};
my $star = $required ? "*" : "";
my $default = exists $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} ? $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} : "";
if ($type eq "select")
{
# Build the select box
my @options = ();
foreach my $option (sort @{$anvil->data->{fences}{$fence_agent}{parameters}{$name}{options}})
{
push @options, $option;
}
}
}
=cut
}
my $fence_agent_select = $anvil->Template->select_form({
name => "fence_agent",
options => $agents,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{fence_agent}{value},
class => "input_clear",
});
my $fence_count_select = $anvil->Template->select_form({
name => "fence_count",
options => [1, 2, 3, 4],
blank => 0,
'sort' => 0,
selected => $anvil->data->{cgi}{fence_count}{value},
class => "input_clear",
});
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value};
$anvil->data->{cgi}{subtask}{value} = "" if not defined $anvil->data->{cgi}{subtask}{value};
$anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value};
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "fence-agent-menu", variables => {
fence_select => $fence_agent_select,
fence_count => $fence_count_select,
descriptions => $description_form,
existing_fences => "",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
# This handles creating an Anvil! from an existing manifest # This handles creating an Anvil! from an existing manifest
sub process_create sub process_create
{ {

@ -16,12 +16,20 @@
&nbsp; &nbsp;
</td> </td>
</tr> </tr>
<tr>
<td class="main_option_icon">
<a href="?anvil=true&task=fences"><img src="#!data!skin::url!#/images/fence.png" class="top_icon" ></a>
</td>
<td class="main_option">
<a href="?anvil=true&task=fences">#!string!striker_0208!#</a>
</td>
</tr>
<tr> <tr>
<td class="main_option_icon"> <td class="main_option_icon">
<a href="?anvil=true&task=create&new=step1"><img src="#!data!skin::url!#/images/manifest.png" class="top_icon" ></a> <a href="?anvil=true&task=create&new=step1"><img src="#!data!skin::url!#/images/manifest.png" class="top_icon" ></a>
</td> </td>
<td class="main_option"> <td class="main_option">
<a href="?anvil=true&task=prep-host">#!string!striker_0204!#</a> <a href="?anvil=true&task=create&new=step1">#!string!striker_0204!#</a>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -50,6 +58,118 @@
</table> </table>
<!-- end create-menu --> <!-- end create-menu -->
<!-- start fence-agent-menu -->
<table align="center" class="anvil_main_menu">
<script type="text/javascript" src="/skins/alteeve/anvil.js"></script>
<tr>
<td colspan="2">
&nbsp;
</td>
</tr>
<tr>
<td class="main_option_icon">
<img src="#!data!skin::url!#/images/fence.png" class="top_icon" >
</td>
<td class="title">
#!string!striker_0209!#
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
<td class="description">
#!string!striker_0210!#<br /><br />
#!string!striker_0211!#
</td>
</tr>
<tr>
<td colspan="2">
&nbsp;
</td>
</tr>
<tr>
<td colspan="2">
#!string!striker_0213!#
</td>
</tr>
<tr>
<td colspan="2">
#!variable!existing_fences!#
</td>
</tr>
<tr>
<td colspan="2">
&nbsp;
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
<td>
<table class="centered">
<div id="new_fences">
<form name="new_fences" action="" method="post">
<tr>
<td>
#!string!striker_0070!#:
</td>
<td>
&nbsp;
</td>
<td>
#!variable!fence_select!#
</td>
</tr>
<tr>
<td>
#!string!striker_0212!#:
</td>
<td>
&nbsp;
</td>
<td>
#!variable!fence_count!#
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td colspan="3" class="no_border_right">
<input type="submit" name="add" id="add" class="button" value="#!string!striker_0070!#">
</td>
</tr>
</form>
</table>
</td>
</tr>
<tr>
<td colspan="2">
<table class="data_table">
<div id="fence_agent_list">
#!variable!descriptions!#
</div>
</table>
</td>
</tr>
</table>
<!-- end fence-agent-menu -->
<!-- start fence-agent-description -->
<tr>
<td>
<span class="column_row_value_fixed">#!variable!fence_agent!#</a>
</td>
<td>
#!variable!description!#
</td>
</tr>
<!-- end fence-agent-description -->
<!-- start existing-manifest-entry --> <!-- start existing-manifest-entry -->
<tr> <tr>
<td> <td>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -405,6 +405,11 @@ td.top_padded_cell {
text-align: center; text-align: center;
} }
.description {
font-size: 1.2em;
text-align: center;
}
.top_icon { .top_icon {
border-top: 0.3em solid transparent; border-top: 0.3em solid transparent;
border-left: 0.3em solid transparent; border-left: 0.3em solid transparent;

94
notes

@ -1349,97 +1349,3 @@ Striker Version: 2.0.7
</tools> </tools>
</common> </common>
</config> </config>
fence_aliyun - Fence agent for Aliyun (Aliyun Web Services)
* action - Fencing action (Default Value: reboot)
* plug - Physical plug number on device, UUID or identification of machine This parameter is always required. Obsoletes: port
* region - Region.
* access_key - Access Key.
* secret_key - Secret Key.
* quiet - Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.
verbose
Verbose mode
debug_file
Write debug information to given file Obsoletes: debug
version
Display version information and exit
help Display help and exit
separator
Separator for CSV created by 'list' operation (Default Value: ,)
delay Wait X seconds before fencing is started (Default Value: 0)
login_timeout
Wait X seconds for cmd prompt after login (Default Value: 5)
power_timeout
Test X seconds for status change after ON/OFF (Default Value: 60)
power_wait
Wait X seconds after issuing ON/OFF (Default Value: 0)
shell_timeout
Wait X seconds for cmd prompt after issuing command (Default Value: 3)
retry_on
Count of attempts to retry power on (Default Value: 1)
fence_amt_ws
fence_apc
fence_apc_snmp
fence_aws
fence_azure_arm
fence_bladecenter
fence_brocade
fence_cisco_mds
fence_cisco_ucs
fence_compute
fence_drac5
fence_eaton_snmp
fence_emerson
fence_eps
fence_evacuate
fence_gce
fence_heuristics_ping
fence_hpblade
fence_ibmblade
fence_idrac
fence_ifmib
fence_ilo
fence_ilo2
fence_ilo3
fence_ilo3_ssh
fence_ilo4
fence_ilo4_ssh
fence_ilo5
fence_ilo5_ssh
fence_ilo_moonshot
fence_ilo_mp
fence_ilo_ssh
fence_imm
fence_intelmodular
fence_ipdu
fence_ipmilan
fence_kdump
fence_mpath
fence_pacemaker
fence_redfish
fence_rhevm
fence_rsa
fence_rsb
fence_sbd
fence_scsi
fence_virsh
fence_virt
fence_virtd
fence_vmware_rest
fence_vmware_soap
fence_wti
fence_xvm

@ -1076,6 +1076,12 @@ If you are comfortable that the target has changed for a known reason, you can s
<key name="striker_0205">Existing Manifests:</key> <key name="striker_0205">Existing Manifests:</key>
<key name="striker_0206">Run</key> <key name="striker_0206">Run</key>
<key name="striker_0207">Edit</key> <key name="striker_0207">Edit</key>
<key name="striker_0208">Configure fence devices. These will be used when creating install manifests and are a critical safety mechanisms that will protect your data when a node misbehaves.</key>
<key name="striker_0209">Configure fence devices.</key>
<key name="striker_0210">Fence devices are used to force a node that has entered an unknown state into a known state. Recovery after a node fault can not proceed until this happens, so this step is critically important.</key>
<key name="striker_0211">Note: Any IPMI (iRMC, iLO, DRAC, etc) fence config will be handled in the host's config. This section configures shared devices, like PDUs. The ports/outlets a given node will use will be set in the install manifest later.</key>
<key name="striker_0212">How Many?</key>
<key name="striker_0213">Known fence devices:</key>
<!-- These are generally units and appended to numbers --> <!-- These are generally units and appended to numbers -->
<key name="suffix_0001">#!variable!number!#/sec</key> <key name="suffix_0001">#!variable!number!#/sec</key>
@ -1254,6 +1260,7 @@ Failure! The return code: [#!variable!return_code!#] was received ('0' was expec
<key name="warning_0026">The recipient's email address appears to not be valid.</key> <key name="warning_0026">The recipient's email address appears to not be valid.</key>
<key name="warning_0027">There was a problem saving the alert recipient data. Please check the logs for more information.</key> <key name="warning_0027">There was a problem saving the alert recipient data. Please check the logs for more information.</key>
<key name="warning_0028">Failed to read the fence agent: [#!variable!agent!#] metadata. Ignoring it.</key> <key name="warning_0028">Failed to read the fence agent: [#!variable!agent!#] metadata. Ignoring it.</key>
<key name="warning_0029">While resync'ing the table: [#!variable!table!#] on: [#!variable!host_name!# (#!variable!host_uuid!#)], there was an entry found in the public schema (#!variable!column!# = #!variable!uuid!#) but not in the history schema. This shouldn't happen, and it probably a bug. Switching the query's schema from public to history for the query: [#!variable!query!#] is being dropped.</key>
<!-- Errors --> <!-- Errors -->
<key name="error_0001">There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network).</key> <key name="error_0001">There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network).</key>
@ -1393,6 +1400,8 @@ The error was:
</key> </key>
<key name="error_0112"><![CDATA[Failed to read valid unified XML data from: [#!variable!file!#]. It should start with: [<?xml version="1.0" ?>]]]></key> <key name="error_0112"><![CDATA[Failed to read valid unified XML data from: [#!variable!file!#]. It should start with: [<?xml version="1.0" ?>]]]></key>
<key name="error_0113">The unified metadata file: [#!data!path::data::fences_unified_metadata!#] was not found. There may have been a problem creating it.</key> <key name="error_0113">The unified metadata file: [#!data!path::data::fences_unified_metadata!#] was not found. There may have been a problem creating it.</key>
<key name="error_0114">This row's modified_date wasn't the first column returned in query: [#!variable!query!#]</key>
<key name="error_0115">This row's UUID column: [#!variable!uuid_column!#] wasn't the second column returned in query: [#!variable!query!#]</key>
<!-- These are units, words and so on used when displaying information. --> <!-- These are units, words and so on used when displaying information. -->
<key name="unit_0001">Yes</key> <key name="unit_0001">Yes</key>

@ -338,10 +338,12 @@ sub handle_periodic_tasks
my ($anvil) = @_; my ($anvil) = @_;
my $now_time = time; my $now_time = time;
my $type = $anvil->System->get_host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"s1:now_time" => $now_time, "s1:now_time" => $now_time,
"s2:timing::next_minute_check" => $anvil->data->{timing}{next_minute_check}, "s2:timing::next_minute_check" => $anvil->data->{timing}{next_minute_check},
"s3:timing::next_daily_check" => $anvil->data->{timing}{next_daily_check}, "s3:timing::next_daily_check" => $anvil->data->{timing}{next_daily_check},
"s4:type" => $type,
}}); }});
# Time to run once per minute tasks. # Time to run once per minute tasks.
@ -375,6 +377,14 @@ sub handle_periodic_tasks
"s2:timing::next_minute_check" => $anvil->data->{timing}{next_minute_check}, "s2:timing::next_minute_check" => $anvil->data->{timing}{next_minute_check},
}}); }});
# If we're a dashboard, see if the fence information needs to be gathered.
if ($type eq "dashboard")
{
# Even when this runs, it should finish in under ten seconds so we don't need to background it.
my ($parse_output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{'striker-parse-fence-agents'}, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { parse_output => $parse_output }});
}
# Scan the local network. # Scan the local network.
update_state_file($anvil); update_state_file($anvil);
@ -419,9 +429,6 @@ sub handle_periodic_tasks
### NOTE: We call it once/day, but this will also trigger on restart of anvil-daemon. As such, we ### NOTE: We call it once/day, but this will also trigger on restart of anvil-daemon. As such, we
### don't use '--force' and let striker-manage-install-target skip the repo update if it happened ### don't use '--force' and let striker-manage-install-target skip the repo update if it happened
### recently enough. ### recently enough.
my $type = $anvil->System->get_host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type }});
if ($type eq "dashboard") if ($type eq "dashboard")
{ {
# Record a job, don't call it directly. It takes too long to run. # Record a job, don't call it directly. It takes too long to run.

@ -32,7 +32,6 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list
}}); }});
refresh_unified_metadata($anvil); refresh_unified_metadata($anvil);
$anvil->Striker->get_fence_data({debug => 2});
$anvil->nice_exit({exit_code => 0}); $anvil->nice_exit({exit_code => 0});
@ -64,7 +63,7 @@ sub refresh_unified_metadata
my $modified_time = (stat($anvil->data->{path}{data}{fences_unified_metadata}))[9]; my $modified_time = (stat($anvil->data->{path}{data}{fences_unified_metadata}))[9];
my $age = time - $modified_time; my $age = time - $modified_time;
my $maximum_age = ((60 * 60) * 24); my $maximum_age = ((60 * 60) * 24);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
modified_time => $modified_time, modified_time => $modified_time,
age => $age, age => $age,
maximum_age => $maximum_age, maximum_age => $maximum_age,

@ -25,16 +25,63 @@ my $anvil = Anvil::Tools->new({debug => 3});
$anvil->Log->secure({set => 1}); $anvil->Log->secure({set => 1});
$anvil->Log->level({set => 2}); $anvil->Log->level({set => 2});
print "Connecting to the database(s);\b"; #print "Connecting to the database(s);\b";
$anvil->Database->connect({debug => 3}); $anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
print "DB Connections: [".$anvil->data->{sys}{database}{connections}."]\n"; #print "DB Connections: [".$anvil->data->{sys}{database}{connections}."]\n";
#$anvil->Network->load_interfces({debug => 2}); #$anvil->Network->load_interfces({debug => 2});
#$anvil->System->generate_state_json({debug => 2}); #$anvil->System->generate_state_json({debug => 2});
$anvil->Words->language_list(); #$anvil->Words->language_list();
foreach my $iso (sort {$a cmp $b} keys %{$anvil->data->{sys}{languages}}) #foreach my $iso (sort {$a cmp $b} keys %{$anvil->data->{sys}{languages}})
{ #{
print "iso: [".$iso."] -> [".$anvil->data->{sys}{languages}{$iso}."]\n"; # print "iso: [".$iso."] -> [".$anvil->data->{sys}{languages}{$iso}."]\n";
} #}
# $anvil->Striker->get_fence_data({debug => 3});
# foreach my $fence_agent (sort {$a cmp $b} keys %{$anvil->data->{fences}})
# {
# # We skip fence_ipmilan, that's handled in the host.
# next if $fence_agent eq "fence_ipmilan";
#
# my $agent_description = $anvil->data->{fences}{$fence_agent}{description};
# print "Agent: [".$fence_agent."]\n";
# print "==========\n";
# print $agent_description."\n";
# print "==========\n";
# foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fences}{$fence_agent}{parameters}})
# {
# next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{replacement};
# next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{deprecated};
# my $unique = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{unique};
# my $required = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{required};
# my $description = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{description};
# my $switches = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{switches};
# my $type = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{content_type};
# my $star = $required ? "*" : "";
# my $default = exists $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} ? $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} : "";
# print "- [".$name."]".$star.": Type: [".$type."], default: [".$default."], switches: [".$switches."]: [".$description."]\n";
# print " - Unique!\n" if $unique;
#
# if ($type eq "select")
# {
# # Build the select box
# my $options = "";
# foreach my $option (sort @{$anvil->data->{fences}{$fence_agent}{parameters}{$name}{options}})
# {
# if (($default) && ($option eq $default))
# {
# $options .= " - [".$option."]*\n";
# }
# else
# {
# $options .= " - [".$option."]\n";
# }
# }
# print $options;
# }
# }
#
#
# }

Loading…
Cancel
Save