#!/usr/bin/perl
# 
# This does checks for changes that are needed because of version changes. Over time, checks here can be 
# removed.

use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use Text::Diff;

$| = 1;

my $THIS_FILE           =  ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory   =  ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
	$running_directory =~ s/^\./$ENV{PWD}/;
}

my $anvil = Anvil::Tools->new();

# Get switches
$anvil->Get->switches({list => [], man => $THIS_FILE});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});

$anvil->Database->connect({sensitive => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132" });
if (not $anvil->data->{sys}{database}{connections})
{
	# No databases, exit.
	$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003" });
	$anvil->nice_exit({ exit_code => 1 });
}

my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});

if ($host_type eq "striker")
{
	striker_checks($anvil);
}
elsif ($host_type eq "node")
{
	node_checks($anvil);
}
elsif ($host_type eq "dr")
{
	dr_checks($anvil);
}


$anvil->nice_exit({exit_code => 0});


#############################################################################################################
# Functions                                                                                                 #
#############################################################################################################

# Check for things that need to happen on Striker dashboards.
sub striker_checks
{
	my ($anvil) = @_;
	
	# This checks to make sure that the new network manager columns are in place
	update_network_interfaces($anvil);
	update_bonds($anvil);
	update_bridges($anvil);
	
	# This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists.
	update_file_location_ready($anvil);
	
	# This checks to make sure that the new dr_links table exists, and that existing anvil_dr1_host_uuid 
	# entries are copied.
	update_dr_links($anvil);
	
	# This removes the old anvil_dr1_host_uuid column from the database.
	remove_dr1_host_column($anvil);

	# This replaces anvil_uuid with host_uuid to support more granular location info to support the new
	# multi-target DR system
	update_file_locations($anvil);
	
	# This converts the old/broken 'notifications' tables with the more appropriately named 'alert-override'
	update_notifications($anvil);

	# This adds notes to storage_group_members
	update_storage_group_members($anvil);

	### NOTE: Disabled until review complete
	# This checks to make sure that the 'audits' table exists (added late into M3.0 pre-release)
	update_audits($anvil);
	
	### TODO: Remove these later. This is here to clean up how we used to handle db_in_use and lock_request flags.
	if (1)
	{
		# Broadly clear all states that are '0' now.
		my $queries = [];
		push @{$queries}, "DELETE FROM states WHERE state_name LIKE 'db_in_use::%' AND state_note != '1';";
		push @{$queries}, "DELETE FROM history.variables WHERE variable_name = 'lock_request';";
		push @{$queries}, "DELETE FROM variables WHERE variable_name = 'lock_request';";
		foreach my $query (@{$queries})
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
		}
		$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
	}
	
	# Make sure the server_networks table exists.
	update_server_network($anvil);

	# This adds notes to storage_group_members
	update_host_variables($anvil);
	
	return(0);
}

# Scan scan-drbd to make sure the DRBD resource files device entries have the path removed, which is
# needed for DRBD 9.2.13
sub update_resource_files
{
	my ($anvil) = @_;
	
	my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/scan-drbd/scan-drbd";
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "message_0524"});
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		return_code => $return_code,
	}});
	
	return(0);
}

# Check for things that need to happen on Anvil! Subnodes.
sub node_checks
{
	my ($anvil) = @_;
	
	# RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16
	handle_bz1961562($anvil);
	
	# Scan scan-drbd to make sure the DRBD resource files device entries have the path removed, which is
	# needed for DRBD 9.2.13
	update_resource_files($anvil);
	
	# Make sure DRBD compiled after a kernel upgrade.
	$anvil->DRBD->_initialize_kmod({debug => 2});

	# Make sure logind is update to handle fencing properly
	# see - https://access.redhat.com/solutions/1578823
	$anvil->Cluster->configure_logind({debug => 2});

	return(0);
}

# Check for things that need to happen on DR hosts.
sub dr_checks
{
	my ($anvil) = @_;
	
	# RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16
	handle_bz1961562($anvil);
	
	# Scan scan-drbd to make sure the DRBD resource files device entries have the path removed, which is
	# needed for DRBD 9.2.13
	update_resource_files($anvil);
	
	# Make sure DRBD compiled after a kernel upgrade.
	$anvil->DRBD->_initialize_kmod({debug => 2});

	return(0);
}

