* Created the manifest database table and Database->insert_or_update_manifests().

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 76e9352717
commit 7df405afcb
  1. 1
      Anvil/Tools.pm
  2. 268
      Anvil/Tools/Database.pm
  3. 45
      cgi-bin/striker
  4. 68
      html/skins/alteeve/anvil.html
  5. BIN
      html/skins/alteeve/images/manifest.png
  6. 2
      html/skins/alteeve/images/sources.txt
  7. 53
      share/anvil.sql
  8. 5
      share/words.xml
  9. 23
      tools/anvil-daemon

@ -906,6 +906,7 @@ sub _set_defaults
"updated",
"alert_sent",
"states",
"manifests",
],
failed_connection_log_level => 1,
local_lock_active => 0,

@ -40,6 +40,7 @@ my $THIS_FILE = "Database.pm";
# insert_or_update_ip_addresses
# insert_or_update_jobs
# insert_or_update_mail_servers
# insert_or_update_manifests
# insert_or_update_network_interfaces
# insert_or_update_notifications
# insert_or_update_mac_to_ip
@ -5059,6 +5060,273 @@ WHERE
}
=head2 insert_or_update_mail_servers
This updates (or inserts) a record in the 'manifests' table. This table is used to the "manifests" used to create and repair Anvil! systems.
If there is an error, an empty string is returned. Otherwise, the record's UUID is returned.
Parameters;
=head3 delete (optional)
If set, the C<< manifest_note >> is set to C<< DELETED >>. When set to C<< 1 >>, only the C<< >> is required
=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 manifest_uuid (optional)
When set, this UUID is used to update an existing record. When not passed, the C<< manifest_name >> is used to search for a match. If found, the associated UUID is used and the record is updated.
=head3 manifest_name (required)
This is the name of the manifest. Generally, this is the name of the Anvil! itself. It can be set to something more useful to the user, however.
=head3 manifest_last_ran (required)
This is the unix time when the manifest was last used to (re)build an Anvil! system. Set this to C<< 0 >> if the manifest hasn't been used yet.
=head3 manifest_xml (required)
This is the raw XML containing the manifest.
=head3 manifest_note (optional)
This is a free-form field for saving notes about the mnaifest. If this is set to C<< DELETED >>, it will be ignored in the web interface.
=cut
sub insert_or_update_mail_servers
{
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->insert_or_update_mail_servers()" }});
my $delete = defined $parameter->{'delete'} ? $parameter->{'delete'} : 0;
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $manifest_uuid = defined $parameter->{manifest_uuid} ? $parameter->{manifest_uuid} : "";
my $manifest_name = defined $parameter->{manifest_name} ? $parameter->{manifest_name} : "";
my $manifest_last_ran = defined $parameter->{manifest_last_ran} ? $parameter->{manifest_last_ran} : "";
my $manifest_xml = defined $parameter->{manifest_xml} ? $parameter->{manifest_xml} : "";
my $manifest_note = defined $parameter->{manifest_note} ? $parameter->{manifest_note} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'delete' => $delete,
file => $file,
line => $line,
manifest_uuid => $manifest_uuid,
manifest_name => $manifest_name,
manifest_last_ran => $manifest_last_ran,
manifest_xml => $manifest_xml,
manifest_note => $manifest_note,
}});
# INSERT, but make sure we have enough data first.
if (not $delete)
{
if (not $manifest_xml)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_manifests()", parameter => "manifest_xml" }});
return("");
}
if (not $manifest_name)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_manifests()", parameter => "manifest_name" }});
return("");
}
}
# If we don't have a network interface UUID, try to look one up using the MAC address
if (not $manifest_uuid)
{
# See if I know this NIC by referencing it's MAC and name. The name is needed because virtual
# devices can share the MAC with the real interface.
my $query = "
SELECT
manifest_uuid
FROM
manifests
WHERE
manifest_name = ".$anvil->Database->quote($manifest_name)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$manifest_uuid = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__})->[0]->[0];
$manifest_uuid = "" if not defined $manifest_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_uuid => $manifest_uuid }});
if (($link_only) && (not $manifest_uuid))
{
# Can't INSERT.
return("");
}
}
if ($delete)
{
if (not $manifest_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_manifests()", parameter => "manifest_uuid" }});
return("");
}
else
{
# Delete it
my $query = "SELECT manifest_note FROM manifests WHERE manifest_uuid = ".$anvil->Database->quote($manifest_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_manifest_note = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_manifest_note => $old_manifest_note }});
if ($old_manifest_note ne "DELETED")
{
my $query = "
UPDATE
manifests
SET
manifest_note = 'DELETED',
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
manifest_uuid = ".$anvil->Database->quote($manifest_uuid)."
;";
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
return($manifest_uuid);
}
else
{
# Not found.
return("");
}
}
}
# Now, if we're inserting or updating, we'll need to require different bits.
if ($manifest_uuid)
{
# Update
my $query = "
SELECT
manifest_name,
manifest_last_ran,
manifest_xml,
manifest_note
FROM
manifests
WHERE
manifest_uuid = ".$anvil->Database->quote($manifest_uuid).";
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, uuid => $uuid, 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 manifest_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 => "manifest_uuid", uuid => $manifest_uuid }});
return("");
}
foreach my $row (@{$results})
{
manifest_name,
manifest_last_ran,
manifest_xml,
manifest_note
my $old_manifest_name = $row->[0];
my $old_manifest_last_ran = $row->[1];
my $old_manifest_xml = $row->[2];
my $old_manifest_note = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_manifest_name => $old_manifest_name,
old_manifest_last_ran => $old_manifest_last_ran,
old_manifest_xml => $old_manifest_xml,
old_manifest_note => $old_manifest_note,
}});
# Anything to update? This is a little extra complicated because if a variable was
# not passed in, we want to not compare it.
if (($manifest_name ne $old_manifest_name) or
($manifest_last_ran ne $old_manifest_last_ran) or
($manifest_xml ne $old_manifest_xml) or
($manifest_note ne $old_manifest_note))
{
# UPDATE any rows passed to us.
my $query = "
UPDATE
manifests
SET
manifest_name = ".$anvil->Database->quote($manifest_name).",
manifest_last_ran = ".$anvil->Database->quote($manifest_last_ran).",
manifest_xml = ".$anvil->Database->quote($manifest_xml).",
manifest_note = ".$anvil->Database->quote($manifest_note).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
manifest_uuid = ".$anvil->Database->quote($manifest_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({uuid => $uuid, query => $query, uuid => $uuid, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
}
}
else
{
# And INSERT
$manifest_uuid = $anvil->Get->uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_uuid => $manifest_uuid }});
my $query = "
INSERT INTO
manifests
(
manifest_uuid,
manifest_name,
manifest_last_ran,
manifest_xml,
manifest_note,
modified_date
) VALUES (
".$anvil->Database->quote($manifest_uuid).",
".$anvil->Database->quote($manifest_name).",
".$anvil->Database->quote($manifest_last_ran).",
".$anvil->Database->quote($manifest_xml).",
".$anvil->Database->quote($manifest_note).",
".$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, uuid => $uuid, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0126", variables => { method => "Database->insert_or_update_network_interfaces()" }});
return($manifest_uuid);
}
=head2 insert_or_update_network_interfaces
This updates (or inserts) a record in the 'interfaces' table. This table is used to store physical network interface information.

