* Created Database->get_anvils() and ->insert_or_update_anvils().

* Updated the anvils database table to have columns for traching which hosts are used as node 1, node 2 and the DR host.
* Updated Database->get_hosts() to check which, if any, Anvil! a given hosts is attached to.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent c5c75f1ddf
commit e99bfac9be
  1. 540
      Anvil/Tools/Database.pm
  2. 11
      Anvil/Tools/Striker.pm
  3. 296
      cgi-bin/striker
  4. 162
      html/skins/alteeve/anvil.html
  5. 35
      share/anvil.sql
  6. 14
      share/words.xml

@ -20,6 +20,7 @@ my $THIS_FILE = "Database.pm";
# configure_pgsql # configure_pgsql
# connect # connect
# disconnect # disconnect
# get_anvils
# get_fences # get_fences
# get_host_from_uuid # get_host_from_uuid
# get_hosts # get_hosts
@ -1468,6 +1469,167 @@ FROM
} }
=head2 get_anvils
This loads information about all known Anvil! systems as recorded in the C<< anvils >> table.
Data is stored in two hashes, one sorted by C<< anvil_uuid >> and one by C<< anvil_name >>. While loading, any referenced nodes and DR hosts are stored for quick reference as well. Data is stored as:
anvils::anvil_uuid::<anvil_uuid>::anvil_name
anvils::anvil_uuid::<anvil_uuid>::anvil_description
anvils::anvil_uuid::<anvil_uuid>::anvil_password
anvils::anvil_uuid::<anvil_uuid>::anvil_node1_host_uuid
anvils::anvil_uuid::<anvil_uuid>::anvil_node2_host_uuid
anvils::anvil_uuid::<anvil_uuid>::anvil_dr1_host_uuid
anvils::anvil_uuid::<anvil_uuid>::modified_date
anvils::anvil_name::<anvil_name>::anvil_uuid
anvils::anvil_name::<anvil_name>::anvil_description
anvils::anvil_name::<anvil_name>::anvil_password
anvils::anvil_name::<anvil_name>::anvil_node1_host_uuid
anvils::anvil_name::<anvil_name>::anvil_node2_host_uuid
anvils::anvil_name::<anvil_name>::anvil_dr1_host_uuid
anvils::anvil_name::<anvil_name>::modified_date
When a host UUID is stored for either node or the DR host, it will be stored at:
anvils::host_uuid::<host_uuid>::anvil_name
Parameters;
=head3 include_deleted (Optional, default 0)
If set to C<< 1 >>, deleted last_rans are included when loading the data. When C<< 0 >> is set, the default, any C<< anvil_description >> set to C<< DELETED >> are ignored.
=cut
sub get_anvils
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_manifests()" }});
my $include_deleted = defined $parameter->{include_deleted} ? $parameter->{include_deleted} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
include_deleted => $include_deleted,
}});
if (exists $anvil->data->{manifests})
{
delete $anvil->data->{manifests};
}
my $query = "
SELECT
anvil_uuid,
anvil_name,
anvil_description,
anvil_password,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid,
modified_date
FROM
anvils ";
if (not $include_deleted)
{
$query .= "
WHERE
anvil_description != 'DELETED'";
}
$query .= "
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $anvil_uuid = $row->[0];
my $anvil_name = $row->[1];
my $anvil_description = $row->[2];
my $anvil_password = $row->[3];
my $anvil_node1_host_uuid = defined $row->[4] ? $row->[4] : "";
my $anvil_node2_host_uuid = defined $row->[5] ? $row->[5] : "";
my $anvil_dr1_host_uuid = defined $row->[6] ? $row->[6] : "";
my $modified_date = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
anvil_name => $anvil_name,
anvil_description => $anvil_description,
anvil_password => $anvil->Log->is_secure($anvil_password),
anvil_node1_host_uuid => $anvil_node1_host_uuid,
anvil_node2_host_uuid => $anvil_node2_host_uuid,
anvil_dr1_host_uuid => $anvil_dr1_host_uuid,
modified_date => $modified_date,
}});
# Record the data in the hash, too.
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name} = $anvil_name;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_description} = $anvil_description;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password} = $anvil_password;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid} = $anvil_node1_host_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid} = $anvil_node2_host_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid} = $anvil_dr1_host_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{modified_date} = $modified_date;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::anvil_uuid::${anvil_uuid}::anvil_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name},
"anvils::anvil_uuid::${anvil_uuid}::anvil_description" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_description},
"anvils::anvil_uuid::${anvil_uuid}::anvil_password" => $anvil->Log->is_secure($anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}),
"anvils::anvil_uuid::${anvil_uuid}::anvil_node1_host_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid},
"anvils::anvil_uuid::${anvil_uuid}::anvil_node2_host_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid},
"anvils::anvil_uuid::${anvil_uuid}::anvil_dr1_host_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid},
"anvils::anvil_uuid::${anvil_uuid}::modified_date" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{modified_date},
}});
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid} = $anvil_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description} = $anvil_description;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_password} = $anvil_password;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid} = $anvil_node1_host_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid} = $anvil_node2_host_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid} = $anvil_dr1_host_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{modified_date} = $modified_date;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::anvil_name::${anvil_name}::anvil_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid},
"anvils::anvil_name::${anvil_name}::anvil_description" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description},
"anvils::anvil_name::${anvil_name}::anvil_password" => $anvil->Log->is_secure($anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_password}),
"anvils::anvil_name::${anvil_name}::anvil_node1_host_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid},
"anvils::anvil_name::${anvil_name}::anvil_node2_host_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid},
"anvils::anvil_name::${anvil_name}::anvil_dr1_host_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid},
"anvils::anvil_name::${anvil_name}::modified_date" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{modified_date},
}});
if ($anvil_node1_host_uuid)
{
$anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{anvil_name} = $anvil_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_node1_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{anvil_name},
}});
}
if ($anvil_node2_host_uuid)
{
$anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{anvil_name} = $anvil_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_node2_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{anvil_name},
}});
}
if ($anvil_dr1_host_uuid)
{
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_name} = $anvil_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_dr1_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_name},
}});
}
}
return(0);
}
=head2 get_fences =head2 get_fences
This loads the known fence devices into the C<< anvil::data >> hash at: This loads the known fence devices into the C<< anvil::data >> hash at:
@ -1654,7 +1816,18 @@ Each anonymous hash is structured as:
host_type => $host_type, host_type => $host_type,
modified_date => $modified_date, modified_date => $modified_date,
It also sets the variables C<< sys::hosts::by_uuid::<host_uuid> = <host_name> >> and C<< sys::hosts::by_name::<host_name> = <host_uuid> >> per host read, for quick reference. It also sets the variables;
hosts::host_uuid::<host_uuid>::host_name = <host_name>;
hosts::host_uuid::<host_uuid>::host_type = <host_type; node, dr or dashboard>
hosts::host_uuid::<host_uuid>::anvil_name = <anvil_name if associated with an anvil>
And to simplify look-ups by UUID or name;
sys::hosts::by_uuid::<host_uuid> = <host_name>
sys::hosts::by_name::<host_name> = <host_uuid>
To prevent some cases of recursion, C<< hosts::loaded >> is set on successful load, and if this is set, this method immediately returns with C<< 0 >>.
=cut =cut
sub get_hosts sub get_hosts
@ -1665,6 +1838,12 @@ sub get_hosts
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_hosts()" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_hosts()" }});
# This prevents some recursive loops, like when Database->insert_or_update_anvils() is called.
return(0) if $anvil->data->{hosts}{loaded};
# Load anvils. If a host is registered with an Anvil!, we'll note it.
$anvil->Database->get_anvils({debug => $debug});
my $query = " my $query = "
SELECT SELECT
host_uuid, host_uuid,
@ -1695,6 +1874,14 @@ FROM
host_type => $host_type, host_type => $host_type,
modified_date => $modified_date, modified_date => $modified_date,
}}); }});
my $anvil_name = "";
if ((exists $anvil->data->{anvils}{host_uuid}{$host_uuid}) && ($anvil->data->{anvils}{host_uuid}{$host_uuid}{anvil_name}))
{
$anvil_name = $anvil->data->{anvils}{host_uuid}{$host_uuid}{anvil_name};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_name => $anvil_name }});
push @{$return}, { push @{$return}, {
host_uuid => $host_uuid, host_uuid => $host_uuid,
host_name => $host_name, host_name => $host_name,
@ -1703,11 +1890,13 @@ FROM
}; };
# Record the data in the hash, too. # Record the data in the hash, too.
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name} = $host_name; $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name} = $host_name;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type} = $host_type; $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type} = $host_type;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name} = $anvil_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"hosts::host_uuid::${host_uuid}::host_name" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name}, "hosts::host_uuid::${host_uuid}::host_name" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name},
"hosts::host_uuid::${host_uuid}::host_type" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type}, "hosts::host_uuid::${host_uuid}::host_type" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type},
"hosts::host_uuid::${host_uuid}::anvil_name" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name},
}}); }});
# Record the host_uuid in a hash so that the name can be easily retrieved. # Record the host_uuid in a hash so that the name can be easily retrieved.
@ -1719,6 +1908,8 @@ FROM
}}); }});
} }
$anvil->data->{hosts}{loaded} = 1;
my $return_count = @{$return}; my $return_count = @{$return};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_count => $return_count }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_count => $return_count }});
return($return); return($return);
@ -2678,9 +2869,326 @@ sub initialize
=head2 insert_or_update_anvils =head2 insert_or_update_anvils
This updates (or inserts) a record in the C<< anvils >> table. The C<< anvil_uuid >> referencing the database row will be returned.
If there is an error, an empty string is returned.
Parameters;
=head3 uuid (optional)
If set, only the corresponding database will be written to.
=head3 file (optional)
If set, this is the file name logged as the source of any INSERTs or UPDATEs.
=head3 line (optional)
If set, this is the file line number logged as the source of any INSERTs or UPDATEs.
=head3 anvil_description (optional)
This is a free-form description for this Anvil! system. If this is set to C<< DELETED >>, the Anvil! will be considered to be deleted and no longer used.
=head3 anvil_dr1_host_uuid (optional)
This is the C<< hosts >> -> C<< host_uuid >> of the machine that is used as the DR host.
B<< Note >>: If set, there must be a matching C<< hosts >> -> C<< host_uuid >> in the database.
=head3 anvil_name (required)
This is the anvil's name. It is usually in the format C<< <prefix>-anvil-<zero-padded-sequence> >>.
=head3 anvil_password (required)
This is the password used for this Anvil! system. Specifically, it is used to set the IPMI BMC user and for C<< hacluster >> and C<< root >> system users.
=head3 anvil_uuid (optional)
If not passed, a check will be made to see if an existing entry is found for C<< anvil_name >>. If found, that entry will be updated. If not found, a new record will be inserted.
=head3 anvil_node1_host_uuid (optional)
This is the C<< hosts >> -> C<< host_uuid >> of the machine that is used as node 1.
B<< Note >>: If set, there must be a matching C<< hosts >> -> C<< host_uuid >> in the database.
=head3 anvil_node2_host_uuid (optional)
This is the C<< hosts >> -> C<< host_uuid >> of the machine that is used as node 2.
B<< Note >>: If set, there must be a matching C<< hosts >> -> C<< host_uuid >> in the database.
=head3 delete (optional, default '0')
If set to C<< 1 >>, C<< anvil_description >> will be set to C<< DELETED >>, indicating that the anvil has been deleted from the system. If set, only C<< anvil_uuid >> or C<< anvil_name >> is needed.
=cut =cut
sub insert_or_update_anvils sub insert_or_update_anvils
{ {
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->initialize()" }});
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $delete = defined $parameter->{'delete'} ? $parameter->{'delete'} : "";
my $anvil_uuid = defined $parameter->{anvil_uuid} ? $parameter->{anvil_uuid} : "";
my $anvil_description = defined $parameter->{anvil_description} ? $parameter->{anvil_description} : $anvil->data->{sys}{host_uuid};
my $anvil_name = defined $parameter->{anvil_name} ? $parameter->{anvil_name} : "";
my $anvil_password = defined $parameter->{anvil_password} ? $parameter->{anvil_password} : "";
my $anvil_node1_host_uuid = defined $parameter->{anvil_node1_host_uuid} ? $parameter->{anvil_node1_host_uuid} : "NULL";
my $anvil_node2_host_uuid = defined $parameter->{anvil_node2_host_uuid} ? $parameter->{anvil_node2_host_uuid} : "NULL";
my $anvil_dr1_host_uuid = defined $parameter->{anvil_dr1_host_uuid} ? $parameter->{anvil_dr1_host_uuid} : "NULL";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
file => $file,
line => $line,
'delete' => $delete,
anvil_uuid => $anvil_uuid,
anvil_description => $anvil_description,
anvil_name => $anvil_name,
anvil_password => $anvil_password,
anvil_node1_host_uuid => $anvil_node1_host_uuid,
anvil_node2_host_uuid => $anvil_node2_host_uuid,
anvil_dr1_host_uuid => $anvil_dr1_host_uuid,
}});
if (not $delete)
{
if (not $anvil_name)
{
# Throw an error and exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_anvils()", parameter => "anvil_name" }});
return("");
}
if (not $anvil_password)
{
# Throw an error and exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_anvils()", parameter => "anvil_password" }});
return("");
}
}
elsif ((not $anvil_name) && (not $anvil_uuid))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0127", variables => { table => "anvils" }});
return("");
}
# If we don't have a UUID, see if we can find one for the given anvil name.
if (not $anvil_uuid)
{
my $query = "
SELECT
anvil_uuid
FROM
anvils
WHERE
anvil_name = ".$anvil->Database->quote($anvil_name)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if ($count)
{
$anvil_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }});
}
}
# Make sure that, if any host_uuid's are passed, that they're valid.
$anvil->Database->get_hosts({debug => $debug}) if not $anvil->data->{hosts}{loaded};
if (($anvil_node1_host_uuid) && (not $anvil->data->{hosts}{host_uuid}{$anvil_node1_host_uuid}{host_name}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0128", variables => { uuid => $anvil_node1_host_uuid, column => "anvil_node1_host_uuid" }});
return("");
}
if (($anvil_node2_host_uuid) && (not $anvil->data->{hosts}{host_uuid}{$anvil_node2_host_uuid}{host_name}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0128", variables => { uuid => $anvil_node2_host_uuid, column => "anvil_node2_host_uuid" }});
return("");
}
if (($anvil_dr1_host_uuid) && (not $anvil->data->{hosts}{host_uuid}{$anvil_dr1_host_uuid}{host_name}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0128", variables => { uuid => $anvil_dr1_host_uuid, column => "anvil_dr1_host_uuid" }});
return("");
}
if ($delete)
{
if (not $anvil_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_anvils()", parameter => "anvil_uuid" }});
return("");
}
else
{
# Delete it
my $query = "SELECT anvil_description FROM anvils WHERE anvil_uuid = ".$anvil->Database->quote($anvil_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if ($count)
{
my $old_anvil_description = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_anvil_description => $old_anvil_description }});
if ($old_anvil_description ne "DELETED")
{
my $query = "
UPDATE
anvils
SET
anvil_description = 'DELETED',
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
anvil_uuid = ".$anvil->Database->quote($anvil_uuid)."
;";
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
return($anvil_uuid);
}
else
{
# Not found.
return("");
}
}
}
# NULL values can't be quoted
my $say_anvil_node1_host_uuid = $anvil_node1_host_uuid eq "NULL" ? "NULL" : $anvil->Database->quote($anvil_node1_host_uuid);
my $say_anvil_node2_host_uuid = $anvil_node2_host_uuid eq "NULL" ? "NULL" : $anvil->Database->quote($anvil_node2_host_uuid);
my $say_anvil_dr1_host_uuid = $anvil_dr1_host_uuid eq "NULL" ? "NULL" : $anvil->Database->quote($anvil_dr1_host_uuid);
# If I still don't have an anvil_uuid, we're INSERT'ing .
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }});
if (not $anvil_uuid)
{
# INSERT
$anvil_uuid = $anvil->Get->uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }});
my $query = "
INSERT INTO
anvils
(
anvil_uuid,
anvil_name,
anvil_description,
anvil_password,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid,
modified_date
) VALUES (
".$anvil->Database->quote($anvil_uuid).",
".$anvil->Database->quote($anvil_name).",
".$anvil->Database->quote($anvil_description).",
".$anvil->Database->quote($anvil_password).",
".$say_anvil_node1_host_uuid.",
".$say_anvil_node2_host_uuid.",
".$say_anvil_dr1_host_uuid.",
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
);
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
else
{
# Query the rest of the values and see if anything changed.
my $query = "
SELECT
anvil_name,
anvil_description,
anvil_password,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid
FROM
anvils
WHERE
anvil_uuid = ".$anvil->Database->quote($anvil_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# I have a anvil_uuid but no matching record. Probably an error.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0216", variables => { uuid_name => "anvil_uuid", uuid => $anvil_uuid }});
return("");
}
foreach my $row (@{$results})
{
my $old_anvil_name = $row->[0];
my $old_anvil_description = $row->[1];
my $old_anvil_password = $row->[2];
my $old_anvil_node1_host_uuid = defined $row->[3] ? $row->[3] : "NULL";
my $old_anvil_node2_host_uuid = defined $row->[4] ? $row->[4] : "NULL";
my $old_anvil_dr1_host_uuid = defined $row->[5] ? $row->[5] : "NULL";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_anvil_name => $old_anvil_name,
old_anvil_description => $old_anvil_description,
old_anvil_password => $old_anvil_password,
old_anvil_node1_host_uuid => $old_anvil_node1_host_uuid,
old_anvil_node2_host_uuid => $old_anvil_node2_host_uuid,
old_anvil_dr1_host_uuid => $old_anvil_dr1_host_uuid,
}});
# Anything change?
if (($old_anvil_name ne $anvil_name) or
($old_anvil_description ne $anvil_description) or
($old_anvil_password ne $anvil_password) or
($old_anvil_node1_host_uuid ne $anvil_node1_host_uuid) or
($old_anvil_node2_host_uuid ne $anvil_node2_host_uuid) or
($old_anvil_dr1_host_uuid ne $anvil_dr1_host_uuid))
{
# Something changed, save.
my $query = "
UPDATE
anvils
SET
anvil_name = ".$anvil->Database->quote($anvil_name).",
anvil_description = ".$anvil->Database->quote($anvil_description).",
anvil_password = ".$anvil->Database->quote($anvil_password).",
anvil_node1_host_uuid = ".$say_anvil_node1_host_uuid.",
anvil_node2_host_uuid = ".$say_anvil_node2_host_uuid.",
anvil_dr1_host_uuid = ".$say_anvil_dr1_host_uuid.",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
anvil_uuid = ".$anvil->Database->quote($anvil_uuid)."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
}
}
return($anvil_uuid);
} }
@ -2724,7 +3232,7 @@ This is the unique identifier for the bridge.
This is the MAC address of the bridge. This is the MAC address of the bridge.
=head3 bridge_mto (optional) =head3 bridge_mtu (optional)
This is the MTU (maximum transfer unit, size in bytes) of the bridge. This is the MTU (maximum transfer unit, size in bytes) of the bridge.
@ -2779,6 +3287,11 @@ sub insert_or_update_bridges
return(""); return("");
} }
} }
elsif ((not $bridge_name) && (not $bridge_uuid))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0127", variables => { table => "bridges" }});
return("");
}
# If we don't have a UUID, see if we can find one for the given bridge server name. # If we don't have a UUID, see if we can find one for the given bridge server name.
if (not $bridge_uuid) if (not $bridge_uuid)
@ -3140,6 +3653,11 @@ sub insert_or_update_bonds
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bond_bridge_uuid => $bond_bridge_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bond_bridge_uuid => $bond_bridge_uuid }});
} }
} }
elsif ((not $bond_name) && (not $bond_uuid))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0127", variables => { table => "bonds" }});
return("");
}
# If we don't have a UUID, see if we can find one for the given bond server name. # If we don't have a UUID, see if we can find one for the given bond server name.
if (not $bond_uuid) if (not $bond_uuid)
@ -5722,6 +6240,11 @@ sub insert_or_update_manifests
return(""); return("");
} }
} }
elsif ((not $manifest_name) && (not $manifest_uuid))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0127", variables => { table => "manifests" }});
return("");
}
# If we don't have a network interface UUID, try to look one up using the MAC address # If we don't have a network interface UUID, try to look one up using the MAC address
if (not $manifest_uuid) if (not $manifest_uuid)
@ -6071,6 +6594,11 @@ sub insert_or_update_network_interfaces
return(""); return("");
} }
} }
elsif ((not $network_interface_name) && (not $network_interface_uuid))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0127", variables => { table => "network_interfaces" }});
return("");
}
# If we don't have a network interface UUID, try to look one up using the MAC address # If we don't have a network interface UUID, try to look one up using the MAC address
if (not $network_interface_uuid) if (not $network_interface_uuid)