# Make sure the server_networks table exists.
sub update_server_network
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = 'anvil' AND table_name = 'server_networks';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			# Add the table.
			my $query = q|
CREATE TABLE server_networks (
    server_network_uuid           uuid                        not null    primary key,
    server_network_server_uuid    uuid                        not null,                   -- This is the servers -> server_uuid of the server
    server_network_mac_address    text                        not null,                   -- This is the MAC address of the interface.
    server_network_vnet_device    text                        not null,                   -- This is the 'vnetX' device used to link the interface to the bridge when the server is running.
    server_network_link_state     text                        not null,                   -- This is the link state (up or down) of the interface. 
    modified_date                 timestamp with time zone    not null, 
    
    FOREIGN KEY(server_network_server_uuid) REFERENCES servers(server_uuid) 
);
ALTER TABLE server_networks OWNER TO admin;

CREATE TABLE history.server_networks (
    history_id                    bigserial,
    server_network_uuid           uuid,
    server_network_server_uuid    uuid, 
    server_network_mac_address    text, 
    server_network_vnet_device    text, 
    server_network_link_state     text, 
    modified_date                 timestamp with time zone    not null
);
ALTER TABLE history.server_networks OWNER TO admin;

CREATE FUNCTION history_server_networks() RETURNS trigger
AS $$
DECLARE
    history_server_networks RECORD;
BEGIN
    SELECT INTO history_server_networks * FROM server_networks WHERE server_network_uuid = new.server_network_uuid;
    INSERT INTO history.server_networks
        (server_network_uuid,
         server_network_server_uuid, 
         server_network_mac_address, 
         server_network_vnet_device, 
         server_network_link_state, 
         modified_date)
    VALUES
        (history_server_networks.server_network_uuid, 
         history_server_networks.server_network_server_uuid, 
         history_server_networks.server_network_mac_address, 
         history_server_networks.server_network_vnet_device, 
         history_server_networks.server_network_link_state, 
         history_server_networks.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_server_networks() OWNER TO admin;

CREATE TRIGGER trigger_server_networks
    AFTER INSERT OR UPDATE ON server_networks
    FOR EACH ROW EXECUTE PROCEDURE history_server_networks();
|;
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	return(0);
}

# 
sub update_dr_links
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = 'anvil' AND table_name = 'dr_links';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			# Add the table.
			my $query = q|
CREATE TABLE dr_links (
    dr_link_uuid          uuid                        not null    primary key, 
    dr_link_host_uuid     uuid                        not null,
    dr_link_anvil_uuid    uuid                        not null,
    dr_link_note          text,                                                 -- Set to 'DELETE' when no longer used.
    modified_date         timestamp with time zone    not null, 
    
    FOREIGN KEY(dr_link_host_uuid) REFERENCES hosts(host_uuid), 
    FOREIGN KEY(dr_link_anvil_uuid) REFERENCES anvils(anvil_uuid) 
);
ALTER TABLE dr_links OWNER TO admin;

CREATE TABLE history.dr_links (
    history_id            bigserial,
    dr_link_uuid          uuid,
    dr_link_host_uuid     uuid,
    dr_link_anvil_uuid    uuid,
    dr_link_note          text, 
    modified_date         timestamp with time zone    not null 
);
ALTER TABLE history.dr_links OWNER TO admin;

CREATE FUNCTION history_dr_links() RETURNS trigger
AS $$
DECLARE
    history_dr_links RECORD;