@ -1502,9 +1502,16 @@ sub process_anvil_menu
{
process_prep_network($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "manifest")
elsif ($anvil->data->{cgi}{task}{value} eq "create")
{
#process_manifest_page($anvil);
if ($anvil->data->{cgi}{subtask}{value} eq "manifest")
{
#process_manifest($anvil);
}
else
{
process_create($anvil);
}
}
else
{
@ -1517,6 +1524,40 @@ sub process_anvil_menu
return(0);
}
# This handles creating an Anvil! from an existing manifest
sub process_create
{
my ($anvil) = @_;
# Show the option to create a new interface.
# Show existing manifests.
### TODO:
# Store the previous CGI variables and display the new fields.
$anvil->data->{form}{back_link} = "?anvil=true";
$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 => "create-menu", variables => {
interface_form => $interface_form,
gateway_form => $say_gateway,
dns_form => $say_dns,
host_name_form => $host_name_form,
bcn_count => $bcn_pair_count,
sn_count => $sn_pair_count,
ifn_count => $ifn_pair_count,
host_uuid => $anvil->data->{cgi}{host_uuid}{value},
host_name => $host_name, # This is the current host name, used to find the data in the all_status.json
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
# This handles configuring a remote target's network interfaces (renaming them, bonding and bridging them).
sub process_prep_network
{

@ -1,3 +1,69 @@
<!-- start create-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 colspan="2" class="title">
#!string!striker_0203!#
</td>
</tr>
<tr>
<td colspan="2">
&nbsp;
</td>
</tr>
<tr>
<td class="main_option_icon">
<a href="?anvil=true&task=create&subtask=manifest"><img src="#!data!skin::url!#/images/manifest.png" class="top_icon" ></a>
</td>
<td class="main_option">
<a href="?anvil=true&task=prep-host">#!string!striker_0204!#</a>
</td>
</tr>
<tr>
<td colspan="2">
&nbsp;
</td>
</tr>
<tr>
<td class="main_option_icon">
&nbsp;
</td>
<td class="main_option">
#!string!striker_0205!#
</td>
</tr>
<tr>
<td class="main_option_icon">
&nbsp;
</td>
<td class="main_option">
<table>
#!variable!existing_manifests!#
</table>
</td>
</tr>
</table>
<!-- end create-menu -->
<!-- start existing-manifest-entry -->
<tr>
<td>
#!variable!run!#
</td>
<td>
#!variable!name!#
</td>
<td>
#!variable!edit!#
</td>
</tr>
<!-- end existing-manifest-entry -->
<!-- start main-menu -->
<table align="center" class="anvil_main_menu">
<script type="text/javascript" src="/skins/alteeve/anvil.js"></script>
@ -52,7 +118,7 @@
<a href="?anvil=true&task=create"><img src="#!data!skin::url!#/images/build-anvil_icon.png" class="top_icon" ></a>
</td>
<td class="main_option">
<a href="?anvil=true&task=sync">#!string!striker_0114!#</a>
<a href="?anvil=true&task=create">#!string!striker_0114!#</a>
</td>
</tr>
</table>

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@ -71,3 +71,5 @@ Reader by Richa from the Noun Project
Delete by Kavya from the Noun Project (https://thenounproject.com/term/delete/860236/)
- delete.png
instructions by Prettycons from the Noun Project (https://thenounproject.com/term/instructions/2081362/)
- manifest.png

@ -1456,6 +1456,59 @@ CREATE TRIGGER trigger_mac_to_ip
FOR EACH ROW EXECUTE PROCEDURE history_mac_to_ip();
-- This stores the information needed to build an Anvil! system.
CREATE TABLE manifests (
manifest_uuid uuid not null primary key,
manifest_name text not null, -- The name of the manifest, defaults to being the Anvil!'s name
manifest_last_ran integer not null, -- This records the last time the manifest was run (in unix time).
manifest_xml text not null, -- The XML body
manifest_note text not null, -- This is set to 'DELETED' when the manifest isn't needed anymore. Otherwise, it's a notepad for the user
modified_date timestamp with time zone not null
);
ALTER TABLE manifests OWNER TO admin;
CREATE TABLE history.manifests (
history_id bigserial,
manifest_uuid uuid,
manifest_name text,
manifest_last_ran integer,
manifest_xml text,
manifest_note text,
modified_date timestamp with time zone
);
ALTER TABLE history.manifests OWNER TO admin;
CREATE FUNCTION history_manifests() RETURNS trigger
AS $$
DECLARE
history_manifests RECORD;
BEGIN
SELECT INTO history_manifests * FROM manifests WHERE manifest_uuid = new.manifest_uuid;
INSERT INTO history.manifests
(manifest_uuid,
manifest_name,
manifest_last_ran,
manifest_xml,
manifest_note,
modified_date)
VALUES
(history_manifests.manifest_uuid,
history_manifests.manifest_name,
history_manifests.manifest_last_ran,
history_manifests.manifest_xml,
history_manifests.manifest_note,
history_manifests.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_manifests() OWNER TO admin;
CREATE TRIGGER trigger_manifests
AFTER INSERT OR UPDATE ON manifests
FOR EACH ROW EXECUTE PROCEDURE history_manifests();
-- ------------------------------------------------------------------------------------------------------- --
-- These are special tables with no history or tracking UUIDs that simply record transient information. --
-- ------------------------------------------------------------------------------------------------------- --

@ -808,6 +808,8 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
<key name="log_0467">Network reconfiguration is complete!</key>
<key name="log_0468">Skipping the OUI parse. The next scheduled parse will be done in: [#!variable!next_parse!#]. Override with '--force'.</key>
<key name="log_0469">The rpm: [#!variable!rpm_path!#] appears to be a problem, removing it.</key>
<key name="log_0470">The network mapping flag has aged out, clearing it.</key>
<key name="log_0471">The network mapping flag is set. If it isn't cleared by the user, it will expire in: [#!variable!timeout!#] second(s).</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>
@ -1066,6 +1068,9 @@ If you are comfortable that the target has changed for a known reason, you can s
<key name="striker_0200">The alert level used for new (and existing) Anvil! systems.</key>
<key name="striker_0201">Existing alert recipients:</key>
<key name="striker_0202">This puts the host into network mapping mode. In this most, most functions are disabled and the link status of network interfaces are closely monitored.</key>
<key name="striker_0203">Create or Run an Install Manifest</key>
<key name="striker_0204">Create a new Install Manifest; The instructions used to assemble/repair a given Anvil! system.</key>
<key name="striker_0205">Existing Manifests:</key>
<!-- These are generally units and appended to numbers -->
<key name="suffix_0001">#!variable!number!#/sec</key>

@ -179,7 +179,7 @@ while(1)
# Reload defaults, re-read the config and then connect to the database(s)
$anvil->refresh();
$anvil->Database->connect({check_if_configured => $check_if_database_is_configured});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0132"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
# Mark that we don't want to check the database now.
$check_if_database_is_configured = 0;
@ -237,8 +237,9 @@ sub check_if_mapping
variable_source_table => "hosts",
variable_source_uuid => $anvil->data->{sys}{host_uuid},
});
my $expire_age = 1200;
my $map_network_age = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:map_network_value' => $map_network_value,
's2:map_network_modified_date' => $map_network_modified_date,
's3:map_network_uuid' => $map_network_uuid,
@ -246,16 +247,17 @@ sub check_if_mapping
if ($map_network_uuid)
{
$map_network_age = time - $map_network_modified_date;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { map_network_age => $map_network_age }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { map_network_age => $map_network_age }});
}
if ($map_network_value)
{
# How long ago was it set?
if ($map_network_age > 1800)
if ($map_network_age >= $expire_age)
{
# Clear it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0470"});
$anvil->Database->insert_or_update_variables({
debug => 2,
debug => 3,
variable_value => 0,
variable_uuid => $map_network_uuid,
update_value_only => 1,
@ -264,14 +266,21 @@ sub check_if_mapping
else
{
# Mark it so we only track the network.
my $say_age = $anvil->Convert->add_commas({number => $expire_age});
my $timeout = $anvil->Convert->add_commas({number => ($expire_age - $map_network_age)});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0471", variables => {
age => $say_age,
timeout => $timeout,
}});
$anvil->data->{sys}{mapping_network} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::mapping_network" => $anvil->data->{sys}{mapping_network} }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::mapping_network" => $anvil->data->{sys}{mapping_network} }});
# Close any open ssh connections.
foreach my $ssh_fh_key (keys %{$anvil->data->{cache}{ssh_fh}})
{
my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
ssh_fh_key => $ssh_fh_key,
ssh_fh => $ssh_fh,
}});

Loading…
Cancel
Save