@ -770,6 +770,8 @@ The parsed manifest XML is stored as (<machine> == node1, node2 or dr1):
manifests::manifest_uuid::<manifest_uuid>::parsed::name = <Anvil! name> manifests::manifest_uuid::<manifest_uuid>::parsed::name = <Anvil! name>
manifests::manifest_uuid::<manifest_uuid>::parsed::domain = <Anvil! domain name> manifests::manifest_uuid::<manifest_uuid>::parsed::domain = <Anvil! domain name>
manifests::manifest_uuid::<manifest_uuid>::parsed::prefix = <Anvil! prefix>
manifests::manifest_uuid::<manifest_uuid>::parsed::sequence = <Anvil! sequence, zero-padded to two digits>
manifests::manifest_uuid::<manifest_uuid>::parsed::upses::<ups_name>::uuid = <upses -> ups_uuid of named UPS> manifests::manifest_uuid::<manifest_uuid>::parsed::upses::<ups_name>::uuid = <upses -> ups_uuid of named UPS>
manifests::manifest_uuid::<manifest_uuid>::parsed::fences::<fence_name>::uuid = <fences -> fence_uuid of named fence device> manifests::manifest_uuid::<manifest_uuid>::parsed::fences::<fence_name>::uuid = <fences -> fence_uuid of named fence device>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::dns = <DNS to use, default is '8.8.8.8,8.8.4.4'> manifests::manifest_uuid::<manifest_uuid>::parsed::networks::dns = <DNS to use, default is '8.8.8.8,8.8.4.4'>
@ -891,6 +893,15 @@ WHERE
"manifests::manifest_uuid::${manifest_uuid}::parsed::name" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name}, "manifests::manifest_uuid::${manifest_uuid}::parsed::name" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name},
}}); }});
my ($prefix, $sequence) = ($anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name} =~ /^(.*?)-anvil-(\d+)$/);
$sequence = sprintf("%02d", $sequence);
$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{prefix} = $prefix;
$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{sequence} = $sequence;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"manifests::manifest_uuid::${manifest_uuid}::parsed::prefix" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{prefix},
"manifests::manifest_uuid::${manifest_uuid}::parsed::sequence" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{sequence},
}});
foreach my $hash_ref (@{$parsed_xml->{upses}{ups}}) foreach my $hash_ref (@{$parsed_xml->{upses}{ups}})
{ {
my $ups_name = $hash_ref->{name}; my $ups_name = $hash_ref->{name};

@ -1537,47 +1537,243 @@ sub process_anvil_menu
return(0); return(0);
} }
# This handles all aspects of Install Manifests.
sub process_manifests
{
my ($anvil) = @_;
# Are we creating a new manifest?
$anvil->data->{cgi}{manifest_uuid}{value} = "" if not defined $anvil->data->{cgi}{manifest_uuid}{value};
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{alert};
$anvil->data->{cgi}{run}{value} = "" if not defined $anvil->data->{cgi}{run}{value};
$anvil->data->{cgi}{step}{value} = 1 if not defined $anvil->data->{cgi}{step}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::manifest_uuid::value' => $anvil->data->{cgi}{manifest_uuid}{value},
}});
# Are we running a manifest, or creating/editing one?
if (($anvil->data->{cgi}{run}{value}) && ($anvil->Validate->is_uuid({uuid => $anvil->data->{cgi}{manifest_uuid}{value}})))
{
run_manifest($anvil);
}
else
{
handle_manifest($anvil);
}
return(0);
}
# This is an extension to 'handle_manifests' that specifically handles running an install manifest.
sub run_manifest
{
my ($anvil) = @_;
my $manifest_uuid = $anvil->data->{cgi}{manifest_uuid}{value};
my $problem = $anvil->Striker->load_manifest({
debug => 2,
manifest_uuid => $manifest_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
manifest_uuid => $manifest_uuid,
problem => $problem,
}});
if ($problem)
{
# Report a problem and send the user back to the manifests page.
my $message = $anvil->Words->string({key => "warning_0046", variables => { uuid => $manifest_uuid }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
=cut
manifests::manifest_uuid::<manifest_uuid>::parsed::name = <Anvil! name>
manifests::manifest_uuid::<manifest_uuid>::parsed::domain = <Anvil! domain name>
manifests::manifest_uuid::<manifest_uuid>::parsed::prefix = <Anvil! prefix>
manifests::manifest_uuid::<manifest_uuid>::parsed::sequence = <Anvil! sequence, zero-padded to two digits>
manifests::manifest_uuid::<manifest_uuid>::parsed::upses::<ups_name>::uuid = <upses -> ups_uuid of named UPS>
manifests::manifest_uuid::<manifest_uuid>::parsed::fences::<fence_name>::uuid = <fences -> fence_uuid of named fence device>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::dns = <DNS to use, default is '8.8.8.8,8.8.4.4'>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::ntp = <NTP to use, if any>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::mtu = <MTU of network>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::bcn_count = <number of BCNs>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::sn_count = <number of SNs>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::ifn_count = <number of IFNs>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::name::<network_name>::network = <base network ip, ie: 10.255.0.0>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::name::<network_name>::subnet = <subnet mask>
manifests::manifest_uuid::<manifest_uuid>::parsed::networks::name::<network_name>::gateway = <gateway ip, if any>
manifests::manifest_uuid::<manifest_uuid>::parsed::machine::<machine>::name = <host name>
manifests::manifest_uuid::<manifest_uuid>::parsed::machine::<machine>::ipmi_ip = <ip of IPMI BMC, if any>
manifests::manifest_uuid::<manifest_uuid>::parsed::machine::<machine>::fence::<fence_name>::port = <'port' name/number (see fence agent man page)
manifests::manifest_uuid::<manifest_uuid>::parsed::machine::<machine>::ups::<ups_name>::used = <1 if powered by USB, 0 if not>
manifests::manifest_uuid::<manifest_uuid>::parsed::machine::<machine>::network::<network_name>::ip = <ip used on network>
=cut
my $anvil_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name};
my $prefix = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{prefix};
my $sequence = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{sequence};
my $domain = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{domain};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_name => $anvil_name,
prefix => $prefix,
sequence => $sequence,
domain => $domain,
}});
my $node1_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{name};
my $node2_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{name};
my $dr1_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_name => $node1_name,
node2_name => $node2_name,
dr1_name => $dr1_name,
}});
# If confirmed, run!
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
if ($anvil->data->{cgi}{confirm}{value})
{
# Save the jobs!
}
else
{
# Ask the user to choose the targets and confirm the manifest settings.
$anvil->Database->get_hosts();
my $nodes = [];
my $dr_hosts = [];
foreach my $host_uuid (keys %{$anvil->data->{hosts}{host_uuid}})
{
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
my $host_anvil = "";
if ((exists $anvil->data->{hosts}{host_uuid}{$host_uuid}) && ($anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name} ne $anvil_name))
{
$host_anvil = $anvil_name;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
host_name => $host_name,
host_type => $host_type,
host_anvil => $host_anvil,
}});
# Does this host belong to another Anvil! already?
if (($host_anvil) && ($host_anvil ne $anvil_name))
{
# yup, ignore it.
next;
}
if ($host_type eq "node")
{
push @{$nodes}, $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
if ((not defined $anvil->data->{cgi}{node1_host}{value}) && ($host_name eq $node1_name))
{
$anvil->data->{cgi}{node1_host}{value} = $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node1_host::value" => $anvil->data->{cgi}{node1_host}{value} }});
}
elsif ((not defined $anvil->data->{cgi}{node2_host}{value}) && ($host_name eq $node2_name))
{
$anvil->data->{cgi}{node2_host}{value} = $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node2_host::value" => $anvil->data->{cgi}{node2_host}{value} }});
}
}
elsif ($host_type eq "dr")
{
push @{$dr_hosts}, $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
if ((not defined $anvil->data->{cgi}{dr1_host}{value}) && ($host_name eq $dr1_name))
{
$anvil->data->{cgi}{node1_host}{value} = $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dr1_host::value" => $anvil->data->{cgi}{dr1_host}{value} }});
}
}
}
# We're going to need three selects; one for each node and one for DR. The DR is allowed to
# be unselected so it has an empty entry.
my $select_node1 = $anvil->Template->select_form({
name => "node1_host",
options => $nodes,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{node1_host}{value},
class => $anvil->data->{cgi}{node1_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
my $select_node2 = $anvil->Template->select_form({
name => "node2_host",
options => $nodes,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{node2_host}{value},
class => $anvil->data->{cgi}{node2_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
my $select_dr1 = $anvil->Template->select_form({
name => "dr_host",
options => $dr_hosts,
blank => 1,
'sort' => 1,
selected => $anvil->data->{cgi}{dr_host}{value},
class => $anvil->data->{cgi}{dr_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{refresh_link} = "?anvil=true&task=manifests&run=true&manifest_uuid=".$anvil->data->{cgi}{manifest_uuid}{value};
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "run-manifest", variables => {
select_node1 => $select_node1,
select_node2 => $select_node2,
select_dr1 => $select_dr1,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
}
return(0);
}
# This handles creating or editing an Install Manifest. # This handles creating or editing an Install Manifest.
sub handle_manifest sub handle_manifest
{ {
my ($anvil) = @_; my ($anvil) = @_;
$anvil->data->{cgi}{step}{value} = 1 if not defined $anvil->data->{cgi}{step}{value}; $anvil->data->{cgi}{step}{value} = 1 if not defined $anvil->data->{cgi}{step}{value};
$anvil->data->{cgi}{prefix}{value} = "" if not defined $anvil->data->{cgi}{prefix}{value}; $anvil->data->{cgi}{prefix}{value} = "" if not defined $anvil->data->{cgi}{prefix}{value};
$anvil->data->{cgi}{prefix}{alert} = 0 if not defined $anvil->data->{cgi}{prefix}{alert}; $anvil->data->{cgi}{prefix}{alert} = 0 if not defined $anvil->data->{cgi}{prefix}{alert};
$anvil->data->{cgi}{domain}{value} = "" if not defined $anvil->data->{cgi}{domain}{value}; $anvil->data->{cgi}{domain}{value} = "" if not defined $anvil->data->{cgi}{domain}{value};
$anvil->data->{cgi}{domain}{alert} = 0 if not defined $anvil->data->{cgi}{domain}{alert}; $anvil->data->{cgi}{domain}{alert} = 0 if not defined $anvil->data->{cgi}{domain}{alert};
$anvil->data->{cgi}{sequence}{value} = "" if not defined $anvil->data->{cgi}{sequence}{value}; $anvil->data->{cgi}{sequence}{value} = "" if not defined $anvil->data->{cgi}{sequence}{value};
$anvil->data->{cgi}{sequence}{alert} = 0 if not defined $anvil->data->{cgi}{sequence}{alert}; $anvil->data->{cgi}{sequence}{alert} = 0 if not defined $anvil->data->{cgi}{sequence}{alert};
$anvil->data->{cgi}{bcn_count}{value} = 0 if not defined $anvil->data->{cgi}{bcn_count}{value}; $anvil->data->{cgi}{bcn_count}{value} = 0 if not defined $anvil->data->{cgi}{bcn_count}{value};
$anvil->data->{cgi}{bcn_count}{alert} = 0 if not defined $anvil->data->{cgi}{bcn_count}{alert}; $anvil->data->{cgi}{bcn_count}{alert} = 0 if not defined $anvil->data->{cgi}{bcn_count}{alert};
$anvil->data->{cgi}{sn_count}{value} = 0 if not defined $anvil->data->{cgi}{sn_count}{value}; $anvil->data->{cgi}{sn_count}{value} = 0 if not defined $anvil->data->{cgi}{sn_count}{value};
$anvil->data->{cgi}{sn_count}{alert} = 0 if not defined $anvil->data->{cgi}{sn_count}{alert}; $anvil->data->{cgi}{sn_count}{alert} = 0 if not defined $anvil->data->{cgi}{sn_count}{alert};
$anvil->data->{cgi}{ifn_count}{value} = 0 if not defined $anvil->data->{cgi}{ifn_count}{value}; $anvil->data->{cgi}{ifn_count}{value} = 0 if not defined $anvil->data->{cgi}{ifn_count}{value};
$anvil->data->{cgi}{ifn_count}{alert} = 0 if not defined $anvil->data->{cgi}{ifn_count}{alert}; $anvil->data->{cgi}{ifn_count}{alert} = 0 if not defined $anvil->data->{cgi}{ifn_count}{alert};
$anvil->data->{cgi}{dns}{value} = "8.8.8.8,8.8.4.4" if not defined $anvil->data->{cgi}{dns}{value}; $anvil->data->{cgi}{dns}{value} = "8.8.8.8,8.8.4.4" if not defined $anvil->data->{cgi}{dns}{value};
$anvil->data->{cgi}{dns}{alert} = 0 if not defined $anvil->data->{cgi}{dns}{alert}; $anvil->data->{cgi}{dns}{alert} = 0 if not defined $anvil->data->{cgi}{dns}{alert};
$anvil->data->{cgi}{ntp}{value} = "" if not defined $anvil->data->{cgi}{ntp}{value}; $anvil->data->{cgi}{ntp}{value} = "" if not defined $anvil->data->{cgi}{ntp}{value};
$anvil->data->{cgi}{ntp}{alert} = 0 if not defined $anvil->data->{cgi}{ntp}{alert}; $anvil->data->{cgi}{ntp}{alert} = 0 if not defined $anvil->data->{cgi}{ntp}{alert};
$anvil->data->{cgi}{mtu}{value} = 1500 if not defined $anvil->data->{cgi}{mtu}{value}; $anvil->data->{cgi}{mtu}{value} = 1500 if not defined $anvil->data->{cgi}{mtu}{value};
$anvil->data->{cgi}{mtu}{alert} = 0 if not defined $anvil->data->{cgi}{mtu}{alert}; $anvil->data->{cgi}{mtu}{alert} = 0 if not defined $anvil->data->{cgi}{mtu}{alert};
$anvil->data->{cgi}{'delete'}{value} = "" if not defined $anvil->data->{cgi}{'delete'}{alert}; $anvil->data->{cgi}{'delete'}{value} = "" if not defined $anvil->data->{cgi}{'delete'}{alert};
$anvil->data->{cgi}{manifest_uuid}{value} = "" if not defined $anvil->data->{cgi}{manifest_uuid}{alert};
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::step::value" => $anvil->data->{cgi}{step}{value}, "cgi::step::value" => $anvil->data->{cgi}{step}{value},
"cgi::prefix::value" => $anvil->data->{cgi}{prefix}{value}, "cgi::prefix::value" => $anvil->data->{cgi}{prefix}{value},
"cgi::domain::value" => $anvil->data->{cgi}{domain}{value}, "cgi::domain::value" => $anvil->data->{cgi}{domain}{value},
"cgi::sequence::value" => $anvil->data->{cgi}{sequence}{value}, "cgi::sequence::value" => $anvil->data->{cgi}{sequence}{value},
"cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value}, "cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value},
"cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value}, "cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value},
"cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value}, "cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value},
"cgi::dns::value" => $anvil->data->{cgi}{dns}{value}, "cgi::dns::value" => $anvil->data->{cgi}{dns}{value},
"cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value}, "cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value},
"cgi::mtu::value" => $anvil->data->{cgi}{mtu}{value}, "cgi::mtu::value" => $anvil->data->{cgi}{mtu}{value},
"cgi::delete::value" => $anvil->data->{cgi}{'delete'}{value}, "cgi::delete::value" => $anvil->data->{cgi}{'delete'}{value},
"cgi::manifest_uuid::value" => $anvil->data->{cgi}{manifest_uuid}{value},
"cgi::confirm::value" => $anvil->data->{cgi}{confirm}{value},
}}); }});
# Are we deleting a manifest? # Are we deleting a manifest?
@ -2955,36 +3151,6 @@ sub process_create
return(0); return(0);
} }
# This handles all aspects of Install Manifests.
sub process_manifests
{
my ($anvil) = @_;
# Are we creating a new manifest?
$anvil->data->{cgi}{manifest_uuid}{value} = "" if not defined $anvil->data->{cgi}{manifest_uuid}{value};
$anvil->data->{cgi}{run}{value} = "" if not defined $anvil->data->{cgi}{run}{value};
$anvil->data->{cgi}{step}{value} = 1 if not defined $anvil->data->{cgi}{step}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::manifest_uuid::value' => $anvil->data->{cgi}{manifest_uuid}{value},
}});
# Are we running a manifest, or creating/editing one?
if ($anvil->data->{cgi}{run}{value})
{
#run_manifest($anvil);
}
elsif ($anvil->data->{cgi}{manifest_uuid}{value})
{
handle_manifest($anvil);
}
else
{
# Uhhhh...
}
return(0);
}
# This allows the user to tell us about upses. # This allows the user to tell us about upses.
sub process_upses sub process_upses
{ {

@ -79,6 +79,168 @@
</table> </table>
<!-- end create-menu --> <!-- end create-menu -->
<!-- start run-manifest -->
<table align="center" class="anvil_main_menu">
<script type="text/javascript" src="/skins/alteeve/anvil.js"></script>
<tr>
<td>
&nbsp;
</td>
</tr>
<tr>
<td class="title">
#!string!header_0028!#
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
</tr>
<tr>
<td class="description">
#!string!striker_0268!#
</td>
</tr>
<tr>
<td>
<!-- Notes -->
#!string!striker_0269!#
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
</tr>
<tr>
<td>
<form name="run_manifest" action="" method="post">
<table align="center" class="anvil_main_menu">
<tr>
<td>
&nbsp;
</td>
<td class="column_header">
<!-- Node 1 -->
#!string!striker_0255!#
</td>
<td>
&nbsp;
</td>
<td class="column_header">
<!-- Node 2 -->
#!string!striker_0256!#
</td>
<td>
&nbsp;
</td>
<td class="column_header">
<!-- DR Host -->
#!string!striker_0257!#
</td>
</tr>
<tr>
<td class="column_header">
<!-- Machine -->
#!string!header_0029!#:
</td>
<td>
#!variable!select_node1!#
</td>
<td>
&nbsp;
</td>
<td>
#!variable!select_node2!#
</td>
<td>
&nbsp;
</td>
<td>
#!variable!select_dr1!#
</td>
</tr>
<tr>
<td colspan="6">
&nbsp;
</td>
</tr>
<tr>
<td colspan="3">
<input type="submit" name="back" id="back" value="#!string!striker_0098!#" class="button">
</td>
<td colspan="3" style="text-align: right;">
<input type="submit" name="confirm" id="confirm" value="#!string!striker_0206!#" class="button">
</td>
<input type="hidden" name="run" id="run" value="true">
<input type="hidden" name="anvil" id="anvil" value="true">
<input type="hidden" name="task" id="task" value="manifests">
<input type="hidden" name="manifest_uuid" id="manifest_uuid" value="#!data!cgi::manifest_uuid::value!#">
</tr>
</table>
</form>
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
</tr>
<tr>
<td colspan="2">
<table class="centered">
<tr style="border: 1px dotted #7f7f7f;">
<td class="column_header">
<!-- Prefix -->
#!string!striker_0228!# &nbsp;
</td>
<td>
#!string!striker_0246!#
</td>
</tr>
<tr style="border: 1px dotted #7f7f7f;">
<td class="column_header">
<!-- Domain -->
#!string!striker_0007!# &nbsp;
</td>
<td>
#!string!striker_0247!#
</td>
</tr>
<tr style="border: 1px dotted #7f7f7f;">
<td class="column_header">
<!-- Sequence -->
#!string!striker_0229!# &nbsp;
</td>
<td>
#!string!striker_0244!#
</td>
</tr>
<tr style="border: 1px dotted #7f7f7f;">
<td class="column_header">
<!-- IFN Count -->
#!string!striker_0230!#
</td>
<td>
#!string!striker_0245!#
</td>
</tr>
<tr style="border: 1px dotted #7f7f7f;">
<td class="column_header">
<!-- Password note -->
#!string!striker_0051!#
</td>
<td>
#!string!striker_0259!#
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- end run-manifest -->
<!-- start create-menu-existing-manifest-entry --> <!-- start create-menu-existing-manifest-entry -->
<tr style="border: 1px dotted #7f7f7f;"> <tr style="border: 1px dotted #7f7f7f;">
<td> <td>

@ -330,21 +330,31 @@ CREATE TRIGGER trigger_sessions
-- This stores information about Anvil! systems. -- This stores information about Anvil! systems.
CREATE TABLE anvils ( CREATE TABLE anvils (
anvil_uuid uuid not null primary key, anvil_uuid uuid not null primary key,
anvil_name text not null, anvil_name text not null,
anvil_description text not null, -- This is a short, one-line (usually) description of this particular Anvil!. It is displayed in the Anvil! selection list. anvil_description text not null, -- This is a short, one-line (usually) description of this particular Anvil!. It is displayed in the Anvil! selection list.
anvil_password text not null, -- This is the 'hacluster' user password. It is also used to access nodes that don't have a specific password set. anvil_password text not null, -- This is the 'hacluster' user password. It is also used to access nodes that don't have a specific password set.
modified_date timestamp with time zone not null anvil_node1_host_uuid uuid, -- This is the host_uuid of the machine that is used as node 1.
anvil_node2_host_uuid uuid, -- This is the host_uuid of the machine that is used as node 2.
anvil_dr1_host_uuid uuid, -- This is the host_uuid of the machine that is used as DR host.
modified_date timestamp with time zone not null,
FOREIGN KEY(anvil_node1_host_uuid) REFERENCES hosts(host_uuid),
FOREIGN KEY(anvil_node2_host_uuid) REFERENCES hosts(host_uuid),
FOREIGN KEY(anvil_dr1_host_uuid) REFERENCES hosts(host_uuid)
); );
ALTER TABLE anvils OWNER TO admin; ALTER TABLE anvils OWNER TO admin;
CREATE TABLE history.anvils ( CREATE TABLE history.anvils (
history_id bigserial, history_id bigserial,
anvil_uuid uuid, anvil_uuid uuid,
anvil_name text, anvil_name text,
anvil_description text, anvil_description text,
anvil_password text, anvil_password text,
modified_date timestamp with time zone not null anvil_node1_host_uuid uuid,
anvil_node2_host_uuid uuid,
anvil_dr1_host_uuid uuid,
modified_date timestamp with time zone not null
); );
ALTER TABLE history.anvils OWNER TO admin; ALTER TABLE history.anvils OWNER TO admin;
@ -359,6 +369,9 @@ BEGIN
anvil_name, anvil_name,
anvil_description, anvil_description,
anvil_password, anvil_password,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid,
modified_date) modified_date)
VALUES VALUES
(history_anvils.anvil_uuid, (history_anvils.anvil_uuid,

@ -185,6 +185,8 @@ The error was:
<key name="error_0124">The IP address: [#!variable!ip!#] does not appear to be within any of the configured networks.</key> <key name="error_0124">The IP address: [#!variable!ip!#] does not appear to be within any of the configured networks.</key>
<key name="error_0125">The IPv4 address assigned to the IPMI interface on: [#!variable!network!#] is invalid.</key> <key name="error_0125">The IPv4 address assigned to the IPMI interface on: [#!variable!network!#] is invalid.</key>
<key name="error_0126">The IP address: [#!variable!ip!#] does not appear to be in the network: [#!variable!network!#].</key> <key name="error_0126">The IP address: [#!variable!ip!#] does not appear to be in the network: [#!variable!network!#].</key>
<key name="error_0127">I was asked to delete and entry from: [#!variable!table!#] but neither the name or UUID was passed.</key>
<key name="error_0128">The host UUID: [#!variable!uuid!#] was set as the value for: [#!variable!column!#], but that host doesn't appear to exist.</key>
<!-- Table headers --> <!-- Table headers -->
<key name="header_0001">Current Network Interfaces and States</key> <key name="header_0001">Current Network Interfaces and States</key>
@ -215,6 +217,7 @@ The error was:
<key name="header_0026">Host Name</key> <key name="header_0026">Host Name</key>
<key name="header_0027">Brand</key> <key name="header_0027">Brand</key>
<key name="header_0028">Install Manifest</key> <key name="header_0028">Install Manifest</key>
<key name="header_0029">Machine</key>
<!-- Strings used by jobs --> <!-- Strings used by jobs -->
<key name="job_0001">Configure Network</key> <key name="job_0001">Configure Network</key>
@ -1387,6 +1390,16 @@ If you are comfortable that the target has changed for a known reason, you can s
<key name="striker_0265">If the machine is powered by a given UPS, click to check the corresponding box. This information will be used in power loss events to decide what machine should host servers, which should be powered off during load-shed conditions and when to gracefully power off entirely.</key> <key name="striker_0265">If the machine is powered by a given UPS, click to check the corresponding box. This information will be used in power loss events to decide what machine should host servers, which should be powered off during load-shed conditions and when to gracefully power off entirely.</key>
<key name="striker_0266">If your machine has an IPMI BMC, (iDRAC, iLO, iRMC, etc), then you can enter the IP to give it here. Further details will be collected when the manifest runs. Leave blank if the machine doesn't have IPMI.</key> <key name="striker_0266">If your machine has an IPMI BMC, (iDRAC, iLO, iRMC, etc), then you can enter the IP to give it here. Further details will be collected when the manifest runs. Leave blank if the machine doesn't have IPMI.</key>
<key name="striker_0267"><![CDATA[Network: [<span class="code">#!variable!network!#</span>].]]></key> <key name="striker_0267"><![CDATA[Network: [<span class="code">#!variable!network!#</span>].]]></key>
<key name="striker_0268"><![CDATA[Below is the install manifest you've selected to run. Please be sure that the details match how you want the nodes and, optionally, DR host to be set to.]]></key>
<key name="striker_0269"><![CDATA[
A few notes:<br />
<br />
<ul>
<li>A node that is found to be running a server will <b>NOT</b> be changed, except to configure passwordless SSH to the peer node and/or DR host. As such, it is safe to run this manifest when adding a rebuilt node or adding a DR host to a live #!string!brand_0006!# system.</li>
<li>Adding a disaster recovery (DR) host is optional. You can add one later if you don't have one now.</li>
<li>If there are no servers on either node (as it a new #!string!brand_0006!# build), the OSes will be updated. Otherwise, they won't be updated. If the kernel is updated, or the network reconfigured, the node will be rebooted.</li>
</ul>
]]></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>
@ -1555,6 +1568,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="warning_0043">[ Warning ] - The install manifest with the UUID: [#!variable!uuid!#] was not found.</key> <key name="warning_0043">[ Warning ] - The install manifest with the UUID: [#!variable!uuid!#] was not found.</key>
<key name="warning_0044">[ Warning ] - The install manifest: [#!variable!name!#] with the UUID: [#!variable!uuid!#] has already been deleted.</key> <key name="warning_0044">[ Warning ] - The install manifest: [#!variable!name!#] with the UUID: [#!variable!uuid!#] has already been deleted.</key>
<key name="warning_0045">[ Warning ] - The install manifest: [#!variable!name!#] with the UUID: [#!variable!uuid!#] was NOT deleted. The reason may be in the: [#!data!path::log::main!#] log file on this host.</key> <key name="warning_0045">[ Warning ] - The install manifest: [#!variable!name!#] with the UUID: [#!variable!uuid!#] was NOT deleted. The reason may be in the: [#!data!path::log::main!#] log file on this host.</key>
<key name="warning_0046">[ Warning ] - The Install Manifest with the UUID: [#!variable!uuid!#] was not found.</key>
</language> </language>
<!-- 日本語 --> <!-- 日本語 -->

Loading…
Cancel
Save