BEGIN
    SELECT INTO history_dr_links * FROM dr_links WHERE dr_link_uuid = new.dr_link_uuid;
    INSERT INTO history.dr_links
        (dr_link_uuid, 
         dr_link_host_uuid,
         dr_link_anvil_uuid,
         dr_link_note, 
         modified_date)
    VALUES
        (history_dr_links.dr_link_uuid, 
         history_dr_links.dr_link_host_uuid,
         history_dr_links.dr_link_anvil_uuid,
         history_dr_links.dr_link_note, 
         history_dr_links.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_dr_links() OWNER TO admin;

CREATE TRIGGER trigger_dr_links
    AFTER INSERT OR UPDATE ON dr_links
    FOR EACH ROW EXECUTE PROCEDURE history_dr_links();
|;
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	# Now make sure that existing DR entries are copied here.
	$anvil->Database->get_hosts({deubg => 2});
	$anvil->Database->get_dr_links({debug => 2});
	
	foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
	{
		my $anvil_uuid          = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
		my $anvil_dr1_host_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:anvil_name"          => $anvil_name,
			"s2:anvil_uuid"          => $anvil_uuid, 
			"s3:anvil_dr1_host_uuid" => $anvil_dr1_host_uuid, 
		}});
		if ($anvil_dr1_host_uuid)
		{
			my $dr1_host_name = $anvil->data->{hosts}{host_uuid}{$anvil_dr1_host_uuid}{short_host_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr1_host_name => $dr1_host_name }});
			
			if ((not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid})                                          or 
			    (not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$anvil_dr1_host_uuid}) or 
			    (not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$anvil_dr1_host_uuid}{dr_link_uuid}))
			{
				# Add it.
				my $dr_link_uuid = $anvil->Database->insert_or_update_dr_links({
					debug              => 2,
					dr_link_anvil_uuid => $anvil_uuid, 
					dr_link_host_uuid  => $anvil_dr1_host_uuid, 
					dr_link_note       => "auto_generated",
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr1_host_name => $dr1_host_name }});
			}
		}
	}

	return(0);
}

sub remove_dr1_host_column
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'anvils' AND column_name = 'anvil_dr1_host_uuid';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if ($count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.anvils DROP COLUMN anvil_dr1_host_uuid;";
			push @{$queries}, "ALTER TABLE history.anvils DROP COLUMN anvil_dr1_host_uuid;";
			push @{$queries}, "DROP FUNCTION history_anvils() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_anvils() RETURNS trigger
AS $$
DECLARE
    history_anvils RECORD;
BEGIN
    SELECT INTO history_anvils * FROM anvils WHERE anvil_uuid = new.anvil_uuid;
    INSERT INTO history.anvils
        (anvil_uuid, 
         anvil_name, 
         anvil_description, 
         anvil_password, 
         anvil_node1_host_uuid,
         anvil_node2_host_uuid,
         modified_date)
    VALUES
        (history_anvils.anvil_uuid, 
         history_anvils.anvil_name, 
         history_anvils.anvil_description, 
         history_anvils.anvil_password, 
         history_anvils.anvil_node1_host_uuid,
         history_anvils.anvil_node2_host_uuid,
         history_anvils.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_anvils() OWNER TO admin;

CREATE TRIGGER trigger_anvils
    AFTER INSERT OR UPDATE ON anvils
    FOR EACH ROW EXECUTE PROCEDURE history_anvils();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	return(0);
}

sub update_bridges
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'bridges' AND column_name = 'bridge_nm_uuid';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.bridges ADD COLUMN bridge_nm_uuid uuid;";
			push @{$queries}, "ALTER TABLE history.bridges ADD COLUMN bridge_nm_uuid uuid;";
			push @{$queries}, "DROP FUNCTION history_bridges() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_bridges() RETURNS trigger
AS $$
DECLARE
    history_bridges RECORD;
BEGIN
    SELECT INTO history_bridges * FROM bridges WHERE bridge_uuid = new.bridge_uuid;
    INSERT INTO history.bridges
        (bridge_uuid, 
         bridge_host_uuid, 
         bridge_nm_uuid, 
         bridge_name, 
         bridge_id, 
         bridge_mac_address, 
         bridge_mtu, 
         bridge_stp_enabled, 
         modified_date)
    VALUES
        (history_bridges.bridge_uuid, 
         history_bridges.bridge_host_uuid, 
         history_bridges.bridge_nm_uuid, 
         history_bridges.bridge_name, 
         history_bridges.bridge_id, 
         history_bridges.bridge_mac_address, 
         history_bridges.bridge_mtu, 
         history_bridges.bridge_stp_enabled, 
         history_bridges.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_bridges() OWNER TO admin;

CREATE TRIGGER trigger_bridges
    AFTER INSERT OR UPDATE ON bridges
    FOR EACH ROW EXECUTE PROCEDURE history_bridges();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	return(0);
}

sub update_bonds
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'bonds' AND column_name = 'bond_nm_uuid';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.bonds ADD COLUMN bond_nm_uuid uuid;";
			push @{$queries}, "ALTER TABLE history.bonds ADD COLUMN bond_nm_uuid uuid;";
			push @{$queries}, "DROP FUNCTION history_bonds() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_bonds() RETURNS trigger
AS $$
DECLARE
    history_bonds RECORD;
BEGIN
    SELECT INTO history_bonds * FROM bonds WHERE bond_uuid = new.bond_uuid;
    INSERT INTO history.bonds
        (bond_uuid, 
         bond_host_uuid, 
         bond_nm_uuid, 
         bond_name, 
         bond_mode, 
         bond_mtu, 
         bond_primary_interface, 
         bond_primary_reselect, 
         bond_active_interface, 
         bond_mii_polling_interval, 
         bond_up_delay, 
         bond_down_delay, 
         bond_mac_address, 
         bond_operational, 
         bond_bridge_uuid, 
         modified_date)
    VALUES
        (history_bonds.bond_uuid, 
         history_bonds.bond_host_uuid, 
         history_bonds.bond_nm_uuid, 
         history_bonds.bond_name, 
         history_bonds.bond_mode, 
         history_bonds.bond_mtu, 
         history_bonds.bond_primary_interface, 
         history_bonds.bond_primary_reselect, 
         history_bonds.bond_active_interface, 
         history_bonds.bond_mii_polling_interval, 
         history_bonds.bond_up_delay, 
         history_bonds.bond_down_delay, 
         history_bonds.bond_mac_address, 
         history_bonds.bond_operational, 
         history_bonds.bond_bridge_uuid, 
         history_bonds.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_bonds() OWNER TO admin;

CREATE TRIGGER trigger_bonds
    AFTER INSERT OR UPDATE ON bonds
    FOR EACH ROW EXECUTE PROCEDURE history_bonds();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	return(0);
}

sub update_network_interfaces
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'network_interfaces' AND column_name = 'network_interface_device';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.network_interfaces ADD COLUMN network_interface_device text not null DEFAULT '';";
			push @{$queries}, "ALTER TABLE history.network_interfaces ADD COLUMN network_interface_device text;";
			push @{$queries}, "DROP FUNCTION history_network_interfaces() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_network_interfaces() RETURNS trigger
AS $$
DECLARE
    history_network_interfaces RECORD;
BEGIN
    SELECT INTO history_network_interfaces * FROM network_interfaces WHERE network_interface_uuid = new.network_interface_uuid;
    INSERT INTO history.network_interfaces
        (network_interface_uuid,
         network_interface_host_uuid, 
         network_interface_nm_uuid, 
         network_interface_mac_address, 
         network_interface_name,
         network_interface_device, 
         network_interface_speed, 
         network_interface_mtu, 
         network_interface_link_state, 
         network_interface_operational, 
         network_interface_duplex, 
         network_interface_medium, 
         network_interface_bond_uuid, 
         network_interface_bridge_uuid, 
         modified_date)
    VALUES
        (history_network_interfaces.network_interface_uuid,
         history_network_interfaces.network_interface_host_uuid, 
         history_network_interfaces.network_interface_nm_uuid, 
         history_network_interfaces.network_interface_mac_address, 
         history_network_interfaces.network_interface_name,
         history_network_interfaces.network_interface_device, 
         history_network_interfaces.network_interface_speed, 
         history_network_interfaces.network_interface_mtu, 
         history_network_interfaces.network_interface_link_state, 
         history_network_interfaces.network_interface_operational, 
         history_network_interfaces.network_interface_duplex, 
         history_network_interfaces.network_interface_medium, 
         history_network_interfaces.network_interface_bond_uuid, 
         history_network_interfaces.network_interface_bridge_uuid, 
         history_network_interfaces.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_network_interfaces() OWNER TO admin;

CREATE TRIGGER trigger_network_interfaces
    AFTER INSERT OR UPDATE ON network_interfaces
    FOR EACH ROW EXECUTE PROCEDURE history_network_interfaces();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
		
		$query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'network_interfaces' AND column_name = 'network_interface_nm_uuid';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		$count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.network_interfaces ADD COLUMN network_interface_nm_uuid uuid;";
			push @{$queries}, "ALTER TABLE history.network_interfaces ADD COLUMN network_interface_nm_uuid uuid;";
			push @{$queries}, "DROP FUNCTION history_network_interfaces() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_network_interfaces() RETURNS trigger
AS $$
DECLARE
    history_network_interfaces RECORD;
BEGIN
    SELECT INTO history_network_interfaces * FROM network_interfaces WHERE network_interface_uuid = new.network_interface_uuid;
    INSERT INTO history.network_interfaces
        (network_interface_uuid,
         network_interface_host_uuid, 
         network_interface_nm_uuid, 
         network_interface_mac_address, 
         network_interface_name,
         network_interface_device, 
         network_interface_speed, 
         network_interface_mtu, 
         network_interface_link_state, 
         network_interface_operational, 
         network_interface_duplex, 
         network_interface_medium, 
         network_interface_bond_uuid, 
         network_interface_bridge_uuid, 
         modified_date)
    VALUES
        (history_network_interfaces.network_interface_uuid,
         history_network_interfaces.network_interface_host_uuid, 
         history_network_interfaces.network_interface_nm_uuid, 
         history_network_interfaces.network_interface_mac_address, 
         history_network_interfaces.network_interface_name,
         history_network_interfaces.network_interface_device, 
         history_network_interfaces.network_interface_speed, 
         history_network_interfaces.network_interface_mtu, 
         history_network_interfaces.network_interface_link_state, 
         history_network_interfaces.network_interface_operational, 
         history_network_interfaces.network_interface_duplex, 
         history_network_interfaces.network_interface_medium, 
         history_network_interfaces.network_interface_bond_uuid, 
         history_network_interfaces.network_interface_bridge_uuid, 
         history_network_interfaces.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_network_interfaces() OWNER TO admin;

CREATE TRIGGER trigger_network_interfaces
    AFTER INSERT OR UPDATE ON network_interfaces
    FOR EACH ROW EXECUTE PROCEDURE history_network_interfaces();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	
	return(0);
}

# This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists.
sub update_file_location_ready
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'file_locations' AND column_name = 'file_location_ready';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.file_locations ADD COLUMN file_location_ready boolean not null DEFAULT FALSE;";
			push @{$queries}, "ALTER TABLE history.file_locations ADD COLUMN file_location_ready boolean;";
			push @{$queries}, "DROP FUNCTION history_file_locations() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_file_locations() RETURNS trigger
AS $$
DECLARE
    history_file_locations RECORD;
BEGIN
    SELECT INTO history_file_locations * FROM file_locations WHERE file_location_uuid = new.file_location_uuid;
    INSERT INTO history.file_locations
        (file_location_uuid,
         file_location_file_uuid,
         file_location_host_uuid, 
         file_location_active, 
         file_location_ready, 
         modified_date)
    VALUES
        (history_file_locations.file_location_uuid, 
         history_file_locations.file_location_file_uuid,
         history_file_locations.file_location_host_uuid, 
         history_file_locations.file_location_active, 
         history_file_locations.file_location_ready, 
         history_file_locations.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_file_locations() OWNER TO admin;

CREATE TRIGGER trigger_file_locations
    AFTER INSERT OR UPDATE ON file_locations
    FOR EACH ROW EXECUTE PROCEDURE history_file_locations();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	# Now make sure that existing DR entries are copied here.
	$anvil->Database->get_hosts({deubg => 2});
	$anvil->Database->get_dr_links({debug => 2});
	
	foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
	{
		my $anvil_uuid          = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
		my $anvil_dr1_host_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:anvil_name"          => $anvil_name,
			"s2:anvil_uuid"          => $anvil_uuid, 
			"s3:anvil_dr1_host_uuid" => $anvil_dr1_host_uuid, 
		}});
		if ($anvil_dr1_host_uuid)
		{
			my $dr1_host_name = $anvil->data->{hosts}{host_uuid}{$anvil_dr1_host_uuid}{short_host_name};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr1_host_name => $dr1_host_name }});
			
			if ((not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid})                                          or 
			    (not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$anvil_dr1_host_uuid}) or 
			    (not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$anvil_dr1_host_uuid}{dr_link_uuid}))
			{
				# Add it.
				my $dr_link_uuid = $anvil->Database->insert_or_update_dr_links({
					debug              => 2,
					dr_link_anvil_uuid => $anvil_uuid, 
					dr_link_host_uuid  => $anvil_dr1_host_uuid, 
					dr_link_note       => "auto_generated",
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr1_host_name => $dr1_host_name }});
			}
		}
	}
	
	return(0);
}

# This checks to make sure that the 'audits' table exists (added late into M3.0 pre-release)
sub update_audits
{
	my ($anvil) = @_;

	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = 'anvil' AND table_name = 'audits';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if (not $count)
		{
			# Add the table.
			my $query = q|
CREATE TABLE audits (
    audit_uuid           uuid                        primary key,
    audit_user_uuid      uuid                        not null,       -- This is the users -> user_uuid the audit is tracking
    audit_details        text                        not null,       -- This is the information explaining the action being audited.
    modified_date        timestamp with time zone    not null, 
    
    FOREIGN KEY(audit_user_uuid) REFERENCES users(user_uuid)
);
ALTER TABLE audits OWNER TO admin;

CREATE TABLE history.audits (
    history_id           bigserial,
    audit_uuid           uuid, 
    audit_user_uuid      uuid,
    audit_details        text,
    modified_date        timestamp with time zone    not null
);
ALTER TABLE history.audits OWNER TO admin;

CREATE FUNCTION history_audits() RETURNS trigger
AS $$
DECLARE
    history_audits RECORD;
BEGIN
    SELECT INTO history_audits * FROM audits WHERE audit_uuid = new.audit_uuid;
    INSERT INTO history.audits
        (audit_uuid,
         audit_user_uuid, 
         audit_details, 
         modified_date)
    VALUES
        (history_audit.audit_uuid,
         history_audit.audit_user_uuid, 
         history_audit.audit_details, 
         history_audit.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_audits() OWNER TO admin;

CREATE TRIGGER trigger_audits
    AFTER INSERT OR UPDATE ON audits
    FOR EACH ROW EXECUTE PROCEDURE history_audits();
|;
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	return(0);
}

sub update_host_variables
{
	my ($anvil) = @_;

	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'host_variable';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});

		my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});

		if ($count)
		{
			my $queries = [];
			push @{$queries}, "DROP FUNCTION history_host_variable() CASCADE;";
			push @{$queries}, "DROP TABLE history.host_variable;";
			push @{$queries}, "DROP TABLE public.host_variable;";
			push @{$queries}, q|CREATE TABLE host_variables (
    host_variable_uuid         uuid                        not null    primary key,
    host_variable_host_uuid    uuid                        not null,
    host_variable_name         text                        not null,
    host_variable_value        text                        not null,
    modified_date              timestamp with time zone    not null, 
    
    FOREIGN KEY(host_variable_host_uuid) REFERENCES hosts(host_uuid)
);
ALTER TABLE host_variables OWNER TO admin;

CREATE TABLE history.host_variables (
    history_id                 bigserial,
    host_variable_uuid         uuid,
    host_variable_host_uuid    uuid,
    host_variable_name         text,
    host_variable_value        text,
    modified_date              timestamp with time zone    not null
);
ALTER TABLE history.host_variables OWNER TO admin;

CREATE FUNCTION history_host_variables() RETURNS trigger
AS $$
DECLARE
    history_host_variables RECORD;
BEGIN
    SELECT INTO history_host_variables * FROM host_variables WHERE host_variable_uuid = new.host_variable_uuid;
    INSERT INTO history.host_variables
        (host_variable_uuid, 
         host_variable_host_uuid, 
         host_variable_name, 
         host_variable_value, 
         modified_date) 
    VALUES
        (history_host_variables.host_variable_uuid, 
         history_host_variables.host_variable_host_uuid, 
         history_host_variables.host_variable_name, 
         history_host_variables.host_variable_value, 
         history_host_variables.modified_date); 
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_host_variables() OWNER TO admin;

CREATE TRIGGER trigger_host_variables
    AFTER INSERT OR UPDATE ON host_variables
    FOR EACH ROW EXECUTE PROCEDURE history_host_variables();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}

	return(0);
}

sub update_storage_group_members
{
	my ($anvil) = @_;

	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'storage_group_members' AND column_name = 'storage_group_member_note';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});

		my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});

		if (not $count)
		{
			my $queries = [];
			push @{$queries}, "ALTER TABLE public.storage_group_members ADD COLUMN storage_group_member_note text not null DEFAULT '';";
			push @{$queries}, "ALTER TABLE history.storage_group_members ADD COLUMN storage_group_member_note text not null DEFAULT '';";
			push @{$queries}, "DROP FUNCTION history_storage_group_members() CASCADE;";
			push @{$queries}, q|CREATE FUNCTION history_storage_group_members() RETURNS trigger
AS $$
DECLARE
    history_storage_group_members RECORD;
BEGIN
    SELECT INTO history_storage_group_members * FROM storage_group_members WHERE storage_group_member_uuid = new.storage_group_member_uuid;
    INSERT INTO history.storage_group_members
        (storage_group_member_uuid,
         storage_group_member_storage_group_uuid,
         storage_group_member_host_uuid,
         storage_group_member_vg_uuid,
         storage_group_member_note,
         modified_date)
    VALUES
        (history_storage_group_members.storage_group_member_uuid,
	 history_storage_group_members.storage_group_member_storage_group_uuid,
         history_storage_group_members.storage_group_member_host_uuid,
         history_storage_group_members.storage_group_member_vg_uuid,
         history_storage_group_members.storage_group_member_note,
         history_storage_group_members.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_storage_group_members() OWNER TO admin;

CREATE TRIGGER trigger_storage_group_members
    AFTER INSERT OR UPDATE ON storage_group_members
    FOR EACH ROW EXECUTE PROCEDURE history_storage_group_members();|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}

	return(0);
}

# This replaces anvil_uuid with host_uuid to support more granular location info to support the new
# multi-target DR system
sub update_file_locations
{
	my ($anvil) = @_;
	
	my $updated = 0;
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'file_locations' AND column_name = 'file_location_anvil_uuid';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});

		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			uuid  => $uuid, 
			count => $count,
		}});
		
		# Wipe it out, then re-add
		if ($count)
		{
			$updated = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { updated => $updated }});
			
			my $queries = [];
			push @{$queries}, "DROP TABLE public.file_locations;";
			push @{$queries}, "DROP TABLE history.file_locations;";
			push @{$queries}, "DROP FUNCTION history_file_locations() CASCADE;";
			push @{$queries}, q|CREATE TABLE file_locations (
    file_location_uuid         uuid                        not null    primary key,
    file_location_file_uuid    uuid                        not null,                   -- This is file to be moved to (or restored to) this machine.
    file_location_host_uuid    uuid                        not null,                   -- This is the sum as calculated when the file_location is first uploaded. Once recorded, it can't change.
    file_location_active       boolean                     not null    default TRUE,   -- This is set to true when the file should be on Anvil! machines, triggering rsyncs when needed. When set to false, the file will be deleted from members, if they exist.
    modified_date              timestamp with time zone    not null,
    
    FOREIGN KEY(file_location_file_uuid) REFERENCES files(file_uuid), 
    FOREIGN KEY(file_location_host_uuid) REFERENCES hosts(host_uuid)
);
ALTER TABLE file_locations OWNER TO admin;

CREATE TABLE history.file_locations (
    history_id                 bigserial,
    file_location_uuid         uuid,
    file_location_file_uuid    text,
    file_location_host_uuid    uuid,
    file_location_active       boolean,
    modified_date              timestamp with time zone    not null
);
ALTER TABLE history.file_locations OWNER TO admin;

CREATE FUNCTION history_file_locations() RETURNS trigger
AS $$
DECLARE
    history_file_locations RECORD;
BEGIN
    SELECT INTO history_file_locations * FROM file_locations WHERE file_location_uuid = new.file_location_uuid;
    INSERT INTO history.file_locations
        (file_location_uuid,
         file_location_file_uuid,
         file_location_host_uuid, 
         file_location_active, 
         modified_date)
    VALUES
        (history_file_locations.file_location_uuid, 
         history_file_locations.file_location_file_uuid,
         history_file_locations.file_location_host_uuid, 
         history_file_locations.file_location_active, 
         history_file_locations.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_file_locations() OWNER TO admin;

CREATE TRIGGER trigger_file_locations
    AFTER INSERT OR UPDATE ON file_locations
    FOR EACH ROW EXECUTE PROCEDURE history_file_locations();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	# Make sure all files are linked to all nodes and dr_hosts
	if ($updated)
	{
		$anvil->Database->get_hosts();
		$anvil->Database->get_files();
		$anvil->Database->get_file_locations();
		foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{files}{file_name}})
		{
			my $file_uuid = $anvil->data->{files}{file_name}{$file_name}{file_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:file_name' => $file_name,
				's2:file_uuid' => $file_uuid,
			}});
			foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}})
			{
				my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name};
				my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
				my $host_key  = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:host_name' => $host_name,
					's2:host_uuid' => $host_uuid,
					's3:host_type' => $host_type, 
					's4:host_key'  => $host_key,
				}});
				next if $host_type eq "striker";
				next if $host_key  eq "DELETED";
				
				my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
					debug                   => 2, 
					file_location_file_uuid => $file_uuid, 
					file_location_host_uuid => $host_uuid, 
					file_location_active    => 1,
					file_location_ready     => "same",
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }});
			}
		}
	}
	
	return(0);
}

# This converts the old/broken 'notifications' tables with the more appropriately named 'alert-override'
sub update_notifications
{
	my ($anvil) = @_;
	
	foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
	{
		my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = 'anvil' AND table_name = 'notifications';";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		
		if ($count)
		{
			my $queries = [];
			push @{$queries}, "DROP FUNCTION history_notifications() CASCADE;";
			push @{$queries}, "DROP TABLE history.notifications;";
			push @{$queries}, "DROP TABLE public.notifications;";
			push @{$queries}, q|CREATE TABLE alert_overrides (
    alert_override_uuid              uuid                        not null    primary key,
    alert_override_recipient_uuid    uuid                        not null,                    -- The recipient we're linking.
    alert_override_host_uuid         uuid                        not null,                    -- This host_uuid of the referenced machine
    alert_override_alert_level       integer                     not null,                    -- This is the alert level (at or above) that this user wants alerts from. If set to '-1', the record is deleted.
    modified_date                  timestamp with time zone    not null,
    
    FOREIGN KEY(alert_override_host_uuid)      REFERENCES hosts(host_uuid),
    FOREIGN KEY(alert_override_recipient_uuid) REFERENCES recipients(recipient_uuid)
);
ALTER TABLE alert_overrides OWNER TO admin;

CREATE TABLE history.alert_overrides (
    history_id                     bigserial,
    alert_override_uuid              uuid,
    alert_override_recipient_uuid    uuid,
    alert_override_host_uuid         uuid,
    alert_override_alert_level       integer,
    modified_date                  timestamp with time zone    not null
);
ALTER TABLE history.alert_overrides OWNER TO admin;

CREATE FUNCTION history_alert_overrides() RETURNS trigger
AS $$
DECLARE
    history_alert_overrides RECORD;
BEGIN
    SELECT INTO history_alert_overrides * FROM alert_overrides WHERE alert_override_uuid = new.alert_override_uuid;
    INSERT INTO history.alert_overrides
        (alert_override_uuid, 
         alert_override_recipient_uuid, 
         alert_override_host_uuid, 
         alert_override_alert_level, 
         modified_date)
    VALUES
        (history_alert_overrides.alert_override_uuid,
         history_alert_overrides.alert_override_recipient_uuid, 
         history_alert_overrides.alert_override_host_uuid, 
         history_alert_overrides.alert_override_alert_level, 
         history_alert_overrides.modified_date);
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_alert_overrides() OWNER TO admin;

CREATE TRIGGER trigger_alert_overrides
    AFTER INSERT OR UPDATE ON alert_overrides
    FOR EACH ROW EXECUTE PROCEDURE history_alert_overrides();
|;
			foreach my $query (@{$queries})
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
			}
			$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	return(0);
}

sub handle_bz1961562
{
	my ($anvil) = @_;
	
	### TODO: Test that this is fixed. The bug is now ERRATA
	# RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16
	# We're a node or DR host. We need to touch this file.
	my $work_around_file = "/etc/qemu/firmware/50-edk2-ovmf-cc.json";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { work_around_file => $work_around_file }});
	if (not -e $work_around_file)
	{
		$anvil->Storage->write_file({
			debug     => 2,
			file      => $work_around_file, 
			body      => "", 
			overwrite => 0,
			backup    => 0,
			mode      => "0644", 
			user      => "root", 
			group     => "root",
		});
	}
	
	return(0);
}
