diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 5862c090..87ed9f6e 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1069,6 +1069,7 @@ sub _set_paths 'journald.conf' => "/etc/systemd/journald.conf", 'logind.conf' => "/etc/systemd/logind.conf", 'lvm.conf' => "/etc/lvm/lvm.conf", + 'persistent-net' => "/etc/udev/rules.d/70-persistent-net.rules", 'pg_hba.conf' => "/var/lib/pgsql/data/pg_hba.conf", 'postgresql.conf' => "/var/lib/pgsql/data/postgresql.conf", pxe_default => "/var/lib/tftpboot/pxelinux.cfg/default", @@ -1078,6 +1079,7 @@ sub _set_paths postfix_relay_password => "/etc/postfix/relay_password", 'qemu.conf' => "/etc/libvirt/qemu.conf", ssh_config => "/etc/ssh/ssh_config", + sshd_root_password => "/etc/ssh/sshd_config.d/01-permitrootlogin.conf", 'type.striker' => "/etc/anvil/type.striker", 'type.dr' => "/etc/anvil/type.dr", 'type.node' => "/etc/anvil/type.node", @@ -1129,6 +1131,7 @@ sub _set_paths provision => "/mnt/shared/provision", temp => "/mnt/shared/temp", }, + 'sshd_config.d' => "/etc/ssh/sshd_config.d", skins => "/var/www/html/skins", status => "/var/www/html/status", syslinux => "/usr/share/syslinux", @@ -1169,7 +1172,6 @@ sub _set_paths 'anvil-special-operations' => "/usr/sbin/anvil-special-operations", 'anvil-sync-shared' => "/usr/sbin/anvil-sync-shared", 'anvil-update-files' => "/usr/sbin/anvil-update-files", - 'anvil-update-states' => "/usr/sbin/anvil-update-states", 'anvil-update-system' => "/usr/sbin/anvil-update-system", 'anvil-version-changes' => "/usr/sbin/anvil-version-changes", augtool => "/usr/bin/augtool", @@ -1195,6 +1197,7 @@ sub _set_paths df => "/usr/bin/df", dmidecode => "/usr/sbin/dmidecode", dnf => "/usr/bin/dnf", + dracut => "/usr/bin/dracut", drbdadm => "/usr/sbin/drbdadm", drbdsetup => "/usr/sbin/drbdsetup", dropdb => "/usr/bin/dropdb", @@ -1210,6 +1213,7 @@ sub _set_paths 'grep' => "/usr/bin/grep", groupadd => "/usr/sbin/groupadd", head => "/usr/bin/head", + hostname => "/usr/bin/hostname", hostnamectl => "/usr/bin/hostnamectl", hpacucli => "/usr/sbin/hpacucli", htpasswd => "/usr/bin/htpasswd", diff --git a/Anvil/Tools/Cluster.pm b/Anvil/Tools/Cluster.pm index 13aabc84..eab943da 100644 --- a/Anvil/Tools/Cluster.pm +++ b/Anvil/Tools/Cluster.pm @@ -105,6 +105,10 @@ This takes a server name, finds where it is running and then adds it to pacemake Parameters; +=head3 ok_if_exists (optional, default '0') + +Normally, if the server is already in the cluster, C<< !!error!! >> is returned. If this is set to C<< 1 >> and the server is already in pacemaker, we'll return C<< 0 >> instead. + =head3 server_name (required) This is the name of the server being added. @@ -118,9 +122,11 @@ sub add_server my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Cluster->add_server()" }}); - my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; + my $ok_if_exists = defined $parameter->{ok_if_exists} ? $parameter->{ok_if_exists} : ""; + my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - server_name => $server_name, + ok_if_exists => $ok_if_exists, + server_name => $server_name, }}); if (not $server_name) @@ -146,6 +152,10 @@ sub add_server $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cib::parsed::cib::resources::primitive::${server_name}::type" => $anvil->data->{cib}{parsed}{cib}{resources}{primitive}{$server_name}{type}, }}); + if ($ok_if_exists) + { + return(0); + } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0213", variables => { server_name => $server_name }}); return("!!error!!"); } diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index a7002d58..090fa04b 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -786,7 +786,11 @@ If the system is already configured, this method will do nothing, so it is safe If the method completes, C<< 0 >> is returned. If this method is called without C<< root >> access, it returns C<< 1 >> without doing anything. If there is a problem, C<< !!error!! >> is returned. -This method takes no parameters. +Parameters; + +=head3 check_db_exists (optional, default 0) + +If set, the database will be checked to see if the schema exists. This is normally not needed, but can be triggered if the database was DROP'ed by a user. =cut ### TODO: Much of this logic is in striker-prep-database, consolidate! @@ -797,6 +801,11 @@ sub configure_pgsql 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->configure_pgsql()" }}); + + my $check_db_exists = defined $parameter->{check_db_exists} ? $parameter->{check_db_exists} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + check_db_exists => $check_db_exists, + }}); # The local host_uuid is the ID of the local database, so get that. my $uuid = $anvil->Get->host_uuid(); @@ -971,7 +980,7 @@ sub configure_pgsql { # Did we initialize? $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { initialized => $initialized }}); - if ($initialized) + if (($initialized) or (not $running)) { # Start the daemon. my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{postgresql}}); @@ -1012,7 +1021,7 @@ sub configure_pgsql 's2:update_postgresql_file' => $update_postgresql_file, 's3:update_pg_hba_file' => $update_pg_hba_file, }}); - if (($initialized) or ($update_postgresql_file) or ($update_pg_hba_file)) + if (($initialized) or ($update_postgresql_file) or ($update_pg_hba_file) or ($check_db_exists)) { # Create the .pgpass file, if needed. my $created_pgpass = 0; @@ -1366,7 +1375,11 @@ sub connect # This method just returns if nothing is needed. if (($local_host_type eq "striker") && ($check_if_configured) && ($< == 0) && ($> == 0)) { - $anvil->Database->configure_pgsql({debug => 2, uuid => $local_host_uuid}); + $anvil->Database->configure_pgsql({ + debug => 2, + uuid => $local_host_uuid, + check_db_exists => $check_if_configured, + }); } # Now setup or however-many connections @@ -1675,7 +1688,6 @@ sub connect $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, 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 => $debug, list => { count => $count }}); if ($count < 1) { @@ -1765,6 +1777,9 @@ sub connect # Record this as successful $anvil->data->{sys}{database}{connections}++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::database::connections" => $anvil->data->{sys}{database}{connections}, + }}); push @{$successful_connections}, $uuid; } @@ -1825,6 +1840,9 @@ sub connect $anvil->data->{sys}{database}{primary_db} = "" if $anvil->data->{sys}{database}{read_active} eq $uuid; $anvil->data->{sys}{database}{read_uuid} = "" if $anvil->data->{sys}{database}{read_uuid} eq $uuid; $anvil->data->{sys}{database}{connections}--; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::database::connections" => $anvil->data->{sys}{database}{connections}, + }}); delete $anvil->data->{database}{$uuid}; next; } @@ -3971,7 +3989,7 @@ AND }}); $anvil->data->{host_from_uuid}{$host_uuid}{full} = $host_name; - $anvil->data->{host_from_uuid}{$host_uuid}{short} = $short_host_name; + $anvil->data->{host_from_uuid}{$host_uuid}{short} = $short_host_name ? $short_host_name : $host_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "host_from_uuid::${host_uuid}::full" => $anvil->data->{host_from_uuid}{$host_uuid}{full}, "host_from_uuid::${host_uuid}::short" => $anvil->data->{host_from_uuid}{$host_uuid}{short}, @@ -4470,7 +4488,8 @@ AND $query = " SELECT network_interface_uuid, - network_interface_name + network_interface_name, + network_interface_device FROM network_interfaces WHERE @@ -4488,14 +4507,18 @@ AND }}); foreach my $row (@{$results}) { - my $network_interface_uuid = $row->[0]; - my $network_interface_name = $row->[1]; + my $network_interface_uuid = $row->[0]; + my $network_interface_name = $row->[1]; + my $network_interface_device = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - network_interface_uuid => $network_interface_uuid, - network_interface_name => $network_interface_name, + network_interface_uuid => $network_interface_uuid, + network_interface_name => $network_interface_name, + network_interface_device => $network_interface_device, }}); - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; + # The interface_device is the name used by 'ip addr list', and the name is the 'enX' + # biosdevname device. So we only use the name now if there is no device. + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_device ? $network_interface_device : $network_interface_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hosts::host_uuid::${host_uuid}::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, }}); @@ -4561,51 +4584,37 @@ AND $on_interface = $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$ip_address_on_uuid}{network_interface_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { on_interface => $on_interface }}); } - my $on_network = ($on_interface =~ /^(.*?)_/)[0]; - if (not defined $on_network) - { - # This isn't a network we should know about (ie: it might be a stray 'virbrX' - # birdge), delete this IP. - my $query = " -UPDATE - ip_addresses -SET - ip_address_note = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid)." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); - next; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { on_network => $on_network }}); - # Store it. - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address} = $ip_address_address; - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask} = $ip_address_subnet_mask; - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface} = $on_interface; + # We want to be able to map IPs to hosts. + $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid} = $ip_address_host_uuid; + $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid} = $ip_address_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "hosts::host_uuid::${host_uuid}::network::${on_network}::ip_address" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address}, - "hosts::host_uuid::${host_uuid}::network::${on_network}::subnet_mask" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask}, - "hosts::host_uuid::${host_uuid}::network::${on_network}::on_interface" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface}, + "ip_addresses::${ip_address_address}::host_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid}, + "ip_addresses::${ip_address_address}::ip_address_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid}, }}); $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{subnet_mask} = $ip_address_subnet_mask; $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_interface} = $on_interface; - $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network} = $on_network; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::subnet_mask" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{subnet_mask}, "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::on_interface" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_interface}, - "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::on_network" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network}, }}); - # We also want to be able to map IPs to hosts. - $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid} = $ip_address_host_uuid; - $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid} = $ip_address_uuid; + # If this is an interface that doesn't belong to us, we're done. + my $on_network = ($on_interface =~ /^(.*?)_/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { on_network => $on_network }}); + next if not $on_network; + + # Store it by network. + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address} = $ip_address_address; + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask} = $ip_address_subnet_mask; + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface} = $on_interface; + $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network} = $on_network; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "ip_addresses::${ip_address_address}::host_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid}, - "ip_addresses::${ip_address_address}::ip_address_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid}, + "hosts::host_uuid::${host_uuid}::network::${on_network}::ip_address" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address}, + "hosts::host_uuid::${host_uuid}::network::${on_network}::subnet_mask" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask}, + "hosts::host_uuid::${host_uuid}::network::${on_network}::on_interface" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface}, + "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::on_network" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network}, }}); } @@ -6948,6 +6957,7 @@ sub initialize $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { sql => $sql }}); # In the off chance that the database user isn't 'admin', update the SQL file. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }}); if ($user ne "admin") { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0253", variables => { database_user => $user }}); @@ -6968,11 +6978,12 @@ sub initialize # Now that I am ready, disable autocommit, write and commit. $anvil->Database->write({ - debug => $debug, - uuid => $uuid, - query => $sql, - source => $THIS_FILE, - line => __LINE__, + debug => $debug, + uuid => $uuid, + query => $sql, + initializing => 1, + source => $THIS_FILE, + line => __LINE__, }); $anvil->data->{sys}{db_initialized}{$uuid} = 1; @@ -7522,7 +7533,6 @@ WHERE return($anvil_uuid); } - =head2 insert_or_update_bridges This updates (or inserts) a record in the 'bridges' table. The C<< bridge_uuid >> referencing the database row will be returned. @@ -7555,6 +7565,10 @@ This is the host that the IP address is on. If not passed, the local C<< sys::ho This is the bridge's device name. +=head3 bridge_nm_uuid (optional) + +This is the network manager UUID for the bridge. + =head3 bridge_id (optional) This is the unique identifier for the bridge. @@ -7591,6 +7605,7 @@ sub insert_or_update_bridges my $bridge_uuid = defined $parameter->{bridge_uuid} ? $parameter->{bridge_uuid} : ""; my $bridge_host_uuid = defined $parameter->{bridge_host_uuid} ? $parameter->{bridge_host_uuid} : $anvil->data->{sys}{host_uuid}; my $bridge_name = defined $parameter->{bridge_name} ? $parameter->{bridge_name} : ""; + my $bridge_nm_uuid = $parameter->{bridge_nm_uuid} ? $parameter->{bridge_nm_uuid} : 'NULL'; my $bridge_id = defined $parameter->{bridge_id} ? $parameter->{bridge_id} : ""; my $bridge_mac_address = defined $parameter->{bridge_mac_address} ? $parameter->{bridge_mac_address} : ""; my $bridge_mtu = defined $parameter->{bridge_mtu} ? $parameter->{bridge_mtu} : ""; @@ -7603,6 +7618,7 @@ sub insert_or_update_bridges bridge_uuid => $bridge_uuid, bridge_host_uuid => $bridge_host_uuid, bridge_name => $bridge_name, + bridge_nm_uuid => $bridge_nm_uuid, bridge_id => $bridge_id, bridge_mac_address => $bridge_mac_address, bridge_mtu => $bridge_mtu, @@ -7735,6 +7751,7 @@ INSERT INTO ( bridge_uuid, bridge_host_uuid, + bridge_nm_uuid, bridge_name, bridge_id, bridge_mac_address, @@ -7744,6 +7761,7 @@ INSERT INTO ) VALUES ( ".$anvil->Database->quote($bridge_uuid).", ".$anvil->Database->quote($bridge_host_uuid).", + ".$anvil->Database->quote($bridge_nm_uuid).", ".$anvil->Database->quote($bridge_name).", ".$anvil->Database->quote($bridge_id).", ".$anvil->Database->quote($bridge_mac_address).", @@ -7752,6 +7770,7 @@ INSERT INTO ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." ); "; + $query =~ s/'NULL'/NULL/g; $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__}); } @@ -7761,6 +7780,7 @@ INSERT INTO my $query = " SELECT bridge_host_uuid, + bridge_nm_uuid, bridge_name, bridge_id, bridge_mac_address, @@ -7787,14 +7807,16 @@ WHERE } foreach my $row (@{$results}) { - my $old_bridge_host_uuid = $row->[0]; - my $old_bridge_name = $row->[1]; - my $old_bridge_id = $row->[2]; - my $old_bridge_mac_address = $row->[3]; - my $old_bridge_mtu = $row->[4]; - my $old_bridge_stp_enabled = $row->[5]; + my $old_bridge_host_uuid = $row->[0]; + my $old_bridge_nm_uuid = defined $row->[1] ? $row->[1] : 'NULL'; + my $old_bridge_name = $row->[2]; + my $old_bridge_id = $row->[3]; + my $old_bridge_mac_address = $row->[4]; + my $old_bridge_mtu = $row->[5]; + my $old_bridge_stp_enabled = $row->[6]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_bridge_host_uuid => $old_bridge_host_uuid, + old_bridge_nm_uuid => $old_bridge_nm_uuid, old_bridge_name => $old_bridge_name, old_bridge_id => $old_bridge_id, old_bridge_mac_address => $old_bridge_mac_address, @@ -7804,6 +7826,7 @@ WHERE # Anything change? if (($old_bridge_host_uuid ne $bridge_host_uuid) or + ($old_bridge_nm_uuid ne $bridge_nm_uuid) or ($old_bridge_name ne $bridge_name) or ($old_bridge_id ne $bridge_id) or ($old_bridge_mac_address ne $bridge_mac_address) or @@ -7816,6 +7839,7 @@ UPDATE bridges SET bridge_host_uuid = ".$anvil->Database->quote($bridge_host_uuid).", + bridge_nm_uuid = ".$anvil->Database->quote($bridge_nm_uuid).", bridge_name = ".$anvil->Database->quote($bridge_name).", bridge_id = ".$anvil->Database->quote($bridge_id).", bridge_mac_address = ".$anvil->Database->quote($bridge_mac_address).", @@ -7825,6 +7849,7 @@ SET WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid)." "; + $query =~ s/'NULL'/NULL/g; $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__}); } @@ -7871,6 +7896,10 @@ This is the host that the IP address is on. If not passed, the local C<< sys::ho This is the bond's device name. +=head3 bond_nm_uuid (optional) + +This is the network manager UUID for this bond. + =head3 bond_mode (required) This is the bonding mode used for this bond. @@ -7931,6 +7960,7 @@ sub insert_or_update_bonds my $bond_uuid = defined $parameter->{bond_uuid} ? $parameter->{bond_uuid} : ""; my $bond_host_uuid = defined $parameter->{bond_host_uuid} ? $parameter->{bond_host_uuid} : $anvil->data->{sys}{host_uuid}; my $bond_name = defined $parameter->{bond_name} ? $parameter->{bond_name} : ""; + my $bond_nm_uuid = $parameter->{bond_nm_uuid} ? $parameter->{bond_nm_uuid} : 'NULL'; my $bond_mode = defined $parameter->{bond_mode} ? $parameter->{bond_mode} : ""; my $bond_mtu = defined $parameter->{bond_mtu} ? $parameter->{bond_mtu} : ""; my $bond_primary_interface = defined $parameter->{bond_primary_interface} ? $parameter->{bond_primary_interface} : ""; @@ -7941,7 +7971,7 @@ sub insert_or_update_bonds my $bond_down_delay = defined $parameter->{bond_down_delay} ? $parameter->{bond_down_delay} : ""; my $bond_mac_address = defined $parameter->{bond_mac_address} ? $parameter->{bond_mac_address} : ""; my $bond_operational = defined $parameter->{bond_operational} ? $parameter->{bond_operational} : ""; - my $bond_bridge_uuid = defined $parameter->{bond_bridge_uuid} ? $parameter->{bond_bridge_uuid} : 'NULL'; + my $bond_bridge_uuid = $parameter->{bond_bridge_uuid} ? $parameter->{bond_bridge_uuid} : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid, file => $file, @@ -7950,6 +7980,7 @@ sub insert_or_update_bonds bond_uuid => $bond_uuid, bond_host_uuid => $bond_host_uuid, bond_name => $bond_name, + bond_nm_uuid => $bond_nm_uuid, bond_mode => $bond_mode, bond_mtu => $bond_mtu, bond_primary_interface => $bond_primary_interface, @@ -8101,6 +8132,7 @@ INSERT INTO ( bond_uuid, bond_host_uuid, + bond_nm_uuid, bond_name, bond_mode, bond_mtu, @@ -8117,6 +8149,7 @@ INSERT INTO ) VALUES ( ".$anvil->Database->quote($bond_uuid).", ".$anvil->Database->quote($bond_host_uuid).", + ".$anvil->Database->quote($bond_nm_uuid).", ".$anvil->Database->quote($bond_name).", ".$anvil->Database->quote($bond_mode).", ".$anvil->Database->quote($bond_mtu).", @@ -8142,6 +8175,7 @@ INSERT INTO my $query = " SELECT bond_host_uuid, + bond_nm_uuid, bond_name, bond_mode, bond_mtu, @@ -8176,20 +8210,22 @@ WHERE foreach my $row (@{$results}) { my $old_bond_host_uuid = $row->[0]; - my $old_bond_name = $row->[1]; - my $old_bond_mode = $row->[2]; - my $old_bond_mtu = $row->[3]; - my $old_bond_primary_interface = $row->[4]; - my $old_bond_primary_reselect = $row->[5]; - my $old_bond_active_interface = $row->[6]; - my $old_bond_mii_polling_interval = $row->[7]; - my $old_bond_up_delay = $row->[8]; - my $old_bond_down_delay = $row->[9]; - my $old_bond_mac_address = $row->[10]; - my $old_bond_operational = $row->[11]; - my $old_bond_bridge_uuid = defined $row->[12] ? $row->[12] : 'NULL'; + my $old_bond_nm_uuid = defined $row->[1] ? $row->[1] : 'NULL'; + my $old_bond_name = $row->[2]; + my $old_bond_mode = $row->[3]; + my $old_bond_mtu = $row->[4]; + my $old_bond_primary_interface = $row->[5]; + my $old_bond_primary_reselect = $row->[6]; + my $old_bond_active_interface = $row->[7]; + my $old_bond_mii_polling_interval = $row->[8]; + my $old_bond_up_delay = $row->[9]; + my $old_bond_down_delay = $row->[10]; + my $old_bond_mac_address = $row->[11]; + my $old_bond_operational = $row->[12]; + my $old_bond_bridge_uuid = defined $row->[13] ? $row->[12] : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_bond_host_uuid => $old_bond_host_uuid, + old_bond_nm_uuid => $old_bond_nm_uuid, old_bond_name => $old_bond_name, old_bond_mode => $old_bond_mode, old_bond_mtu => $old_bond_mtu, @@ -8206,6 +8242,7 @@ WHERE # Anything change? if (($old_bond_host_uuid ne $bond_host_uuid) or + ($old_bond_nm_uuid ne $bond_nm_uuid) or ($old_bond_name ne $bond_name) or ($old_bond_mode ne $bond_mode) or ($old_bond_mtu ne $bond_mtu) or @@ -8225,6 +8262,7 @@ UPDATE bonds SET bond_host_uuid = ".$anvil->Database->quote($bond_host_uuid).", + bond_nm_uuid = ".$anvil->Database->quote($bond_nm_uuid).", bond_name = ".$anvil->Database->quote($bond_name).", bond_mode = ".$anvil->Database->quote($bond_mode).", bond_mtu = ".$anvil->Database->quote($bond_mtu).", @@ -9606,9 +9644,9 @@ sub insert_or_update_hosts my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $host_ipmi = defined $parameter->{host_ipmi} ? $parameter->{host_ipmi} : ""; my $host_key = defined $parameter->{host_key} ? $parameter->{host_key} : ""; - my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : $anvil->Get->host_name; - my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : $anvil->Get->host_type; - my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid; + my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : ""; + my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : ""; + my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : ""; my $host_status = defined $parameter->{host_status} ? $parameter->{host_status} : "no_change"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid, @@ -9624,15 +9662,34 @@ sub insert_or_update_hosts if (not $host_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_hosts()", parameter => "host_name" }}); - return(""); + # Can we get it? + $host_name = $anvil->Get->host_name({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }}); + + if (not $host_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_hosts()", parameter => "host_name" }}); + return(""); + } + } + if (not $host_type) + { + $host_type = $anvil->Get->host_type({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); } if (not $host_uuid) { - # 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_hosts()", parameter => "host_uuid" }}); - return(""); + # Can we get it? + $host_uuid = $anvil->Get->host_uuid({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }}); + + if (not $host_uuid) + { + # 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_hosts()", parameter => "host_uuid" }}); + return(""); + } } # If we're looking at ourselves and we don't have the host_key, read it in. @@ -11364,6 +11421,10 @@ If this interface is part of a bond, this UUID will be the C<< bonds >> -> C<< b If this interface is connected to a bridge, this is the C<< bridges >> -> C<< bridge_uuid >> of that bridge. +=head3 network_interface_device (optional) + +This is the device name (nmcli's GENERAL.IP-IFACE) of the device. This is the name shown in 'ip addr list'. When the interface is down, this will be blank. Use the MAC address ideally, or the 'connection.id' if needed, to find this interface. + =head3 network_interface_duplex (optional) This can be set to C<< full >>, C<< half >> or C<< unknown >>, with the later being the default. @@ -11390,7 +11451,11 @@ This is the maximum transmit unit (MTU) that this interface supports, in bytes p =head3 network_interface_name (required) -This is the current device name for this interface. +This is the nmcli 'connection.id' name (bios device name) for the current device of this interface. If the previously recorded MAC address is no longer found, but a new/unknown interface with this name is found, it is sane to configure the device with this name as the replacement 'network_interface_device'. + +=head3 network_interface_nm_uuid (optional) + +This is the network manager's UUID for this interface. =head3 network_interface_operational (optional) @@ -11420,6 +11485,7 @@ sub insert_or_update_network_interfaces my $link_only = defined $parameter->{link_only} ? $parameter->{link_only} : 0; my $network_interface_bond_uuid = $parameter->{network_interface_bond_uuid} ? $parameter->{network_interface_bond_uuid} : 'NULL'; my $network_interface_bridge_uuid = $parameter->{network_interface_bridge_uuid} ? $parameter->{network_interface_bridge_uuid} : 'NULL'; + my $network_interface_device = defined $parameter->{network_interface_device} ? $parameter->{network_interface_device} : ""; my $network_interface_duplex = defined $parameter->{network_interface_duplex} ? $parameter->{network_interface_duplex} : "unknown"; my $network_interface_host_uuid = defined $parameter->{network_interface_host_uuid} ? $parameter->{network_interface_host_uuid} : $anvil->Get->host_uuid; my $network_interface_link_state = defined $parameter->{network_interface_link_state} ? $parameter->{network_interface_link_state} : "unknown"; @@ -11428,6 +11494,7 @@ sub insert_or_update_network_interfaces my $network_interface_medium = defined $parameter->{network_interface_medium} ? $parameter->{network_interface_medium} : ""; my $network_interface_mtu = defined $parameter->{network_interface_mtu} ? $parameter->{network_interface_mtu} : 0; my $network_interface_name = defined $parameter->{network_interface_name} ? $parameter->{network_interface_name} : ""; + my $network_interface_nm_uuid = defined $parameter->{network_interface_nm_uuid} ? $parameter->{network_interface_nm_uuid} : ""; my $network_interface_speed = defined $parameter->{network_interface_speed} ? $parameter->{network_interface_speed} : 0; my $network_interface_uuid = defined $parameter->{network_interface_uuid} ? $parameter->{network_interface_uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -11438,6 +11505,7 @@ sub insert_or_update_network_interfaces link_only => $link_only, network_interface_bond_uuid => $network_interface_bond_uuid, network_interface_bridge_uuid => $network_interface_bridge_uuid, + network_interface_device => $network_interface_device, network_interface_duplex => $network_interface_duplex, network_interface_host_uuid => $network_interface_host_uuid, network_interface_link_state => $network_interface_link_state, @@ -11446,6 +11514,7 @@ sub insert_or_update_network_interfaces network_interface_medium => $network_interface_medium, network_interface_mtu => $network_interface_mtu, network_interface_name => $network_interface_name, + network_interface_nm_uuid => $network_interface_nm_uuid, network_interface_speed => $network_interface_speed, network_interface_uuid => $network_interface_uuid, }}); @@ -11504,6 +11573,7 @@ WHERE "; network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." AND "; } + ### TODO: We may need to switch this to 'device' if the name or MAC address isn't found $query .= " network_interface_name = ".$anvil->Database->quote($network_interface_name)." AND @@ -11522,6 +11592,68 @@ AND $network_interface_uuid = $results->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); } + elsif ($network_interface_device) + { + # Try again using the device name. + my $query = " +SELECT + network_interface_uuid +FROM + network_interfaces +WHERE "; + if ($network_interface_name !~ /^vnet/) + { + $query .= " + network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." +AND "; + } + ### TODO: We may need to switch this to 'device' if the name or MAC address isn't found + $query .= " + network_interface_device = ".$anvil->Database->quote($network_interface_device)." +AND + network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_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) + { + $network_interface_uuid = $results->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); + } + } + elsif ($network_interface_name !~ /^vnet/) + { + # Try finding it by MAC + my $query = " +SELECT + network_interface_uuid +FROM + network_interfaces +WHERE + network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." +AND + network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_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) + { + $network_interface_uuid = $results->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); + } + } if (($link_only) && (not $network_interface_uuid)) { @@ -11585,8 +11717,10 @@ WHERE my $query = " SELECT 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, @@ -11617,20 +11751,24 @@ WHERE foreach my $row (@{$results}) { my $old_network_interface_host_uuid = $row->[0]; + my $old_network_interface_nm_uuid = defined $row->[1] ? $row->[1] : 'NULL'; my $old_network_interface_mac_address = $row->[1]; my $old_network_interface_name = $row->[2]; - my $old_network_interface_speed = $row->[3]; - my $old_network_interface_mtu = $row->[4]; - my $old_network_interface_link_state = $row->[5]; - my $old_network_interface_operational = $row->[6]; - my $old_network_interface_duplex = $row->[7]; - my $old_network_interface_medium = $row->[8]; - my $old_network_interface_bond_uuid = defined $row->[9] ? $row->[9] : 'NULL'; - my $old_network_interface_bridge_uuid = defined $row->[10] ? $row->[10] : 'NULL'; + my $old_network_interface_device = $row->[3]; + my $old_network_interface_speed = $row->[4]; + my $old_network_interface_mtu = $row->[5]; + my $old_network_interface_link_state = $row->[6]; + my $old_network_interface_operational = $row->[7]; + my $old_network_interface_duplex = $row->[8]; + my $old_network_interface_medium = $row->[9]; + my $old_network_interface_bond_uuid = defined $row->[10] ? $row->[10] : 'NULL'; + my $old_network_interface_bridge_uuid = defined $row->[11] ? $row->[11] : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_network_interface_host_uuid => $old_network_interface_host_uuid, + old_network_interface_nm_uuid => $old_network_interface_nm_uuid, old_network_interface_mac_address => $old_network_interface_mac_address, old_network_interface_name => $old_network_interface_name, + old_network_interface_device => $old_network_interface_device, old_network_interface_speed => $old_network_interface_speed, old_network_interface_mtu => $old_network_interface_mtu, old_network_interface_link_state => $old_network_interface_link_state, @@ -11644,7 +11782,9 @@ WHERE # If 'link_only' is set, we're only checking/updating a subset of values. if ($link_only) { - if (($network_interface_name ne $old_network_interface_name) or + if (($network_interface_nm_uuid ne $old_network_interface_nm_uuid) or + ($network_interface_name ne $old_network_interface_name) or + ($network_interface_device ne $old_network_interface_device) or ($network_interface_link_state ne $old_network_interface_link_state) or ($network_interface_operational ne $old_network_interface_operational) or ($network_interface_mac_address ne $old_network_interface_mac_address) or @@ -11656,7 +11796,9 @@ UPDATE network_interfaces SET network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid).", + network_interface_nm_uuid = ".$anvil->Database->quote($network_interface_nm_uuid).", network_interface_name = ".$anvil->Database->quote($network_interface_name).", + network_interface_device = ".$anvil->Database->quote($network_interface_device).", network_interface_link_state = ".$anvil->Database->quote($network_interface_link_state).", network_interface_operational = ".$anvil->Database->quote($network_interface_operational).", network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address).", @@ -11676,7 +11818,9 @@ WHERE # not passed in, we want to not compare it. if (($network_interface_bond_uuid ne $old_network_interface_bond_uuid) or ($network_interface_bridge_uuid ne $old_network_interface_bridge_uuid) or + ($network_interface_nm_uuid ne $old_network_interface_nm_uuid) or ($network_interface_name ne $old_network_interface_name) or + ($network_interface_device ne $old_network_interface_device) or ($network_interface_duplex ne $old_network_interface_duplex) or ($network_interface_link_state ne $old_network_interface_link_state) or ($network_interface_operational ne $old_network_interface_operational) or @@ -11692,9 +11836,11 @@ UPDATE network_interfaces SET network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid).", + network_interface_nm_uuid = ".$anvil->Database->quote($network_interface_nm_uuid).", network_interface_bond_uuid = ".$anvil->Database->quote($network_interface_bond_uuid).", network_interface_bridge_uuid = ".$anvil->Database->quote($network_interface_bridge_uuid).", network_interface_name = ".$anvil->Database->quote($network_interface_name).", + network_interface_device = ".$anvil->Database->quote($network_interface_device).", network_interface_duplex = ".$anvil->Database->quote($network_interface_duplex).", network_interface_link_state = ".$anvil->Database->quote($network_interface_link_state).", network_interface_operational = ".$anvil->Database->quote($network_interface_operational).", @@ -11723,9 +11869,11 @@ INSERT INTO network_interfaces ( network_interface_uuid, + network_interface_nm_uuid, network_interface_bond_uuid, network_interface_bridge_uuid, network_interface_name, + network_interface_device, network_interface_duplex, network_interface_host_uuid, network_interface_link_state, @@ -11737,9 +11885,11 @@ INSERT INTO modified_date ) VALUES ( ".$anvil->Database->quote($network_interface_uuid).", + ".$anvil->Database->quote($network_interface_nm_uuid).", ".$anvil->Database->quote($network_interface_bond_uuid).", ".$anvil->Database->quote($network_interface_bridge_uuid).", ".$anvil->Database->quote($network_interface_name).", + ".$anvil->Database->quote($network_interface_device).", ".$anvil->Database->quote($network_interface_duplex).", ".$anvil->Database->quote($network_interface_host_uuid).", ".$anvil->Database->quote($network_interface_link_state).", @@ -17825,7 +17975,7 @@ sub resync_databases $query .= " ORDER BY utc_modified_date DESC;"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { - uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}), + uuid => $anvil->Database->get_host_from_uuid({debug => $debug, short => 1, host_uuid => $uuid}), query => $query, }}); @@ -18071,7 +18221,7 @@ sub resync_databases # Already in, redirect to the history schema. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0029", variables => { table => $table, - host_name => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}), + host_name => $anvil->Database->get_host_from_uuid({debug => $debug, short => 1, host_uuid => $uuid}), host_uuid => $uuid, column => $uuid_column, uuid => $row_uuid, @@ -18494,7 +18644,6 @@ sub track_files }}); next if $file_type eq "DELETED"; - ### TODO - Left off here, not adding DR links. my $anvil_needs_file = 0; foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid) { @@ -18679,6 +18828,10 @@ This records data to one or all of the databases. If a UUID is passed, the query Parameters; +=head3 initializing (optional, default 0) + +When set to C<< 1 >>, this tells the method that the database is being initialized, so some checks and lookups are disabled. + =head3 line (optional) If you want errors to be traced back to the query called, this can be set (usually to C<< __LINE__ >>) along with the C<< source >> parameter. In such a case, if there is an error in this method, the caller's file and line are displayed in the logs. @@ -18718,20 +18871,23 @@ sub write my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->write()" }}); - my $line = $parameter->{line} ? $parameter->{line} : __LINE__; - my $query = $parameter->{query} ? $parameter->{query} : ""; - my $reenter = $parameter->{reenter} ? $parameter->{reenter} : ""; - my $secure = $parameter->{secure} ? $parameter->{secure} : 0; - my $source = $parameter->{source} ? $parameter->{source} : $THIS_FILE; - my $transaction = $parameter->{transaction} ? $parameter->{transaction} : 0; - my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; + my $initializing = $parameter->{initializing} ? $parameter->{initializing} : 0; + my $line = $parameter->{line} ? $parameter->{line} : __LINE__; + my $query = $parameter->{query} ? $parameter->{query} : ""; + my $reenter = $parameter->{reenter} ? $parameter->{reenter} : ""; + my $secure = $parameter->{secure} ? $parameter->{secure} : 0; + my $source = $parameter->{source} ? $parameter->{source} : $THIS_FILE; + my $transaction = $parameter->{transaction} ? $parameter->{transaction} : 0; + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - uuid => $uuid, - line => $line, - query => (not $secure) ? $query : $anvil->Log->is_secure($query), - secure => $secure, - source => $source, - reenter => $reenter, + initializing => $initializing, + line => $line, + query => (not $secure) ? $query : $anvil->Log->is_secure($query), + reenter => $reenter, + secure => $secure, + source => $source, + transaction => $transaction, + uuid => $uuid, }}); if ($uuid) @@ -18765,7 +18921,7 @@ sub write } # If I am still alive check if any locks need to be renewed. - $anvil->Database->check_lock_age({debug => $debug}); + $anvil->Database->check_lock_age({debug => $debug}) if not $initializing; # This array will hold either just the passed DB ID or all of them, if no ID was specified. my @db_uuids; @@ -18822,6 +18978,10 @@ sub write { push @{$query_set}, $this_query; $i++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + this_query => $this_query, + i => $i, + }}); if ($i > $next) { @@ -18852,6 +19012,7 @@ sub write foreach my $this_query (@{$query}) { push @{$query_set}, $this_query; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_query => $this_query }}); } } } @@ -18867,8 +19028,11 @@ sub write foreach my $uuid (@db_uuids) { # Test access to the DB before we do the actual query - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); - $anvil->Database->_test_access({debug => $debug, uuid => $uuid}); + if (not $initializing) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + $anvil->Database->_test_access({debug => $debug, uuid => $uuid}); + } # Do the actual query(ies) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -18886,7 +19050,7 @@ sub write if (($anvil->data->{sys}{database}{log_transactions}) or ($debug <= $anvil->Log->level)) { $anvil->Log->entry({source => $source, line => $line, secure => $secure, level => 0, key => "log_0083", variables => { - uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}), + uuid => $initializing ? $uuid : $anvil->Database->get_host_from_uuid({debug => 1, short => 1, host_uuid => $uuid}), query => $query, }}); } @@ -18905,6 +19069,7 @@ sub write 's1:test' => $test, 's2:$@' => $@, }}); + if (not $test) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0090", variables => { diff --git a/Anvil/Tools/Email.pm b/Anvil/Tools/Email.pm index e0d9add2..55b49c82 100644 --- a/Anvil/Tools/Email.pm +++ b/Anvil/Tools/Email.pm @@ -487,9 +487,9 @@ sub send_alerts if ($alert_title) { my $title = "[ ".$alert_set_by." ] ".$anvil->Words->parse_banged_string({ + debug => $debug, language => $recipient_language, key_string => $alert_title, - }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { title => $title }}); diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 29e8204a..93d5773b 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -1513,10 +1513,29 @@ sub host_name { # Failed to read the file, too. What the hell? Exit out. print "Failed to query the hostname using 'hostnamectl --static' and failed to read the content of: [".$anvil->data->{path}{configs}{hostname}."]. Something is very wrong, exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } else { + # Did we get a real answer? If it's "unet", the string will be emtpy. + if (not $host_name) + { + # Try seeing if there is a transient hostname. + ($host_name, my $return_code) = $anvil->System->call({debug => 9999, shell_call => $anvil->data->{path}{exe}{hostnamectl}." --transient"}); + if (not $host_name) + { + # OK, can we get it from the 'hostname' command? + ($host_name, my $return_code) = $anvil->System->call({debug => 9999, shell_call => $anvil->data->{path}{exe}{hostname}}); + if (not $host_name) + { + # Failed to find the hostname at all. + print "Failed to query the hostname using 'hostnamectl --static', 'hostnamectl --transient' or 'hostname'. Something is very wrong, exiting.\n"; + $anvil->nice_exit({exit_code => 1}); + } + } + } + # Cache the answer $anvil->data->{sys}{host_name} = $host_name; } @@ -2146,6 +2165,11 @@ sub os_type $os_type = "centos-stream".$1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }}); } + elsif ($release =~ /AlmaLinux .*? (\d+)/) + { + $os_type = "alma".$1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }}); + } elsif ($release =~ /CentOS .*? (\d+)\./) { # CentOS, with the major version number appended diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm index 460ca803..27146dea 100644 --- a/Anvil/Tools/Job.pm +++ b/Anvil/Tools/Job.pm @@ -12,6 +12,7 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Job.pm"; ### Methods; +# bump_progress # clear # get_job_details # get_job_uuid @@ -80,6 +81,84 @@ sub parent # Public methods # ############################################################################################################# +=head2 bump_progress + +This method is meant to make it easier to bump the progress of a jump by some number of steps when a job doesn't run in a linear fashion. + +It does this by storing the progress in the C<< sys::job_progress >> hash and incrementing it by the C<< steps >> parameter value (setting it to C<< 0 >> if it doesn't exist or exists with a non-digit value). If the progress goes over C<< 99 >>, it will return C<< 99 >>. + +If you want to set the progress to C<< 0 >> or C<< 100 >>, use the C<< set >> parameter. + +Parameters; + +=head3 set (optional) + +If you want to set the progress to a specific value, use this parameter. + +B<< NOTE >>: If the set value is less than the current value, the current progress + 1 will be returns. This is meant to prevent progress bars from backing up. + +=head3 steps (default '1') + +This takes an integer and it will increase the job progress by that value. If this is not specified, or if it is set to a non-integer value, C<< 1 >> will be used. + +=cut +sub bump_progress +{ + 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 => "Job->bump_progress()" }}); + + my $set = defined $parameter->{set} ? $parameter->{set} : ""; + my $steps = defined $parameter->{steps} ? $parameter->{steps} : 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + set => $set, + steps => $steps, + }}); + + if ((not exists $anvil->data->{sys}{job_progress}) or ($anvil->data->{sys}{job_progress} !~ /^\d+$/)) + { + $anvil->data->{sys}{job_progress} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + + if ($set =~ /^\d+$/) + { + if ($set > 100) + { + $anvil->data->{sys}{job_progress} = 100; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + elsif ($set > $anvil->data->{sys}{job_progress}) + { + $anvil->data->{sys}{job_progress}++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + } + + $anvil->data->{sys}{job_progress} += $steps; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + if ($anvil->data->{sys}{job_progress} > 99) + { + $anvil->data->{sys}{job_progress} = 99; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + + return($anvil->data->{sys}{job_progress}); +} + + =head2 clear This clears the C<< job_picked_up_by >> value for the given job. @@ -501,8 +580,8 @@ sub html_list } # Convert the double-banged strings into a proper message. - my $say_title = $job_title ? $anvil->Words->parse_banged_string({key_string => $job_title}) : ""; - my $say_description = $job_description ? $anvil->Words->parse_banged_string({key_string => $job_description}) : ""; + my $say_title = $job_title ? $anvil->Words->parse_banged_string({debug => $debug, key_string => $job_title}) : ""; + my $say_description = $job_description ? $anvil->Words->parse_banged_string({debug => $debug, key_string => $job_description}) : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_title => $job_title, say_description => $say_description, @@ -537,10 +616,18 @@ B<< Note >>: Some special C<< job_status >> processing is done to support some s Parameters; +=head3 file (optional) + +When logging as well, this is the file causing the update. Use with C<< line >>. Ignored if C<< log_level >> is not set, or such that it wouldn't be logged anyway. + =head3 job_uuid (optional, default 'jobs::job_uuid') This is the UUID of the job to update. If it isn't set, but C<< jobs::job_uuid >> is set, it will be used. If that is also not set, +=head3 line (optional_ + +When logging as well, this is the line the update came from. Use with C<< file >>. Ignored if C<< log_level >> is not set, or such that it wouldn't be logged anyway. + =head3 log_level (optional) If set to a numeric level, the job's message will also be logged. This is designed to simplify code as most job progress messages will also want to be logged. @@ -584,7 +671,9 @@ sub update_progress my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Job->update_progress()" }}); + my $file = defined $parameter->{file} ? $parameter->{file} : $THIS_FILE; my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : ""; + my $line = defined $parameter->{line} ? $parameter->{line} : __LINE__; my $log_level = defined $parameter->{log_level} ? $parameter->{log_level} : ""; my $message = defined $parameter->{message} ? $parameter->{message} : ""; my $picked_up_by = defined $parameter->{picked_up_by} ? $parameter->{picked_up_by} : ""; @@ -594,11 +683,13 @@ sub update_progress my $secure = defined $parameter->{secure} ? $parameter->{secure} : ""; my $variables = defined $parameter->{variables} ? $parameter->{variables} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + file => $file, job_uuid => $job_uuid, + line => $line, + log_level => $log_level, picked_up_by => $picked_up_by, 'print' => $print, progress => $progress, - log_level => $log_level, message => $message, variables => $variables, secure => $secure, @@ -608,7 +699,7 @@ sub update_progress if (($message ne "clear") && ($log_level =~ /^\d+$/)) { # Log this message. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, 'print' => $print, secure => $secure, priority => $priority, key => $message, variables => $variables}); + $anvil->Log->entry({source => $file, line => $line, level => $log_level, 'print' => $print, secure => $secure, priority => $priority, key => $message, variables => $variables}); } if ($picked_up_by eq "") @@ -654,6 +745,12 @@ sub update_progress $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::last_update" => $anvil->data->{sys}{last_update} }}); } + # If we don't have a database connection, we're done. + if (not $anvil->data->{sys}{database}{connections}) + { + return(0); + } + # Add variables to the message, if required if (ref($variables) eq "HASH") { diff --git a/Anvil/Tools/Log.pm b/Anvil/Tools/Log.pm index db627adb..7bcb0bf2 100644 --- a/Anvil/Tools/Log.pm +++ b/Anvil/Tools/Log.pm @@ -491,7 +491,7 @@ sub entry binmode($anvil->data->{HANDLE}{'log'}{main}, ':encoding(utf-8)'); print $THIS_FILE." ".__LINE__."; HANDLE::log::main: [".$anvil->data->{HANDLE}{'log'}{main}."]\n" if $test; - # Make sure it can be written to by apache. + # Make sure it can be written to by striker-ui-api. $anvil->Storage->change_mode({test => $test, debug => $debug, path => $log_file, mode => "0666"}); } @@ -531,7 +531,7 @@ sub entry $anvil->data->{HANDLE}{'log'}{alert} = $file_handle; print $THIS_FILE." ".__LINE__."; HANDLE::log::alert: [".$anvil->data->{HANDLE}{'log'}{alert}."]\n" if $test; - # Make sure it can be written to by apache. + # Make sure it can be written to by striker-ui-api. $anvil->Storage->change_mode({test => $test, debug => $debug, path => $log_file, mode => "0666"}); } diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 0434afcb..00906da5 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -15,8 +15,8 @@ my $THIS_FILE = "Network.pm"; ### Methods; # bridge_info # check_firewall -# check_network # check_internet +# collect_data # download # find_access # find_matches @@ -31,8 +31,10 @@ my $THIS_FILE = "Network.pm"; # load_interfces # load_ips # manage_firewall +# modify_connection # ping # read_nmcli +# reset_connection # _check_firewalld_conf # _get_existing_zone_interfaces # _get_server_ports @@ -382,40 +384,40 @@ sub check_firewall } -=head2 check_network +=head2 check_internet -B<< NOTE >>: This method is not yet implemented. +This method tries to connect to the internet. If successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. -This method checks to see if bridges and the links in bonds are up. It can simply report the bridge, bond and link states, or it can try to bring up interfaces that are down. +Paramters; -This method returns C<< 0 >> if nothing was done. It returns C<< 1 >> if any repairs were done. +=head3 domains (optional, default 'defaults::network::test::domains') -Data is stored in the hash; +If passed an array reference, the domains in the array will be checked in the order they are found in the array. As soon as any respond to a ping, the check exits and C<< 1 >> is returned. -* bridge_health::::up = [0,1] -* bond_health::::up = [0,1] -* bond_health::::active_links = -* bond_health::::up_links = -* bond_health::::configured_links = -* bond_health::::interface::::in_bond = [0,1] -* bond_health::::interface::::up = [0,1] -* bond_health::::interface::::carrier = [0,1] -* bond_health::::interface::::name = +If not passed, C<< defaults::network::test::domains >> are used. -Parameters; +=head3 password (optional) + +If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail). + +=head3 port (optional, default 22) + +If C<< target >> is set, this is the TCP port number used to connect to the remote machine. + +=head3 remote_user (optional) -=head3 heal (optional, default 'down_only') +If C<< target >> is set, this is the user account that will be used when connecting to the remote system. -When set to C<< down_only >>, a bond where both links are down will attempt to up the links. However, bonds with at least one link up will be left alone. This is the default behaviour as it's not uncommon for admins to remotely down a single interface that is failing to stop alerts until a physical repair can be made. +=head3 target (optional) -When set to C<< all >>, any interfaces that are found to be down will attempt to brought up. +If set, the file will be read from the target machine. This must be either an IP address or a resolvable host name. -Wen set to C<< none >>, no attempts will be made to bring up any interfaces. The states will simply be recorded. +=head3 tries (optional, default 3) -B<< Note >>: Interfaces that show no carrier will not be started in any case. +This is how many times we'll try to ping the target. Pings are done one ping at a time, so that if the first ping succeeds, the test can exit quickly and return success. =cut -sub check_network +sub check_internet { my $self = shift; my $parameter = shift; @@ -423,184 +425,493 @@ sub check_network my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->check_internet()" }}); - # This is causing more problems than it solves. Disabled for the time being. - return(0); - - my $heal = defined $parameter->{heal} ? $parameter->{heal} : "down_only"; + my $access = 0; + my $domains = defined $parameter->{domains} ? $parameter->{domains} : $anvil->data->{defaults}{network}{test}{domains}; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : 22; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $tries = defined $parameter->{tries} ? $parameter->{tries} : 3; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - heal => $heal, + domains => $domains, + password => $anvil->Log->is_secure($password), + port => $port, + remote_user => $remote_user, + target => $target, + tries => $tries, }}); - # Find out the bonds that are up. - my $host = $anvil->Get->short_host_name(); - $anvil->Network->bridge_info({debug => $debug}); + if (ref($domains) eq "ARRAY") + { + my $domain_count = @{$domains}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { domain_count => $domain_count }}); + if (not $domain_count) + { + # Array is empty + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0440", variables => { name => "domain" }}); + return($access); + } + } + else + { + # Domains isn't an array. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0218", variables => { name => "domain", value => $domains }}); + return($access); + } - if (exists $anvil->data->{bond_health}) + if (($tries =~ /\D/) or ($tries < 1)) { - delete $anvil->data->{bond_health}; + # Invalid + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0441", variables => { name => "tries", value => $tries }}); + return($access); } - # Read in the network configuration files to track which interfaces are bound to which bonds. - my $repaired = 0; - my $interface = ""; - my $directory = $anvil->data->{path}{directories}{ifcfg}; - local(*DIRECTORY); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0018", variables => { directory => $directory }}); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) + foreach my $domain (@{$domains}) { - if ($file =~ /^ifcfg-(.*)$/) - { - $interface = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface => $interface }}); - - # We'll check these, so this just makes sure we don't get an undefined variable error. - $anvil->data->{raw_network}{interface}{$interface}{variable}{TYPE} = ""; - $anvil->data->{raw_network}{interface}{$interface}{variable}{DEVICE} = ""; - $anvil->data->{raw_network}{interface}{$interface}{variable}{MASTER} = ""; - } - else + # Is the domain valid? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { domain => $domain }}); + + if ((not $anvil->Validate->domain_name({debug => $debug, name => $domain})) and + (not $anvil->Validate->ipv4({debug => $debug, ip => $domain}))) { + # Not valid, skip + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0442", variables => { name => $domain }}); next; } - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }}); - - my $device = ""; - my $is_link = ""; - my $in_bond = ""; - my $is_bond = ""; - # Read in the file. - my $file_body = $anvil->Storage->read_file({debug => ($debug+1), file => $full_path}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); - - foreach my $line (split/\n/, $file_body) + my ($pinged, $average_time) = $anvil->Network->ping({ + debug => $debug, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, + ping => $domain, + count => 3, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + pinged => $pinged, + average_time => $average_time, + }}); + if ($pinged) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - $line =~ s/#.*$//; - if ($line =~ /^(.*?)=(.*)$/) - { - my $variable = $1; - my $value = $2; - $value =~ s/^"(.*)"$/$1/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - variable => $variable, - value => $value, - }}); - - $anvil->data->{raw_network}{interface}{$interface}{variable}{$variable} = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "raw_network::interface::${interface}::variable::${variable}" => $anvil->data->{raw_network}{interface}{$interface}{variable}{$variable}, - }}); - } + $access = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { access => $access }}); } - $interface = ""; + last if $pinged; } - closedir(DIRECTORY); - # Process - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{raw_network}{interface}}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { access => $access }}); + return($access); +} + + +### NOTE: This is the new way of collecting data from nmcli, it is the method to use going forward. +=head2 collect_data + +This method uses Network Manager, sysfs and procfs to collect data about the current state of the network. + +Stored data: + +* nmcli::uuid::::device = 'connection.interface-name', or 'GENERAL.DEVICES'. See note below +* nmcli::uuid::::type = interface, bond, bridge, etc +* nmcli::uuid::::active = 1,0 +* nmcli::uuid::::state = activated,activating,etc +* nmcli::uuid:::: = all 'variable: value' pairs returned by 'nmcli connection show ' +* nmcli::uuid::::mac_address = MAC address (in lower case) +* nmcli::uuid::::connected = 0 is down, unix timestamp (seconds since epoch) of when it connected if up. +* nmcli::uuid::::mtu = This is the MTU (maximum transimssion unit in bytes) of the interface. + +To make it easier to map a device by name or MAC address to a UUID, this lookup hash is provided. Note that 'device' is 'connection.interface-name' when available, falling back to 'GENERAL.DEVICES' otherwise. + +B<< NOTE >>: An inactive interface will not report the 'connection.interface-name', and the bios device name will be returned (which is what is stored in 'GENERAL.DEVICES'. If you're trying to find a device, and the expected name doesn't exist, look up the device by MAC address. If that's not found, then the old GENERAL.DEVICES name can help you identify a replaced interface. + +* nmcli::device::::uuid = interface name (or device name) +* nmcli::mac_address::::uuid = MAC address (lower case) + +Given that a single interface can have multiple IP addresses and routes, the IPs on a given interface are stored using a sequence number <1, 2, 3 ... n>. To make it easier to find what device has an IP, the IPs are stored with a quick access hash. + +* nmcli::ipv4::::on_uuid = interface UUID +* nmcli::ipv4::::sequence = sequence number +* nmcli::uuid::::ipv{4,6}::ip::::ip_address = IP address +* nmcli::uuid::::ipv{4,6}::ip::::subnet_mask = subnet mask (CIDR notation) +* nmcli::uuid::::ipv{4,6}::dns = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::gateway = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::route:: = Route info (ie: 'dst = 0.0.0.0/0, nh = 192.168.255.254, mt = 428', or 'dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 428'.) + +Bond data is stored in these hashes; + +* nmcli::bond::::uuid = The UUID on the bond +* nmcli::bond::::carrier = 1,0 - indicates if the bond has a connection or not. +* nmcli::bond::::operstate = 1,0 - indicates if the bond is operational or not. +* nmcli::bond::::up = 1,0 - indicates if the bond up up or not. +* nmcli::bond::::interface::::up = 1,0 - indicates if the child interface is up or not. + +Bridge data is simple, but also made easy to find. The only real data is the hash references for the interfaces connected to the bridge. + +* nmcli::bridge::::uuid = The UUID of the bridge +* nmcli::bridge::::interface::::status = This is the link data for the connected interface (ie: 'BROADCAST,MULTICAST,MASTER,UP,LOWER_UP'). + +To make it easier to find interfaces, the following look up hash is available. + +* nmcli::interface::::uuid = The UUID of the interface +* nmcli::mac_address::::uuid = MAC address + +Parameters; + +=head3 start (optional, default '0') + +If this is set to C<< 1 >>, any connetions found to be down and not referencing any devices will be assigned the unroutable IP C<< 169.0.0.x >>, where C<< x >> is a sequential number. This should bring up unconfigured devices. + +=cut +sub collect_data +{ + 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 => "Network->check_internet()" }}); + + my $start = defined $parameter->{start} ? $parameter->{start} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + start => $start, + }}); + + if (exists $anvil->data->{nmcli}) { - my $type = $anvil->data->{raw_network}{interface}{$interface}{variable}{TYPE}; - my $device = $anvil->data->{raw_network}{interface}{$interface}{variable}{DEVICE}; - my $name = defined $anvil->data->{raw_network}{interface}{$interface}{variable}{NAME} ? $anvil->data->{raw_network}{interface}{$interface}{variable}{NAME} : $device; - $name =~ s/ /_/g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - interface => $interface, - type => $type, - device => $device, - name => $name, - }}); - - # Is this a bridge? - if (lc($type) eq "bridge") + delete $anvil->data->{nmcli}; + } + + # Use nmcli to collect the data. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state,name connection show"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^(.*?):(.*?):(.*?):(.*?):(.*?)$/) { - # Yup! - $anvil->data->{bridge_health}{$device}{up} = 0; - $anvil->data->{bridge_health}{$device}{name} = $name; - if ((exists $anvil->data->{bridge}{$host}{$device}) && ($anvil->data->{bridge}{$host}{$device}{found})) + my $uuid = $1; + my $type = $2; + my $active = $3; + my $state = $4; + my $nm_name = $4; # biosdevname + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + uuid => $uuid, + type => $type, + active => $active, + 'state' => $state, + nm_name => $nm_name, + }}); + next if $type eq "loopback"; + + if ($type eq "802-3-ethernet") { - $anvil->data->{bridge_health}{$device}{up} = 1; + $type = "interface"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bridge_health::${device}::up" => $anvil->data->{bridge_health}{$device}{up}, - "bridge_health::${device}::name" => $anvil->data->{bridge_health}{$device}{name}, + + $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; + $anvil->data->{nmcli}{uuid}{$uuid}{active} = lc($active) eq "yes" ? 1 : 0; + $anvil->data->{nmcli}{uuid}{$uuid}{'state'} = lc($state); + $anvil->data->{nmcli}{uuid}{$uuid}{nm_name} = $nm_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{active}, + "nmcli::uuid::${uuid}::state" => $anvil->data->{nmcli}{uuid}{$uuid}{'state'}, + "nmcli::uuid::${uuid}::nm_name" => $anvil->data->{nmcli}{uuid}{$uuid}{nm_name}, }}); } + } + + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); - # Is this a bond? - if (lc($type) eq "bond") + # Collect all the rest of the data now. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) { - # Yes! - $anvil->data->{bond_health}{$device}{configured_links} = 0; - $anvil->data->{bond_health}{$device}{active_links} = 0; - $anvil->data->{bond_health}{$device}{up_links} = 0; - $anvil->data->{bond_health}{$device}{name} = $name; - - # Find the links configured to be under this bond. - foreach my $this_interface (sort {$a cmp $b} keys %{$anvil->data->{raw_network}{interface}}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^(.*?):\s+(.*)$/) { - # Is this a bond? - my $this_type = $anvil->data->{raw_network}{interface}{$this_interface}{variable}{TYPE}; - my $this_device = $anvil->data->{raw_network}{interface}{$this_interface}{variable}{DEVICE}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - this_interface => $this_interface, - this_type => $this_type, - this_device => $this_device, + my $variable = $1; + my $value = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable' => $variable, + 's2:value' => $value, }}); - next if lc($this_type) ne "ethernet"; - my $master = $anvil->data->{raw_network}{interface}{$this_interface}{variable}{MASTER}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { master => $master }}); - if (($master) && ($master eq $device)) + if ($value eq "--") { - # This interface belongs to this bond. - $anvil->data->{bond_health}{$device}{interface}{$this_device}{in_bond} = 0; - $anvil->data->{bond_health}{$device}{interface}{$this_device}{up} = "unknown"; - $anvil->data->{bond_health}{$device}{interface}{$this_device}{carrier} = "unknown"; - $anvil->data->{bond_health}{$device}{interface}{$this_device}{name} = $this_interface; - $anvil->data->{bond_health}{$device}{configured_links}++; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${this_device}::name" => $anvil->data->{bond_health}{$device}{interface}{$this_device}{name}, - "bond_health::${device}::configured_links" => $anvil->data->{bond_health}{$device}{configured_links}, + $value = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + + $anvil->data->{nmcli}{uuid}{$uuid}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${variable}" => $anvil->data->{nmcli}{uuid}{$uuid}{$variable}, + }}); + + if ($variable =~ /IP(\d).ADDRESS\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, }}); - # Read the interface's carrier - my $carrier_file = "/sys/class/net/".$this_device."/carrier"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier_file => $carrier_file }}); - - if (-e $carrier_file) + if (($ip_type == 4) && ($value =~ /^(.*?)\/(.*)$/)) { - my $carrier = $anvil->Storage->read_file({debug => ($debug+1), file => $carrier_file}); - chomp $carrier; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); + my $ip_address = $1; + my $subnet_mask = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }}); - $anvil->data->{bond_health}{$device}{interface}{$this_device}{carrier} = $carrier; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${this_device}::carrier" => $anvil->data->{bond_health}{$device}{interface}{$this_device}{carrier}, + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $1; + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = $2; + $anvil->data->{nmcli}{ipv4}{$ip_address}{on_uuid} = $uuid; + $anvil->data->{nmcli}{ipv4}{$ip_address}{sequence} = $sequence; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + "nmcli::ipv4::${ip_address}::on_uuid" => $anvil->data->{nmcli}{ipv4}{$ip_address}{on_uuid}, + "nmcli::ipv4::${ip_address}::sequence" => $anvil->data->{nmcli}{ipv4}{$ip_address}{sequence}, + }}); + } + else + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $value; + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = ""; + $anvil->data->{nmcli}{ipv4}{$value}{on_uuid} = $value; + $anvil->data->{nmcli}{ipv4}{$value}{sequence} = $sequence; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + "nmcli::ipv4::${value}::on_uuid" => $anvil->data->{nmcli}{ipv4}{$value}{on_uuid}, + "nmcli::ipv4::${value}::sequence" => $anvil->data->{nmcli}{ipv4}{$value}{sequence}, }}); + } - my $operstate_file = "/sys/class/net/".$this_device."/operstate"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate_file => $operstate_file }}); + # Make sure the DNS key exists. + if (not exists $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}) + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}, + }}); + } + if (not exists $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}) + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } + if ($variable =~ /IP(\d).ROUTE\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); - if (-e $operstate_file) + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{route}{$sequence} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::route::${sequence}" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{route}{$sequence}, + }}); + } + if ($variable =~ /IP(\d).DNS\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + if ((exists $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}) and ($anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} ne "")) { - my $operstate = $anvil->Storage->read_file({debug => ($debug+1), file => $operstate_file}); - chomp $operstate; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); - - $anvil->data->{bond_health}{$device}{interface}{$this_device}{up} = $operstate eq "up" ? 1 : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${this_device}::operstate" => $anvil->data->{bond_health}{$device}{interface}{$this_device}{operstate}, + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} .= ",".$value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}, + }}); + } + else + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}, }}); } } + if ($variable =~ /IP(\d).GATEWAY/) + { + my $ip_type = $1; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + hash_key => $hash_key, + }}); + + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } + } + } + } + + # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a + # bit tricky. + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + ### NOTE: The 'connection_id' is the 'network_interface_name' (biosdevname) and it is always + ### available, 'GENERAL.IP-IFACE' is the 'network_interface_device' and is only + ### available when the interface is up. + my $connection_id = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.id'} // ""; + my $general_ip_iface = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.IP-IFACE'} // ""; + $general_ip_iface = "" if $general_ip_iface eq "--"; + my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; + my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'} // ""; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'match.interface-name'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:uuid' => $uuid, + 's2:connection_id' => $connection_id, + 's3:general_ip_iface' => $general_ip_iface, + 's4:device_type' => $device_type, + 's5:connection_interface_name' => $connection_interface_name, + 's6:match_interface_name' => $match_interface_name, + }}); + + # An unrenamed interface will have a default 'Wired connection X' name, not he biosdevname + # name. So if there's not 'match.interface_name', use the 'connection.interface-name'. + if ((not $match_interface_name) && ($connection_interface_name)) + { + $connection_id = $connection_interface_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_id => $connection_id }}); + } + + # If there isn't a GENERAL.DEVICES or GENERAL.IP-IFACE, the link is down. Use the match.interface-name. + if ((not $general_ip_iface) && ($match_interface_name)) + { + foreach my $interface (split/,/, $match_interface_name) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }}); + next if $connection_id eq $interface; + if ($interface) + { + $general_ip_iface = $interface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { general_ip_iface => $general_ip_iface }}); + } + last if $general_ip_iface; + } + } + + # Make it easier to lookup this device by name. + $anvil->data->{nmcli}{name}{$connection_id}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::name::${connection_id}::uuid" => $anvil->data->{nmcli}{name}{$connection_id}{uuid}, + }}); + + if ((not $general_ip_iface) && (not $connection_interface_name)) + { + # This connection is down, so it's not linked to a device. + next; + } + + my $device = $general_ip_iface ? $general_ip_iface : $connection_interface_name; + $anvil->data->{nmcli}{device}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::device::${device}::uuid" => $anvil->data->{nmcli}{device}{$device}{uuid}, + }}); + + ### Get some data from sysfs. + $anvil->data->{nmcli}{uuid}{$uuid}{name} = $connection_id; + $anvil->data->{nmcli}{uuid}{$uuid}{device} = $device; + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = ""; + $anvil->data->{nmcli}{uuid}{$uuid}{type} = ""; + $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::device" => $anvil->data->{nmcli}{uuid}{$uuid}{device}, + }}); + + # The 'connection.timestamp' seems to be where the 'connected' (as in, have an IP) + # comes from. + $anvil->data->{nmcli}{uuid}{$uuid}{connected} = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} ? $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::connected" => $anvil->data->{nmcli}{uuid}{$uuid}{connected}, + }}); + + if ($device_type eq "bond") + { + # Bonds always have the name we chose as the connection.id as they don't have + # biosdevnames. + $anvil->data->{nmcli}{bond}{$connection_id}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bond::${connection_id}::uuid" => $anvil->data->{nmcli}{bond}{$connection_id}{uuid}, + }}); + + # Read the interface's carrier + my $carrier_file = "/sys/class/net/".$connection_id."/carrier"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier_file => $carrier_file }}); + + if (-e $carrier_file) + { + my $carrier = $anvil->Storage->read_file({debug => $debug, file => $carrier_file}); + chomp $carrier; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); + + $anvil->data->{nmcli}{bond}{$connection_id}{carrier} = $carrier; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${connection_id}::carrier" => $anvil->data->{nmcli}{bond}{$connection_id}{carrier}, + }}); + } + + my $operstate_file = "/sys/class/net/".$connection_id."/operstate"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate_file => $operstate_file }}); + + if (-e $operstate_file) + { + my $operstate = $anvil->Storage->read_file({debug => $debug, file => $operstate_file}); + chomp $operstate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); + + $anvil->data->{nmcli}{bond}{$connection_id}{up} = $operstate eq "up" ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${connection_id}::operstate" => $anvil->data->{nmcli}{bond}{$connection_id}{operstate}, + }}); } # Read in the /proc file. - my $proc_file = "/proc/net/bonding/".$device; + my $proc_file = "/proc/net/bonding/".$connection_id; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proc_file => $proc_file }}); my $in_link = ""; @@ -612,13 +923,8 @@ sub check_network if ($line =~ /Slave Interface: (.*)$/) { - $in_link = $1; - $anvil->data->{bond_health}{$device}{active_links}++; - $anvil->data->{bond_health}{$device}{interface}{$in_link}{in_bond} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::active_links" => $anvil->data->{bond_health}{$device}{active_links}, - "bond_health::${device}::interface::${in_link}::in_bond" => $anvil->data->{bond_health}{$device}{interface}{$in_link}{in_bond}, - }}); + $in_link = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); next; } if (not $line) @@ -635,275 +941,241 @@ sub check_network $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); if ($status eq "up") { - $anvil->data->{bond_health}{$device}{up_links}++; - $anvil->data->{bond_health}{$device}{interface}{$in_link}{up} = 1; + $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::up_links" => $anvil->data->{bond_health}{$device}{up_links}, - "bond_health::${device}::interface::${in_link}::up" => $anvil->data->{bond_health}{$device}{interface}{$in_link}{up}, + "nmcli::bond::${connection_id}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up}, }}); } else { - $anvil->data->{bond_health}{$device}{interface}{$in_link}{up} = 0; + $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up} = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${in_link}::up" => $anvil->data->{bond_health}{$device}{interface}{$in_link}{up}, + "nmcli::bond::${connection_id}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up}, }}); } next; } + if ($line =~ / (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/i) + { + # This is the real MAC address of the link. + my $mac_address = $1; + $anvil->data->{nmcli}{perm_mac_address}{$in_link} = $mac_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::perm_mac_address::${in_link}" => $anvil->data->{nmcli}{perm_mac_address}{$in_link}, + }}); + } } else { if ($line =~ /MII Status: (.*)$/) { - my $status = $1; - $anvil->data->{bond_health}{$device}{up} = $status eq "up" ? 1 : 0; + my $status = $1; + $anvil->data->{nmcli}{bond}{$connection_id}{up} = $status eq "up" ? 1 : 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status, - "bond_health::${device}::up" => $anvil->data->{bond_health}{$device}{up}, + "nmcli::bond::${connection_id}::up" => $anvil->data->{nmcli}{bond}{$connection_id}{up}, }}); next; } } } } - } - - # Before we check the bonds, check the bridges. Bonds won't come up if they're in a bridge that is - # down. - my $bridge_count = keys %{$anvil->data->{bridge_health}}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_count => $bridge_count }}); - if (($bridge_count) && (not $heal eq "none")) - { - foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{bridge_health}}) + elsif ($device_type eq "bridge") { - my $up = $anvil->data->{bridge_health}{$bridge}{up}; - my $name = $anvil->data->{bridge_health}{$bridge}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - bridge => $bridge, - name => $name, - up => $up, + # Bonds always have the name we chose as the connection.id as they don't have + # biosdevnames. + $anvil->data->{nmcli}{bridge}{$connection_id}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bridge::${connection_id}::uuid" => $anvil->data->{nmcli}{bridge}{$connection_id}{uuid}, }}); - if (not $up) + # See what interfaces are connected to the bridge. + my $shell_call = $anvil->data->{path}{exe}{ip}." link show master ".$connection_id; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + 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, + }}); + foreach my $line (split/\n/, $output) { - # Try to recover the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0632", variables => { bridge => $bridge }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - - my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output' => $output, - 'return_code' => $return_code, - }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^\d+: (.*?): <(.*?)>/) + { + my $interface = $1; + my $status = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + status => $status, + }}); + + $anvil->data->{nmcli}{bridge}{$connection_id}{interface}{$interface}{status} = $status; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bridge::${connection_id}::interface::${interface}::status" => $anvil->data->{nmcli}{bridge}{$connection_id}{interface}{$interface}{status}, + }}); + } } } - } - - foreach my $bond (sort {$a cmp $b} keys %{$anvil->data->{bond_health}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:bond_health::${bond}::name" => $anvil->data->{bond_health}{$bond}{name}, - "s2:bond_health::${bond}::up" => $anvil->data->{bond_health}{$bond}{up}, - "s3:bond_health::${bond}::configured_links" => $anvil->data->{bond_health}{$bond}{configured_links}, - "s4:bond_health::${bond}::active_links" => $anvil->data->{bond_health}{$bond}{active_links}, - "s5:bond_health::${bond}::up_links" => $anvil->data->{bond_health}{$bond}{up_links}, - }}); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{bond_health}{$bond}{interface}}) + elsif (($device_type eq "802-3-ethernet") or ($device_type eq "interface")) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:bond_health::${bond}::interface::${interface}::name" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{name}, - "s2:bond_health::${bond}::interface::${interface}::in_bond" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{in_bond}, - "s3:bond_health::${bond}::interface::${interface}::up" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{up}, - "s4:bond_health::${bond}::interface::${interface}::carrier" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{carrier}, + # If we've got the if-name, use it. Otherwise, it's likely down and not renamed by + # us, so use the connection id. + my $device = $connection_id; + if (($general_ip_iface) && ($general_ip_iface ne "--")) + { + $device = $general_ip_iface; + } + $anvil->data->{nmcli}{interface}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::interface::${device}::uuid" => $anvil->data->{nmcli}{interface}{$device}{uuid}, }}); - } - - if ($anvil->data->{bond_health}{$bond}{configured_links} != $anvil->data->{bond_health}{$bond}{up_links}) - { - next if $heal eq "none"; - next if (($anvil->data->{bond_health}{$bond}{up}) && ($heal eq "down_only")); - # Log that we're going to try to heal this bond. - if ($heal eq "down_only") + # MAC address + my $mac_address_file = "/sys/class/net/".$device."/address"; + my $type_file = "/sys/class/net/".$device."/type"; + my $mtu_file = "/sys/class/net/".$device."/mtu"; + if (-e $mac_address_file) { - # Log that we're healing fully down bonds. - $repaired = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0627", variables => { bond => $bond }}); + ### NOTE: This will always be the active link's MAC in a bond, so tis gets + ### overwritten when the bond device is parsed. + my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + + if (($mac_address) && ($mac_address ne "!!error!!")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::mac_address" => $anvil->data->{nmcli}{uuid}{$uuid}{mac_address}, + "nmcli::mac_address::${mac_address}::uuid" => $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, + }}); + } } - else + if (-e $type_file) { - # Log that we're healing all bond links - $repaired = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0628", variables => { bond => $bond }}); + my $type = $anvil->Storage->read_file({file => $type_file}); + $type =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + + if (($type) && ($type ne "!!error!!")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + }}); + } } - - # For good measure, try to up the bond as well. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0630", variables => { bond => $bond }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$anvil->data->{bond_health}{$bond}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - - my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output' => $output, - 'return_code' => $return_code, - }}); - - # If we're here, try to bring up down'ed interfaces. - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{bond_health}{$bond}{interface}}) + if (-e $mtu_file) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s2:bond_health::${bond}::interface::${interface}::in_bond" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{in_bond}, - "s4:bond_health::${bond}::interface::${interface}::carrier" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{carrier}, - }}); - if ((not $anvil->data->{bond_health}{$bond}{interface}{$interface}{in_bond}) && ($anvil->data->{bond_health}{$bond}{interface}{$interface}{carrier})) + my $mtu = $anvil->Storage->read_file({file => $mtu_file}); + $mtu =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); + + if (($mtu) && ($mtu ne "!!error!!")) { - # Link shown, try to start the interface. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0629", variables => { - bond => $bond, - interface => $interface." (".$anvil->data->{bond_health}{$bond}{interface}{$interface}{name}.")", - }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$anvil->data->{bond_health}{$bond}{interface}{$interface}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); - - my ($output, $return_code) = $anvil->System->call({debug => 1, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output' => $output, - 'return_code' => $return_code, + $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = $mtu; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::mtu" => $anvil->data->{nmcli}{uuid}{$uuid}{mtu}, }}); } } } } - return($repaired); -} - - -=head2 check_internet - -This method tries to connect to the internet. If successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. - -Paramters; - -=head3 domains (optional, default 'defaults::network::test::domains') - -If passed an array reference, the domains in the array will be checked in the order they are found in the array. As soon as any respond to a ping, the check exits and C<< 1 >> is returned. - -If not passed, C<< defaults::network::test::domains >> are used. - -=head3 password (optional) - -If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail). - -=head3 port (optional, default 22) - -If C<< target >> is set, this is the TCP port number used to connect to the remote machine. - -=head3 remote_user (optional) - -If C<< target >> is set, this is the user account that will be used when connecting to the remote system. - -=head3 target (optional) - -If set, the file will be read from the target machine. This must be either an IP address or a resolvable host name. - -=head3 tries (optional, default 3) - -This is how many times we'll try to ping the target. Pings are done one ping at a time, so that if the first ping succeeds, the test can exit quickly and return success. - -=cut -sub check_internet -{ - 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 => "Network->check_internet()" }}); - - my $access = 0; - my $domains = defined $parameter->{domains} ? $parameter->{domains} : $anvil->data->{defaults}{network}{test}{domains}; - my $password = defined $parameter->{password} ? $parameter->{password} : ""; - my $port = defined $parameter->{port} ? $parameter->{port} : 22; - my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; - my $target = defined $parameter->{target} ? $parameter->{target} : ""; - my $tries = defined $parameter->{tries} ? $parameter->{tries} : 3; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - domains => $domains, - password => $anvil->Log->is_secure($password), - port => $port, - remote_user => $remote_user, - target => $target, - tries => $tries, - }}); - - if (ref($domains) eq "ARRAY") + # Loop through interfaces and see if the MAC address needs to be updated if it's the backup interface + # in a bond. + foreach my $device (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{interface}}) { - my $domain_count = @{$domains}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { domain_count => $domain_count }}); - if (not $domain_count) + my $uuid = $anvil->data->{nmcli}{interface}{$device}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:device" => $device, + "s2:uuid" => $uuid, + }}); + + if ((exists $anvil->data->{nmcli}{perm_mac_address}{$device}) && ($anvil->data->{nmcli}{perm_mac_address}{$device})) { - # Array is empty - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0440", variables => { name => "domain" }}); - return($access); + # There's a permanent MAC address, overwrite the one we read earlier. + my $perm_mac_address = $anvil->data->{nmcli}{perm_mac_address}{$device}; + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = $perm_mac_address; + $anvil->data->{nmcli}{mac_address}{$perm_mac_address}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:nmcli::uuid::${uuid}::mac_address" => $anvil->data->{nmcli}{uuid}{$uuid}{mac_address}, + "s2:nmcli::mac_address::${perm_mac_address}::uuid" => $anvil->data->{nmcli}{mac_address}{$perm_mac_address}{uuid}, + }}); } } - else - { - # Domains isn't an array. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0218", variables => { name => "domain", value => $domains }}); - return($access); - } - - if (($tries =~ /\D/) or ($tries < 1)) - { - # Invalid - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0441", variables => { name => "tries", value => $tries }}); - return($access); - } - foreach my $domain (@{$domains}) + # Should we start interfaces? + if ($start) { - # Is the domain valid? - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { domain => $domain }}); + # Yup, but are there any to start? We'll set this to '1' if so and that will trigger a + # rescan. + my $rescan = 0; - if ((not $anvil->Validate->domain_name({debug => $debug, name => $domain})) and - (not $anvil->Validate->ipv4({debug => $debug, ip => $domain}))) + # Sorted for log consistency on repeat runs + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) { - # Not valid, skip - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0442", variables => { name => $domain }}); - next; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{active}, + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'}, + }}); + if ((not $anvil->data->{nmcli}{uuid}{$uuid}{active}) && (not $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'})) + { + # Find an IP + my $sequence = 1; + my $found = 0; + my $use_ip = ""; + until ($found) + { + my $test_ip = "169.0.0.".$sequence; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_ip => $test_ip }}); + if (not exists $anvil->data->{nmcli}{ipv4}{$test_ip}) + { + $found = 1; + $use_ip = $test_ip; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + found => $found, + use_ip => $use_ip, + }}); + } + else + { + $sequence++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sequence => $sequence }}); + } + die "Failed to find an unused IP in 169.0.0.0/24\n" if $sequence > 255; + } + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." ipv4.method manual ipv4.addresses ".$use_ip."/8"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, + }}); + + $rescan = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rescan => $rescan }}); + } } - my ($pinged, $average_time) = $anvil->Network->ping({ - debug => $debug, - target => $target, - port => $port, - password => $password, - remote_user => $remote_user, - ping => $domain, - count => 3, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - pinged => $pinged, - average_time => $average_time, - }}); - if ($pinged) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rescan => $rescan }}); + if ($rescan) { - $access = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { access => $access }}); + # Give things a few seconds to settle + sleep 3; + + # Rescan + $anvil->Network->collect_data({debug => $debug}); } - last if $pinged; } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { access => $access }}); - return($access); + return(0); } + + =head2 download This downloads a file from a network target and saves it to a local file. This must be called on a local system so that the download progress can be reported. @@ -1403,7 +1675,7 @@ sub find_matches $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "first" }}); return(""); } - elsif (ref($anvil->data->{network}{$first}) ne "HASH") + if (ref($anvil->data->{network}{$first}) ne "HASH") { $anvil->Network->load_ips({ debug => $debug, @@ -1420,12 +1692,13 @@ sub find_matches return(""); } } + if (not $second) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "second" }}); return(""); } - elsif (ref($anvil->data->{network}{$second}) ne "HASH") + if (ref($anvil->data->{network}{$second}) ne "HASH") { $anvil->Network->load_ips({ debug => $debug, @@ -1469,13 +1742,14 @@ sub find_matches foreach my $second_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$second}{interface}}) { + next if not exists $anvil->data->{network}{$second}{interface}{$second_interface}{ip}; my $second_ip = $anvil->data->{network}{$second}{interface}{$second_interface}{ip}; my $second_subnet_mask = $anvil->data->{network}{$second}{interface}{$second_interface}{subnet_mask}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - second => $second, - second_interface => $second_interface, - second_ip => $second_ip, - second_subnet_mask => $second_subnet_mask, + 's1:second' => $second, + 's2:second_interface' => $second_interface, + 's3:second_ip' => $second_ip, + 's4:second_subnet_mask' => $second_subnet_mask, }}); if (($second_ip) && ($second_subnet_mask)) { @@ -1759,7 +2033,7 @@ sub get_ip_from_mac =head2 get_ips -This method checks the local system for interfaces and stores them in: +This method checks the target system for interfaces and stores them in: * C<< network::::interface::::ip >> - If an IP address is set * C<< network::::interface::::subnet_mask >> - If an IP is set @@ -3685,6 +3959,68 @@ sub manage_firewall return(0); } +=head3 modify_connection + +This takes a network manager connection UUID, and changes the requested variable to be set to the given value. + +The command output and return code are returned. If there is a problem, C<< !!error!! >> is returned. + +Parameters + +=head3 uuid (required) + +This is the network manager UUID of the connection being worked on. + +=head3 variable (required) + +This is the name of the variable to set (as shown in C<< nmcli connection show >>). + +=head3 value (optional, defult "") + +This is the value to set. Note that and empty string (C<< "" >>) deletes the variable. + +=cut +sub modify_connection +{ + 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 => "Network->modify_connection()" }}); + + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; + my $variable = defined $parameter->{variable} ? $parameter->{variable} : ""; + my $value = defined $parameter->{value} ? $parameter->{value} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + uuid => $uuid, + variable => $variable, + value => $value, + }}); + + if (not $uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->modify_connection()", parameter => "uuid" }}); + return("!!error!!"); + } + + if (not $variable) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->modify_connection()", parameter => "variable" }}); + return("!!error!!"); + } + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." ".$variable." ".$value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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($output, $return_code); +} + + =head2 ping @@ -3922,6 +4258,8 @@ sub ping return($pinged, $average_ping_time); } + +### TODO: Phase this out when EL8 / ifcfg-X file support is ended. =head2 read_nmcli This method reads and parses the C<< nmcli >> data. The data is stored as; @@ -4060,7 +4398,7 @@ sub read_nmcli # Read the file, see if we can find it there. if (-e $filename) { - my $file_body = $anvil->Storage->read_file({debug => ($debug+1), file => $filename}); + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $filename}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); foreach my $line (split/\n/, $file_body) @@ -4117,6 +4455,59 @@ sub read_nmcli return(0); } + +=head2 reset_connection + +This method takes a network manager connection UUID and resets the connection by calling it C<< down >> and then C<< up >>. + +If there is a problem, C<< !!error!! >> is returned. Otherwise, the output and return code from the C<< up >> call are returned. + +Parameters; + +=head3 uuid (required) + +This is the UUID of the connection to reset. + +=cut +sub reset_connection +{ + 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 => "Network->reset_connection()" }}); + + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + uuid => $uuid, + }}); + + if (not $uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->reset_connection()", parameter => "uuid" }}); + return("!!error!!"); + } + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, + }}); + + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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($output, $return_code); +} + + ############################################################################################################# # Private functions # ############################################################################################################# @@ -4326,7 +4717,7 @@ sub _get_drbd_ports $full_path =~ s/\/\//\//g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }}); - my $file_body = $anvil->Storage->read_file({debug => ($debug+1), file => $full_path}); + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $full_path}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); foreach my $line (split/\n/, $file_body) diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index 2a158d39..32159eca 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -3232,6 +3232,8 @@ fi;"; =head2 manage_lvm_conf +B<< Note >>: This only works on EL8. If used on another distro, this method will return without actually doing anything. + This method configures C<< lvm.conf >> to add the C<< filter = [ ... ] >> to ensure DRBD devices aren't scanned. If there was a problem, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. @@ -3274,6 +3276,18 @@ sub manage_lvm_conf target => $target, }}); + ### NOTE: Only add the filter on EL8 machines. + my ($os_type, $os_arch) = $anvil->Get->os_type({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + os_type => $os_type, + os_arch => $os_arch, + }}); + if ($os_type !~ /\D8/) + { + # Not EL8, return + return(0); + } + my $body = $anvil->Storage->read_file({ debug => $debug, file => $anvil->data->{path}{configs}{'lvm.conf'}, diff --git a/Anvil/Tools/Striker.pm b/Anvil/Tools/Striker.pm index 6451a810..9195add1 100644 --- a/Anvil/Tools/Striker.pm +++ b/Anvil/Tools/Striker.pm @@ -14,7 +14,7 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Striker.pm"; ### Methods; -# check_httpd_conf +# check_httpd_conf - Deprecated # generate_manifest # get_fence_data # get_local_repo diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index e8e07bb1..1d837517 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -26,6 +26,7 @@ my $THIS_FILE = "System.pm"; # check_if_configured # check_ssh_keys # check_memory +# check_network_type # check_storage # collect_ipmi_data # configure_ipmi @@ -1279,6 +1280,62 @@ sub check_ssh_keys } +=head2 check_network_type + +This method checks to see if this host is using network manager to configure the network, versus the older C<< ifcfg-X >> based config. It does this by looking for any C<< ifcfg-X >> files in C<< /etc/sysconfig/network-scripts >>. + +If any 'ifcfg-X' files are found, C<< ifcfg >> is returned. Otherwise, C<< nm >> is returned. + +The results are cached in C<< sys::network_type >>. + +This method takes no parameters. + +=cut +sub check_network_type +{ + 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 => "System->check_storage()" }}); + + if ((exists $anvil->data->{sys}{network_type}) && ($anvil->data->{sys}{network_type})) + { + # Cached. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::network_type" => $anvil->data->{sys}{network_type} }}); + return($anvil->data->{sys}{network_type}); + } + + # Open the 'ifcfg' directory, if it exists, and see if there are any 'ifcfg-X' files. + my $type = "nm"; + my $directory = $anvil->data->{path}{directories}{ifcfg}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory }}); + + if (-e $directory) + { + local(*DIRECTORY); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0018", variables => { directory => $directory }}); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file => $file }}); + if ($file =~ /^ifcfg-(.*)$/) + { + $type = "ifcfg"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); + last; + } + } + closedir(DIRECTORY); + } + + # Cache the results + $anvil->data->{sys}{network_type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::network_type" => $anvil->data->{sys}{network_type} }}); + return($anvil->data->{sys}{network_type}); +} + + =head2 check_storage Thic gathers LVM data from the local system. @@ -2790,6 +2847,7 @@ sub disable_daemon return($return_code); } + =head2 generate_state_json This method generates the C<< all_status.json >> file. @@ -2879,13 +2937,14 @@ sub generate_state_json my $mac_address = $anvil->data->{network}{$host}{interface}{$interface}{mac_address}; my $iface_hash = {}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:interface" => $interface, - "s2:mac_address" => $mac_address, - "s3:type" => $type, - "s4:mtu" => $mtu, - "s5:configured" => $configured, - "s6:host_uuid" => $host_uuid, - "s7:host_key" => $host_key, + "s1:host" => $host, + "s2:interface" => $interface, + "s3:mac_address" => $mac_address, + "s4:type" => $type, + "s5:mtu" => $mtu, + "s6:configured" => $configured, + "s7:host_uuid" => $host_uuid, + "s8:host_key" => $host_key, }}); $iface_hash->{name} = $interface; $iface_hash->{type} = $type; @@ -3191,8 +3250,8 @@ sub generate_state_json backup => 0, file => $json_file, body => $json, - group => "apache", - user => "apache", + group => "striker-ui-api", + user => "striker-ui-api", mode => "0644", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); diff --git a/anvil.spec.in b/anvil.spec.in index 458221a1..073ec54f 100644 --- a/anvil.spec.in +++ b/anvil.spec.in @@ -247,6 +247,7 @@ setenforce 0 ### TODO: check it if was disabled (if it existed before) and, if so, leave it disabled. systemctl enable --now chronyd.service systemctl enable --now anvil-daemon.service +systemctl enable --now anvil-monitor-network.service systemctl enable --now scancore.service %pre striker @@ -285,11 +286,6 @@ then systemctl enable gdm.service fi -### This is handled by anvil-daemon now -#echo "Preparing the database" -#striker-prep-database -#anvil-update-states - # Touch the system type file. echo "Touching the system type file" if [ -e '/etc/anvil/type.node' ] diff --git a/man/anvil-manage-host.8 b/man/anvil-manage-host.8 index 9a587139..366a5319 100644 --- a/man/anvil-manage-host.8 +++ b/man/anvil-manage-host.8 @@ -35,9 +35,6 @@ Check to see if the host is marked as configured or yet. \fB\-\-check\-database\fR This checks to see if the database is enabled or not. .TP -\fB\-\-check\-network\-mapping\fR -This reports if the host is currently in network mapping (this disables several features and watches the network states much more frequently) -.TP \fB\-\-confirm\fR This confirms actions that would normally prompt the user to confirm before proceeding. .TP @@ -47,12 +44,6 @@ This enables the database on the local Striker dashboard. \fB\-\-database\-inactive\fR This disables the database on the local Striker dashboard. .TP -\fB\-\-disable\-network\-mapping\fR -This disables the network mapping mode. -.TP -\fB\-\-enable\-network\-mapping\fR -This enables the network mapping mode. -.TP \fB\-\-mark\-configured\fR This marks the host as having been configured. .TP diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 7c6292f5..663c59de 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -69,6 +69,9 @@ if ($anvil->data->{switches}{purge}) $anvil->nice_exit({exit_code => 0}); } +# If there's no DB (or cached data isn't recorded to the database yet), this will store those records. +$anvil->data->{cache}{new_file} = "# interface (nm_device),timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_name\n"; +process_interface_cache($anvil); # Read the data. collect_data($anvil); @@ -88,6 +91,18 @@ clear_old_variables($anvil); # This removes network interfaces that have been marked as DELETED for a while now. clear_old_interfaces($anvil); +# Write out the interface cache +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + "cache::new_file" => $anvil->data->{cache}{new_file}, + "path::data::network_cache" => $anvil->data->{path}{data}{network_cache}, +}}); +$anvil->Storage->write_file({ + body => $anvil->data->{cache}{new_file}, + file => $anvil->data->{path}{data}{network_cache}, + overwrite => 1, + backup => 0, +}); + # Shut down. $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); @@ -96,6 +111,66 @@ $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); # Functions # ############################################################################################################# +# This reads in the interface cache file and looks for records that haven't been stored in the database yet. +sub process_interface_cache +{ + my ($anvil) = @_; + + # Does the file exist? If so, read it in. + if (-e $anvil->data->{path}{data}{network_cache}) + { + my $body = $anvil->Storage->read_file({debug => 2, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}}); + foreach my $line (split/\n/, $body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + next if $line =~ /^#/; + my ($nm_device, $timestamp, $mac_address, $speed, $link_state, $operational, $nm_uuid, $nm_name) = (split/,/, $line); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + timestamp => $timestamp, + speed => $speed, + mac_address => $mac_address, + link_state => $link_state, + operational => $operational, + nm_uuid => $nm_uuid, + nm_device => $nm_device, + }}); + + if ($anvil->data->{sys}{database}{connections}) + { + my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({ + debug => 2, + link_only => 1, + timestamp => $timestamp, + network_interface_name => $nm_device, + network_interface_link_state => $link_state, + network_interface_mac_address => $mac_address, + network_interface_operational => $operational, + network_interface_speed => $speed, + network_interface_nm_uuid => $nm_uuid, + network_interface_device => $nm_device, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }}); + if (not $network_interface_uuid) + { + # Failed to update, could be that we cached data for an interface not yet + # seen. If so, the coming scan will add it and this cache should flush out + # next time. + $anvil->data->{cache}{new_file} .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); + } + } + else + { + # No database, re-cache + $anvil->data->{cache}{new_file} .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); + } + } + } + + return(0); +} + # This removes network interfaces that have been marked as DELETED for a while now. sub clear_old_interfaces { @@ -124,7 +199,7 @@ sub clear_old_interfaces foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid})." (".$uuid.")", + uuid => $anvil->Database->get_host_from_uuid({debug => 2, short => 1, host_uuid => $uuid})." (".$uuid.")", }}); my $query = " SELECT @@ -460,19 +535,12 @@ sub collect_data { my ($anvil) = @_; - $anvil->Network->get_ips({debug => 2}); - - # Read the data from the ifcfg files, if available. We'll use this to check for bond interfaces that - # didn't start. - $anvil->Network->check_network(); - my $uptime = $anvil->Get->uptime(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }}); - if ($uptime < 600) - { - $anvil->Network->read_nmcli({debug => 2}) - } + # Read in data from Network Manager + $anvil->Network->collect_data({debug => 2}); + ### TODO: We can get the IPs from collect_data, we should phase this out. # The 'local_host' is needed to pull data recorded by Network->get_ips(); + $anvil->Network->get_ips({debug => 2}); my $local_host = $anvil->Get->short_host_name(); my $directory = "/sys/class/net"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { @@ -480,6 +548,7 @@ sub collect_data directory => $directory, }}); + ### TODO: Convert this to use Sys::Virt # Make sure there are no virsh bridges, removing any found. my $host_type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); @@ -516,61 +585,11 @@ sub collect_data set_by => $THIS_FILE, }); } -=cut - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list --all --name"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - - # This often hangs. - 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, - }}); - if (not $return_code) - { - # Virsh is up. - foreach my $line (split/\n/, $output) - { - $line =~ s/^\s+//; - $line =~ s/\s+$//; - next if not $line; - next if $line =~ /^error/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "striker_0287", variables => { bridge => $line }}); - - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$line; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - 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, - }}); - - $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$line; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($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, - }}); - - # Register an alert - my $variables = { - bridge => $line, - }; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0001", variables => $variables}); - $anvil->Alert->register({ - alert_level => "notice", - message => "scan_network_alert_0001", - variables => $variables, - set_by => $THIS_FILE, - }); - } - } -=cut } + # Collect data from nmcli + $anvil->Network->collect_data({debug => 2}); + # Walk through the sysfs files. local(*DIRECTORY); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); @@ -584,27 +603,27 @@ sub collect_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); if (-d $full_path) { + ### NOTE: The 'interface' maps to the network manager 'GENERAL.IP-IFACE', which is + ### 'network_interface_device'. The 'network_interface_name' is the biosdevname. # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. my $interface = $file; my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; + $link_state =~ s/\n$//; my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; + $mtu =~ s/\n$//; my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? + $duplex =~ s/\n$//; my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down + $operational =~ s/\n$//; my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; + $modalias =~ s/\n$//; my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link - my $media = "unknown"; - my $type = "interface"; - my $driver = ""; - my $tx_bytes = 0; # How many bytes transmitted - my $rx_bytes = 0; # How many bytes received - - # Clean up some newlines. - $link_state =~ s/\n$//; - $mtu =~ s/\n$//; - $duplex =~ s/\n$//; - $operational =~ s/\n$//; - $speed =~ s/\n$//; - $modalias =~ s/\n$//; + $speed =~ s/\n$//; + my $media = "unknown"; + my $type = "interface"; + my $driver = ""; + my $tx_bytes = 0; # How many bytes transmitted + my $rx_bytes = 0; # How many bytes received $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, link_state => $link_state, @@ -615,6 +634,31 @@ sub collect_data modalias => $modalias, }}); + # Try to find the nm_uuid + my $nm_uuid = ""; + if ((exists $anvil->data->{nmcli}{name}{$interface}) && ($anvil->data->{nmcli}{name}{$interface}{uuid})) + { + $nm_uuid = $anvil->data->{nmcli}{name}{$interface}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }}); + } + elsif ((exists $anvil->data->{nmcli}{device}{$interface}) && ($anvil->data->{nmcli}{device}{$interface}{uuid})) + { + $nm_uuid = $anvil->data->{nmcli}{device}{$interface}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }}); + } + + my $nm_device = ""; # biosdevname + my $nm_name = ""; # ip name + if ($nm_uuid) + { + $nm_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + $nm_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{name}; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + nm_device => $nm_device, + nm_name => $nm_name, + }}); + ### NOTE: This only parses virtio so far. # Pick out our driver. if ($modalias =~ /^virtio:/) @@ -729,7 +773,12 @@ sub collect_data { # Yup, we'll neet to dig into the bond proc files to get the proper slaved # interface MAC addresses. - $type = "bond"; + $type = "bond"; + $nm_uuid = $anvil->data->{nmcli}{bond}{$interface}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + type => $type, + nm_uuid => $nm_uuid, + }}); # Read the bond mode. $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); @@ -777,9 +826,9 @@ sub collect_data $bridge_stp_enabled =~ s/\n$//; $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + type => $type, bridge_id => $bridge_id, bridge_stp_enabled => $bridge_stp_enabled, - type => $type, }}); if ($bridge_stp_enabled eq "0") { @@ -851,7 +900,7 @@ sub collect_data } # Find the media, if possible. - (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); + (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." ".$interface}); foreach my $line (split/\n/, $ethtool) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); @@ -871,6 +920,9 @@ sub collect_data } # Store new information we found. + $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid} = $nm_uuid; + $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device} = $nm_device; + $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name} = $nm_name; $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; @@ -892,6 +944,9 @@ sub collect_data $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "network::${local_host}::interface::${interface}::nm_uuid" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}, + "network::${local_host}::interface::${interface}::nm_device" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}, + "network::${local_host}::interface::${interface}::nm_name" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name}, "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, @@ -921,7 +976,12 @@ sub collect_data # If this is a link and there's no database connections, cache the data. if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + nm_name => $nm_name, + nm_device => $nm_device, + }}); + # nm_device,timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_name + $anvil->data->{cache}{new_file} .= $nm_device.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",".$nm_uuid.",".$nm_name."\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::new_file" => $anvil->data->{cache}{new_file}, }}); @@ -950,6 +1010,7 @@ sub collect_data if ($type eq "bridge") { # Store the bridge + $anvil->data->{new}{bridge}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; $anvil->data->{new}{bridge}{$interface}{id} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; $anvil->data->{new}{bridge}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; $anvil->data->{new}{bridge}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; @@ -957,6 +1018,7 @@ sub collect_data $anvil->data->{new}{bridge}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{bridge}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::bridge::${interface}::nm_uuid" => $anvil->data->{new}{bridge}{$interface}{nm_uuid}, "new::bridge::${interface}::id" => $anvil->data->{new}{bridge}{$interface}{id}, "new::bridge::${interface}::mac_address" => $anvil->data->{new}{bridge}{$interface}{mac_address}, "new::bridge::${interface}::mtu" => $anvil->data->{new}{bridge}{$interface}{mtu}, @@ -968,6 +1030,7 @@ sub collect_data elsif ($type eq "bond") { # Store the bond + $anvil->data->{new}{bond}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; $anvil->data->{new}{bond}{$interface}{mode} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; $anvil->data->{new}{bond}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; $anvil->data->{new}{bond}{$interface}{master} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; @@ -984,6 +1047,7 @@ sub collect_data $anvil->data->{new}{bond}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{bond}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::bond::${interface}::nm_uuid" => $anvil->data->{new}{bond}{$interface}{nm_uuid}, "new::bond::${interface}::mode" => $anvil->data->{new}{bond}{$interface}{mode}, "new::bond::${interface}::mtu" => $anvil->data->{new}{bond}{$interface}{mtu}, "new::bond::${interface}::master" => $anvil->data->{new}{bond}{$interface}{master}, @@ -1004,6 +1068,9 @@ sub collect_data elsif ($type eq "interface") { # Store the interface + $anvil->data->{new}{interface}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; + $anvil->data->{new}{interface}{$interface}{nm_device} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}; + $anvil->data->{new}{interface}{$interface}{nm_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name}; $anvil->data->{new}{interface}{$interface}{bond_uuid} = ""; $anvil->data->{new}{interface}{$interface}{bond_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; $anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; @@ -1018,6 +1085,9 @@ sub collect_data $anvil->data->{new}{interface}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{interface}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::interface::${interface}::nm_uuid" => $anvil->data->{new}{interface}{$interface}{nm_uuid}, + "new::interface::${interface}::nm_device" => $anvil->data->{new}{interface}{$interface}{nm_device}, + "new::interface::${interface}::nm_name" => $anvil->data->{new}{interface}{$interface}{nm_name}, "new::interface::${interface}::bond_uuid" => $anvil->data->{new}{interface}{$interface}{bond_uuid}, "new::interface::${interface}::bond_name" => $anvil->data->{new}{interface}{$interface}{bond_name}, "new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, @@ -1032,48 +1102,6 @@ sub collect_data "new::interface::${interface}::tx_bytes" => $anvil->data->{new}{interface}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{tx_bytes}}).")", "new::interface::${interface}::rx_bytes" => $anvil->data->{new}{interface}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{rx_bytes}}).")", }}); - - # On some occassions, an interface that is in a bond won't start. If the host uptime - # is less than ten minutes, and a bond's member interface is down, up it. - if ($uptime < 600) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::${local_host}::device_to_uuid::${interface}" => $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$interface}, - }}); - my $uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$interface}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); - - if ($uuid) - { - my $state = $anvil->data->{nmcli}{$local_host}{uuid}{$uuid}{'state'}; - my $filename = $anvil->data->{nmcli}{$local_host}{uuid}{$uuid}{filename}; - my $name = ($filename =~ /ifcfg-(.*?)$/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - filename => $filename, - name => $name, - 'state' => $state, - }}); - - # This could be 'active' or 'activated' - if ($state !~ /activ/) - { - # Try brinding the interface up. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0147", variables => { - interface => $interface, - uptime => $uptime, - 'state' => $state, - }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - 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, - }}); - } - } - } } # Record the IP address info. @@ -1097,7 +1125,7 @@ sub collect_data }}); } } - + return(0); } @@ -1778,9 +1806,11 @@ sub load_interface_data # Process interfaces my $query = " SELECT - network_interface_uuid, + network_interface_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, @@ -1805,12 +1835,14 @@ WHERE foreach my $row (@{$results}) { my $network_interface_uuid = $row->[0]; - my $network_interface_mac_address = $row->[1]; - my $network_interface_name = $row->[2]; + my $network_interface_mac_address = $row->[2]; + my $network_interface_name = $row->[3]; + my $network_interface_device = $row->[4]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, network_interface_mac_address => $network_interface_mac_address, network_interface_name => $network_interface_name, + network_interface_device => $network_interface_device, }}); # Read in the RX/TX values, set to '0' if not found. @@ -1833,23 +1865,27 @@ WHERE tx_variable_uuid => $tx_variable_uuid, }}); + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_nm_uuid} = $row->[1]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed} = $row->[3]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu} = $row->[4]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state} = $row->[5]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $row->[6]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex} = $row->[7]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium} = $row->[8]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = defined $row->[9] ? $row->[9] : ''; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = defined $row->[10] ? $row->[10] : ''; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device} = $network_interface_device; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed} = $row->[5]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu} = $row->[6]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state} = $row->[7]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $row->[8]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex} = $row->[9]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium} = $row->[10]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = defined $row->[11] ? $row->[11] : ''; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = defined $row->[12] ? $row->[12] : ''; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes} = $rx_bytes =~ /^\d+$/ ? $rx_bytes : 0; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid} = $rx_variable_uuid; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes} = $tx_bytes =~ /^\d+$/ ? $tx_bytes : 0; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid} = $tx_variable_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_nm_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_nm_uuid}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, + "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_device" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_speed" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mtu" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_link_state" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}, @@ -1865,14 +1901,18 @@ WHERE }}); $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; + $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device} = $network_interface_uuid; $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; + $anvil->data->{interface}{device_to_uuid}{$network_interface_device} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, + "network_interfaces::device_to_uuid::${network_interface_device}" => $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device}, "network_interfaces::uuid_to_name::${network_interface_name}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${network_interface_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, + "interface::device_to_uuid::${network_interface_device}" => $anvil->data->{interface}{device_to_uuid}{$network_interface_device}, }}); } @@ -2105,7 +2145,6 @@ sub check_ip_addresses { my $on_interface = $anvil->data->{new}{ip_address}{$ip_address}{on_interface}; my $new_on_type = $anvil->data->{interface}{name_to_type}{$on_interface}; - my $new_on_uuid = $anvil->data->{interface}{name_to_uuid}{$on_interface}; my $new_subnet_mask = $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}; my $new_gateway = $anvil->data->{new}{ip_address}{$ip_address}{gateway}; my $new_default_gateway = $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}; @@ -2114,12 +2153,22 @@ sub check_ip_addresses ip_address => $ip_address, on_interface => $on_interface, new_on_type => $new_on_type, - new_on_uuid => $new_on_uuid, new_subnet_mask => $new_subnet_mask, new_gateway => $new_gateway, new_default_gateway => $new_default_gateway, new_dns => $new_dns, }}); + my $new_on_uuid = ""; + if ($anvil->data->{interface}{name_to_uuid}{$on_interface}) + { + $new_on_uuid = $anvil->data->{interface}{name_to_uuid}{$on_interface}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_on_uuid => $new_on_uuid }}); + } + elsif ($anvil->data->{interface}{device_to_uuid}{$on_interface}) + { + $new_on_uuid = $anvil->data->{interface}{device_to_uuid}{$on_interface}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_on_uuid => $new_on_uuid }}); + } if (exists $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address}) { @@ -2381,8 +2430,13 @@ sub check_interfaces { my ($anvil) = @_; + my $interfaces = keys %{$anvil->data->{new}{interface}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interfaces => $interfaces }}); foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}}) { + my $new_nm_uuid = $anvil->data->{new}{interface}{$network_interface_name}{nm_uuid}; + my $new_nm_name = $anvil->data->{new}{interface}{$network_interface_name}{nm_name}; + my $new_nm_device = $anvil->data->{new}{interface}{$network_interface_name}{nm_device}; my $new_bond_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bond_uuid}; my $new_bond_name = $anvil->data->{new}{interface}{$network_interface_name}{bond_name}; my $new_bridge_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bridge_uuid}; @@ -2398,6 +2452,9 @@ sub check_interfaces my $new_rx_bytes = $anvil->data->{new}{interface}{$network_interface_name}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_name => $network_interface_name, + new_nm_uuid => $new_nm_uuid, + new_nm_name => $new_nm_name, + new_nm_device => $new_nm_device, new_bond_uuid => $new_bond_uuid, new_bond_name => $new_bond_name, new_bridge_uuid => $new_bridge_uuid, @@ -2431,26 +2488,45 @@ sub check_interfaces } # New or existing? + my $network_interface_uuid = ""; if (exists $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}) + { + $network_interface_uuid = $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); + } + elsif (exists $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_name}) + { + $network_interface_uuid = $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); + } + elsif (($new_mac_address) && (exists $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address})) + { + $network_interface_uuid = $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); + } + if ($network_interface_uuid) { # Existing. Changes? - my $network_interface_uuid = $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}; - my $old_bond_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; - my $old_bond_name = ""; - my $old_bridge_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; - my $old_bridge_name = ""; - my $old_duplex = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}; - my $old_link_state = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}; - my $old_operational = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; - my $old_mac_address = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; - my $old_medium = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}; - my $old_mtu = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}; - my $old_speed = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}; - my $old_rx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}; - my $rx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}; - my $old_tx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}; - my $tx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}; + my $old_nm_name = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}; + my $old_nm_device = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device}; + my $old_bond_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; + my $old_bond_name = ""; + my $old_bridge_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; + my $old_bridge_name = ""; + my $old_duplex = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}; + my $old_link_state = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}; + my $old_operational = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; + my $old_mac_address = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; + my $old_medium = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}; + my $old_mtu = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}; + my $old_speed = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}; + my $old_rx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}; + my $rx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}; + my $old_tx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}; + my $tx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_nm_name => $old_nm_name, + old_nm_device => $old_nm_device, old_bond_uuid => $old_bond_uuid, old_bridge_uuid => $old_bridge_uuid, old_duplex => $old_duplex, @@ -2484,6 +2560,52 @@ sub check_interfaces # Look for changes. my $changes = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_name => $new_nm_name, + old_nm_name => $old_nm_name, + }}); + if ($new_nm_name ne $old_nm_name) + { + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + my $variables = { + name => $network_interface_name, + old => $old_nm_name, + new => $new_nm_name, + }; + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0062", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_network_alert_0062", + variables => $variables, + set_by => $THIS_FILE, + }); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_device => $new_nm_device, + old_nm_device => $old_nm_device, + }}); + if ($new_nm_device ne $old_nm_device) + { + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + my $variables = { + name => $network_interface_name, + old => $old_nm_device, + new => $new_nm_device, + }; + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0063", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_network_alert_0063", + variables => $variables, + set_by => $THIS_FILE, + }); + } if ($new_bond_uuid ne $old_bond_uuid) { # We're making this a warning level alert as it should not be changing. @@ -2813,11 +2935,17 @@ sub check_interfaces if ($changes) { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_name => $new_nm_name, + new_nm_device => $new_nm_device, + }}); my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, + network_interface_nm_uuid => $new_nm_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, - network_interface_name => $network_interface_name, + network_interface_name => $new_nm_name, # biosdevname + network_interface_device => $new_nm_device, # ip name network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -2946,11 +3074,18 @@ sub check_interfaces else { # Record the interface + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_name => $new_nm_name, + network_interface_name => $network_interface_name, + new_nm_device => $new_nm_device, + }}); my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, + network_interface_nm_uuid => $new_nm_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, - network_interface_name => $network_interface_name, + network_interface_name => $new_nm_name, + network_interface_device => $network_interface_name, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -2966,11 +3101,13 @@ sub check_interfaces $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; + $anvil->data->{interface}{device_to_uuid}{$new_nm_device} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, "network_interfaces::uuid_to_name::${network_interface_uuid}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${new_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, + "interface::device_to_uuid::${new_nm_device}" => $anvil->data->{interface}{device_to_uuid}{$new_nm_device}, }}); # Store the rx_bytes and tx_bytes @@ -3079,6 +3216,7 @@ sub check_bonds foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{new}{bond}}) { # Store the bond + my $new_nm_uuid = $anvil->data->{new}{bond}{$bond_name}{nm_uuid}; my $new_mode = $anvil->data->{new}{bond}{$bond_name}{mode}; my $new_mtu = $anvil->data->{new}{bond}{$bond_name}{mtu}; my $new_operational = $anvil->data->{new}{bond}{$bond_name}{operational}; @@ -3449,6 +3587,7 @@ sub check_bonds { my $bond_uuid = $anvil->Database->insert_or_update_bonds({ debug => 2, + bond_nm_uuid => $new_nm_uuid, bond_name => $bond_name, bond_mode => $new_mode, bond_mtu => $new_mtu, diff --git a/scancore-agents/scan-network/scan-network.xml b/scancore-agents/scan-network/scan-network.xml index 04908108..3dcfaf6d 100644 --- a/scancore-agents/scan-network/scan-network.xml +++ b/scancore-agents/scan-network/scan-network.xml @@ -133,6 +133,8 @@ Note: If this is a Storage Network directly connected to the peer, and the peer The network interface: [#!variable!name!#] appears to have been removed. The last time we saw it, it had transmitted: [#!variable!tx!#] and received: [#!variable!rx!#]. The IP address: [#!variable!ip!#] appears to no longer be used on this machine. The network interface: [#!variable!name!#] MAC address has changed from: [#!variable!old!#] to: [#!variable!new!#]. This is normal when a server boots or migrates. + The network interface: [#!variable!name!#] network manager's 'connection.id' name (biosdevname) has changed from: [#!variable!old!#] to: [#!variable!new!#]. + The network interface: [#!variable!name!#] network manager's 'GENERAL.IP-IFACE' name (ip addr name) has changed from: [#!variable!old!#] to: [#!variable!new!#]. Failed to read the network interface speed from the file: [#!variable!file!#]. Ignoring interface. diff --git a/scancore-agents/scan-server/scan-server b/scancore-agents/scan-server/scan-server index b3233196..3e8d0cfe 100755 --- a/scancore-agents/scan-server/scan-server +++ b/scancore-agents/scan-server/scan-server @@ -856,6 +856,7 @@ sub collect_data new_anvil_name => $anvil->Get->anvil_name_from_uuid({anvil_uuid => $server_anvil_uuid}), new_anvil_uuid => $server_anvil_uuid, }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0009", variables => $variables}); $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0009", variables => $variables, set_by => $THIS_FILE}); $update = 1; diff --git a/share/anvil.sql b/share/anvil.sql index ea6de393..11cdf49f 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -855,6 +855,7 @@ CREATE TRIGGER trigger_jobs CREATE TABLE bridges ( bridge_uuid uuid not null primary key, bridge_host_uuid uuid not null, + bridge_nm_uuid uuid, -- This is the network manager UUID for this bridge interface bridge_name text not null, bridge_id text not null, bridge_mac_address text not null, @@ -870,6 +871,7 @@ CREATE TABLE history.bridges ( history_id bigserial, bridge_uuid uuid, bridge_host_uuid uuid, + bridge_nm_uuid uuid, bridge_name text, bridge_id text, bridge_mac_address text, @@ -888,6 +890,7 @@ BEGIN INSERT INTO history.bridges (bridge_uuid, bridge_host_uuid, + bridge_nm_uuid, bridge_name, bridge_id, bridge_mac_address, @@ -897,6 +900,7 @@ BEGIN 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, @@ -918,6 +922,7 @@ CREATE TRIGGER trigger_bridges CREATE TABLE bonds ( bond_uuid uuid not null primary key, bond_host_uuid uuid not null, + bond_nm_uuid uuid, -- The is the network manager UUID for this bond. bond_name text not null, bond_mode text not null, -- This is the numerical bond type (will translate to the user's language in the Anvil!) bond_mtu bigint not null, @@ -941,6 +946,7 @@ CREATE TABLE history.bonds ( history_id bigserial, bond_uuid uuid, bond_host_uuid uuid, + bond_nm_uuid uuid, bond_name text, bond_mode text, bond_mtu bigint, @@ -964,8 +970,9 @@ DECLARE BEGIN SELECT INTO history_bonds * FROM bonds WHERE bond_uuid = new.bond_uuid; INSERT INTO history.bonds - (bond_uuid, - bond_host_uuid, + (bond_uuid, + bond_host_uuid, + bond_nm_uuid, bond_name, bond_mode, bond_mtu, @@ -980,8 +987,9 @@ BEGIN bond_bridge_uuid, modified_date) VALUES - (history_bonds.bond_uuid, - history_bonds.bond_host_uuid, + (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, @@ -1011,8 +1019,10 @@ CREATE TRIGGER trigger_bonds CREATE TABLE network_interfaces ( network_interface_uuid uuid not null primary key, network_interface_host_uuid uuid not null, - network_interface_mac_address text not null, - network_interface_name text not null, -- This is the current name of the interface. + network_interface_nm_uuid uuid, -- This is the network manager UUID used to track the device. It can change, so we can't used this as the main UUID + network_interface_mac_address text not null, -- This is the interface MAC address, and it can change if a failed controller it replaced. + network_interface_name text not null, -- This is the current name (network manager's connection.id) of the interface. + network_interface_device text not null, -- This is the current device name (network manager's GENERAL.IP-IFACE) of the interface. network_interface_speed bigint not null, -- This is the speed, in bits-per-second, of the interface. network_interface_mtu bigint not null, -- This is the MTU (Maximum Transmitable Size), in bytes, for this interface. network_interface_link_state text not null, -- 0 or 1 @@ -1033,8 +1043,10 @@ CREATE TABLE history.network_interfaces ( history_id bigserial, network_interface_uuid uuid not null, network_interface_host_uuid uuid, + network_interface_nm_uuid uuid, network_interface_mac_address text, network_interface_name text, + network_interface_device text, network_interface_speed bigint, network_interface_mtu bigint, network_interface_link_state text, @@ -1056,8 +1068,10 @@ BEGIN 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, @@ -1070,8 +1084,10 @@ BEGIN 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, @@ -1096,7 +1112,7 @@ CREATE TRIGGER trigger_network_interfaces CREATE TABLE ip_addresses ( ip_address_uuid uuid not null primary key, ip_address_host_uuid uuid not null, - ip_address_on_type text not null, -- Either 'interface', 'bond' or 'bridge' + ip_address_on_type text not null, -- Either 'interface', 'bond', 'bridge' or 'network_manager' ip_address_on_uuid uuid not null, -- This is the UUID of the interface, bond or bridge that has this IP ip_address_address text not null, -- The actual IP address ip_address_subnet_mask text not null, -- The subnet mask (in dotted decimal format) @@ -1167,6 +1183,91 @@ CREATE TRIGGER trigger_ip_addresses FOR EACH ROW EXECUTE PROCEDURE history_ip_addresses(); +/* + TODO - This will be added only if we need to use it if the existing network tables aren't sufficient +-- This stores information about network interfaces on hosts. It is mainly used to match a MAC address to a +-- host. Given that it is possible that network devices can move, the linkage to the host_uuid can change. +CREATE TABLE network_manager ( + network_manager_uuid uuid not null primary key, -- Unlike most other tables, this UUID comes from nmcli itself, and so this matches what's displayed nmcli + network_manager_host_uuid uuid not null, -- The host_uuid for this interface + network_manager_device text not null, -- This is the nmcli "device" name + network_manager_name text not null, -- This is the nmcli "name" name + network_manager_mac text not null, -- This is the MAC address of the interface + network_manager_type text not null, -- This is the nmcli "type" string + network_manager_active text not null, -- This is the nmcli "active" field + network_manager_state text not null, -- This is the nmcli "state" field + network_manager_connected numeric not null, -- This is '0' if the connection is down, or a unix timestamp if it's up. + network_manager_mtu numeric not null, -- This is the MTU of the interface + modified_date timestamp with time zone not null, + + FOREIGN KEY(network_manager_host_uuid) REFERENCES hosts(host_uuid) + ); +ALTER TABLE network_manager OWNER TO admin; + +CREATE TABLE history.network_manager ( + history_id bigserial, + network_manager_uuid uuid not null, + network_manager_host_uuid uuid, + network_manager_mac_address text, + network_manager_name text, + network_manager_speed bigint, + network_manager_mtu bigint, + network_manager_link_state text, + network_manager_operational text, + network_manager_duplex text, + network_manager_medium text, + network_manager_bond_uuid uuid, + network_manager_bridge_uuid uuid, + modified_date timestamp with time zone not null +); +ALTER TABLE history.network_manager OWNER TO admin; + +CREATE FUNCTION history_network_manager() RETURNS trigger +AS $$ +DECLARE + history_network_manager RECORD; +BEGIN + SELECT INTO history_network_manager * FROM network_manager WHERE network_manager_uuid = new.network_manager_uuid; + INSERT INTO history.network_manager + (network_manager_uuid, + network_manager_host_uuid, + network_manager_mac_address, + network_manager_name, + network_manager_speed, + network_manager_mtu, + network_manager_link_state, + network_manager_operational, + network_manager_duplex, + network_manager_medium, + network_manager_bond_uuid, + network_manager_bridge_uuid, + modified_date) + VALUES + (history_network_manager.network_manager_uuid, + history_network_manager.network_manager_host_uuid, + history_network_manager.network_manager_mac_address, + history_network_manager.network_manager_name, + history_network_manager.network_manager_speed, + history_network_manager.network_manager_mtu, + history_network_manager.network_manager_link_state, + history_network_manager.network_manager_operational, + history_network_manager.network_manager_duplex, + history_network_manager.network_manager_medium, + history_network_manager.network_manager_bond_uuid, + history_network_manager.network_manager_bridge_uuid, + history_network_manager.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_network_manager() OWNER TO admin; + +CREATE TRIGGER trigger_network_manager + AFTER INSERT OR UPDATE ON network_manager + FOR EACH ROW EXECUTE PROCEDURE history_network_manager(); +*/ + + -- This stores files made available to Anvil! systems and DR hosts. CREATE TABLE files ( file_uuid uuid not null primary key, diff --git a/share/words.xml b/share/words.xml index fef25809..0f3b4ec1 100644 --- a/share/words.xml +++ b/share/words.xml @@ -752,6 +752,33 @@ The XML that failed sanity check was: [ Error ] - The requested number of cores: [#!variable!requested_cores!#] (sockets: [#!variable!new_sockets!], cores per socket: [#!variable!new_cores!#], threads per core: [#!variable!new_threads!#]). [ Error ] - This program must be run on a subnode. [ Error ] - This subnode is not in the cluster (failed to parse the CIB). Exiting. + [ Error ] - The wanted interface: [#!variable!interface_name!#] which should have the MAC address: [#!variable!mac_address!#] was not found in Network Manager. Unable to proceed. + [ Error ] - Failed to delete the 'connection.interface-name', got: [#!variable!output!#] and it should bhave been blank, aborting! + [ Error ] - Failed to create the 'match.interface-name' value. Expected: [#!variable!new_name!#,#!variable!old_device!#], got: [#!variable!output!#], aborting! + [ Error ] - The attempt to add the bond: [#!variable!bond_name!#] failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The attempt to add the network link: [#!variable!link_name!#] to the bond: [#!variable!bond_name!#] failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The attempt to add the bridge: [#!variable!bridge_name!# failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The attempt to add the device: [#!variable!on_device!#] to the bridge: [#!variable!bridge_name!#] failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The subnet_mask: [#!variable!subnet_mask!#] is not valid. It must be either a CIDR notation, or a dotted-decimal mask that can be translated to CIDR notation. + [ Error ] - Can't find a device to assign the: [#!variable!network!#] IP address: [#!variable!ip_address!#/#!variable!subnet_mask!#] to! + [ Error ] - Failed to map the IP address: [#!variable!ip_address!#] to a network manager connection UUID! + [ Error ] - Both the netbios name: [#!variable!wanted_link_name!#] and the old device name: [#!variable!old_device!#] are the same, 'match.interface-name' would break! @@ -2681,6 +2708,13 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The physical volume: [#!variable!pv_name!#] has been resized! The user answered: [#!variable!answer!#] + Failed to connect to any database, waiting before trying to connect again. We will reboot if we do not connect in: [#!variable!time_left!#] second. + The host: [#!variable!host_name!#] was found in the '/etc/hosts' file with the expected IP: [#!variable!ip_address!#]! + The host: [#!variable!host_name!#] was found in the '/etc/hosts' file, but the expected IP: [#!variable!ip_address!#] doesn't match the found IP: [#!variable!found_ip!#]! Ignoring this entry. + The host: [#!variable!host_name!#] was found not found in the '/etc/hosts' file! We'll wait a few seconds and check again. + All host names were found in '/etc/hosts', ready to proceed! + One or more hosts are not yet in the '/etc/hosts' file with expected IPs. We'll wait a short bit and check again. + There are entries we need to add to the '/etc/hosts' file before we can form the cluster, updating it now. The host name: [#!variable!target!#] does not resolve to an IP address. @@ -3284,6 +3318,42 @@ proceeding. - Threads per Core: [#!variable!old_threads!#] -> [#!variable!new_threads!#] - Total Cores: .... [#!variable!old_total_cores!#] -> [#!variable!new_total_cores!#]]]> + ' to exit]]> + Renaming old device/name: [#!variable!old_device!#/#!variable!old_name!#] with MAC: [#!variable!mac_address!#] to: [#!variable!new_name!#] using UUID: [#!variable!nm_uuid!#]. + - Updating the udev file: [#!variable!file!#]. + - Removing the old 'connection.interface-name': [#!variable!name!#]. + - Matching the new interface name: [#!variable!new_name!#] to the bios device name: [#!variable!old_device!#]. + - Setting the connection.id to the bios device name: [#!variable!old_device!#] + The new interface names need a reboot to take effect. + Rebooting NOW! The job will restart on reboot. + Checking if the bond: [#!variable!bond_name!#] exists or not. + - It does, its UUID is: [#!variable!nm_uuid!#]. + - The bond: [#!variable!bond_name!#] doesn't exist. Will create it using the primary interface: [#!variable!link1_name!#] (MAC: [#!variable!link1_mac!#], NM UUID: [#!variable!link1_nm_uuid!#) and the backup interface: [#!variable!link2_name!#] (MAC: [#!variable!link2_mac!#], NM UUID: [#!variable!link2_nm_uuid!#). + Checking to see if the IP address: [#!variable!ip_address!#/#!variable!subnet_mask!#] is assigned to: [#!variable!device!#] yet. + - Done! Rescanning the network config. + - The interface: [#!variable!link_name!#] (#!variable!nm_uuid!#) is already a member of the bond. + - The interface: [#!variable!link_name!#] (#!variable!nm_uuid!#) is a member of the bond: [#!variable!old_bond!#], switching it to this bond. + - The interface: [#!variable!link_name!#] (#!variable!nm_uuid!#) needs to be connected to the bond. + - The IP exists, checking if it needs to be updated. + - Connecting the interface: [#!variable!link_name!#] to the bond: [#!variable!bond_name!#]. + Checking if the bridge: [#!variable!bridge_name!#] exists and that it is on: [#!variable!on_device!#] + - The bridge exists! + - The IP address is on: [#!variable!device!#], will move the IP. + - Resetting the device: [#!variable!device!#] (#!variable!device_uuid!#) to make sure the new config takes effect. + - Checking that the device: [#!variable!on_device!#] is connected to this bridge. + - The device is connected to the bridge already. + - The device is on the bridge: [#!variable!on_device_parent!#], moving it. + - The device is not on this bridge, connecting it. + - Disabling DHCP on the device: [#!variable!device!#] (#!variable!device_uuid!#). + - Connecting it now. + - The current subnet mask is: [#!variable!current_subnet_mask!#], will update. + - The current gateway is: [#!variable!current_gateway!#], will update. + - The current DNS is: [#!variable!current_dns!#], will update. + - No update is needed. + - The IP address needs to be assigned. + [ Note ] - Reconfiguring the network will break connections. Disconnecting from the database before starting. It might take a bit before this system reconnects and progress can be seen. + [ Note ] - The network has reconnected to the database, configuring will complete shortly. + [ Note ] - The old 'ifcfg' style config file: [#!variable!file!#] will be backed up and then removed! + [ Note ] - Updated the ssh daemon config file: [#!variable!file!#] to enable ssh access for the root user. Normal Password @@ -4094,6 +4164,7 @@ We will try to proceed anyway. ==== Please specify a storage group to use to add the new drive to. + [ Warning ] - After reconfiguring the network, we've failed to connect to any database for two minutes. Rebooting in case this fixes the connection. diff --git a/tools/Makefile.am b/tools/Makefile.am index 88e9ec61..bdd4fddd 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -42,7 +42,6 @@ dist_sbin_SCRIPTS = \ anvil-test-alerts \ anvil-update-definition \ anvil-update-issue \ - anvil-update-states \ anvil-update-system \ anvil-version-changes \ anvil-virsh-wrapper \ diff --git a/tools/anvil-check-memory b/tools/anvil-check-memory index 971ade0a..acf0bb72 100755 --- a/tools/anvil-check-memory +++ b/tools/anvil-check-memory @@ -84,7 +84,7 @@ foreach my $pid (sort {$a cmp $b} @{$anvil->data->{sys}{pids}}) { my $size = $1; my $type = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type, size => $size, }}); @@ -94,10 +94,10 @@ foreach my $pid (sort {$a cmp $b} @{$anvil->data->{sys}{pids}}) # This uses 'kB' for 'KiB' >_> $type = lc($type); $type =~ s/b$/ib/ if $type !~ /ib$/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type }}); my $size_in_bytes = $anvil->Convert->human_readable_to_bytes({size => $size, type => $type, base2 => 1}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { size_in_bytes => $anvil->Convert->add_commas({number => $size_in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size_in_bytes}).")", }}); diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 231341ac..10e4df6f 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -40,6 +40,9 @@ my $anvil = Anvil::Tools->new(); $anvil->Get->switches({list => ["job-uuid"], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + # Make sure we're running as 'root' # $< == real UID, $> == effective UID if (($< != 0) && ($> != 0)) @@ -64,7 +67,7 @@ pickup_job_details($anvil); overwrite_variables_with_switches($anvil); # Set maintenance mode -$anvil->System->maintenance_mode({set => 1}); +#$anvil->System->maintenance_mode({set => 1}); # Reconfigure the network. reconfigure_network($anvil); @@ -83,24 +86,15 @@ $anvil->Database->insert_or_update_variables({ update_passwords($anvil); $anvil->Job->update_progress({ - debug => 3, - progress => 100, - message => "", - job_uuid => $anvil->data->{job}{uuid}, + progress => 100, + message => "", + job_uuid => $anvil->data->{job}{uuid}, }); # Clear maintenance mode. $anvil->System->maintenance_mode({set => 0, debug => 2}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0467"}); -### TODO: As of now, the network doesn't come up reliably, so reboot. We add a 60 second delay to make it -### easier to log in and disable anvil-daemon in case of reboot loops caused by this program thinking -### it needs to reconfigure the system every run. -# if ($anvil->data->{sys}{reboot}) -# { -# do_reboot($anvil); -# } - $anvil->nice_exit({exit_code => 0}); @@ -113,28 +107,44 @@ sub do_reboot { my ($anvil) = @_; -### TODO: Nothing should be killing us, anything that could should be updated to hold while we run. -# # Mark that a reboot is needed, in case something kills us before we actually reboot. -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "#!string!log_0693!#" }}); -# my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ -# file => $THIS_FILE, -# line => __LINE__, -# job_command => $anvil->data->{path}{exe}{'anvil-manage-power'}." --reboot -y".$anvil->Log->switches, -# job_data => "", -# job_name => "reboot::system", -# job_title => "job_0009", -# job_description => "job_0006", -# job_progress => 0, -# }); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); - + # Tell the user why we're rebooting + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 5}), + message => "message_0388", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + }); my $time_left = 60; while ($time_left) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0626", variables => { seconds => $time_left }}); + # Give them the countdown. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "log_0626", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { seconds => $time_left }, + }); sleep 10; $time_left -= 10; } + + # Last, log that we're going down now. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0389", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + }); my $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); @@ -143,17 +153,19 @@ sub do_reboot return(0); } -# This updates the passwords on the root user, admin user, database and apache user. +# This updates the passwords on the root user, admin user, database and striker-ui-api user. sub update_passwords { my ($anvil) = @_; # Have we been asked to set a password? - $anvil->data->{variables}{form}{config_step2}{striker_password}{value} = "" if not defined $anvil->data->{variables}{form}{config_step2}{striker_password}{value}; - if ($anvil->data->{variables}{form}{config_step2}{striker_password}{value}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { + "config::striker_password" => $anvil->data->{config}{striker_password}, + }}); + if ($anvil->data->{config}{striker_password}) { # Set the passwords - my $password = $anvil->data->{variables}{form}{config_step2}{striker_password}{value}; + my $password = $anvil->data->{config}{striker_password}; my $temp_file = "/tmp/anvil-".$anvil->Get->uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { password => $password }}); @@ -172,7 +184,17 @@ sub update_passwords if ($error) { # Couldn't write the temp file. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "message_0030", variables => { file => $temp_file }}); + $anvil->Job->update_progress({ + progress => 100, + message => "message_0030", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { file => $temp_file }, + }); $anvil->nice_exit({exit_code => 5}); } else @@ -235,18 +257,17 @@ sub reconfigure_network { my ($anvil) = @_; - my $local_host = $anvil->Get->short_host_name(); - my $reboot_needed = 0; - my $prefix = exists $anvil->data->{variables}{form}{config_step1}{prefix}{value} ? $anvil->data->{variables}{form}{config_step1}{prefix}{value} : ""; - my $sequence = exists $anvil->data->{variables}{form}{config_step1}{sequence}{value} ? $anvil->data->{variables}{form}{config_step1}{sequence}{value} : ""; - my $domain = exists $anvil->data->{variables}{form}{config_step1}{domain}{value} ? $anvil->data->{variables}{form}{config_step1}{domain}{value} : ""; - my $organization = exists $anvil->data->{variables}{form}{config_step1}{organization}{value} ? $anvil->data->{variables}{form}{config_step1}{organization}{value} : ""; - my $bcn_count = exists $anvil->data->{variables}{form}{config_step1}{bcn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{bcn_count}{value} : 1; - my $sn_count = exists $anvil->data->{variables}{form}{config_step1}{sn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{sn_count}{value} : 0; - my $mn_count = exists $anvil->data->{variables}{form}{config_step1}{mn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{mn_count}{value} : 0; - my $ifn_count = exists $anvil->data->{variables}{form}{config_step1}{ifn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{ifn_count}{value} : 1; - my $new_host_name = exists $anvil->data->{variables}{form}{config_step2}{host_name}{value} ? $anvil->data->{variables}{form}{config_step2}{host_name}{value} : ""; - my $type = $anvil->Get->host_type(); + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $new_host_name = $anvil->data->{config}{host_name}; + my $organization = $anvil->data->{config}{organization}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { prefix => $prefix, sequence => $sequence, @@ -259,18 +280,6 @@ sub reconfigure_network new_host_name => $new_host_name, type => $type, }}); - - # Clear the network mapping flag. - $anvil->Database->insert_or_update_variables({ - debug => 2, - variable_name => "config::map_network", - variable_value => 0, - variable_default => "", - variable_description => "striker_0202", - variable_section => "config", - variable_source_uuid => $anvil->Get->host_uuid, - variable_source_table => "hosts", - }); # If we're configuring a dashboard and no host name was given, generate it. if (($type eq "striker") && (not $new_host_name)) @@ -314,42 +323,39 @@ sub reconfigure_network { # Success $anvil->Job->update_progress({ - progress => 10, - message => "message_0016,!!host_name!$new_host_name!!", - job_uuid => $anvil->data->{job}{uuid}, + progress => $anvil->Job->bump_progress({steps => 5}), + message => "message_0016", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { host_name => $new_host_name }, }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "message_0016", variables => { host_name => $new_host_name }}); } else { # Failed $anvil->Job->update_progress({ - progress => 0, - message => "message_0017,!!host_name!$new_host_name!!,!!bad_host_name!$host_name!!", - job_uuid => $anvil->data->{job}{uuid}, + progress => 100, + message => "message_0017", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + job_status => "failed", + variables => { + host_name => $new_host_name, + bad_host_name => $host_name, + }, }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "message_0017", variables => { - host_name => $new_host_name, - bad_host_name => $host_name, - }}); $anvil->nice_exit({exit_code => 4}); } } - # Read the local network manager data. - $anvil->Network->read_nmcli({debug => 2}); - - # Get the current list of IPs and MAC addresses. - $anvil->Network->get_ips({debug => 2}); - - # If we're a striker, check apache's config. - if ($type eq "striker") - { - $anvil->Striker->check_httpd_conf({debug => 2}); - } - # Now configure the network. - my $dns = defined $anvil->data->{variables}{form}{config_step2}{dns}{value} ? [split/,/, $anvil->data->{variables}{form}{config_step2}{dns}{value}] : []; + my $dns = $anvil->data->{config}{dns} ? [split/,/, $anvil->data->{config}{dns}] : []; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dns => $dns }}); for (my $i = 0; $i < @{$dns}; $i++) { @@ -357,8 +363,8 @@ sub reconfigure_network $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "dns->[$i]" => $dns->[$i] }}); } - my $gateway = defined $anvil->data->{variables}{form}{config_step2}{gateway}{value} ? $anvil->data->{variables}{form}{config_step2}{gateway}{value} : ""; - my $gateway_interface = defined $anvil->data->{variables}{form}{config_step2}{gateway_interface}{value} ? $anvil->data->{variables}{form}{config_step2}{gateway_interface}{value} : ""; + my $gateway = $anvil->data->{config}{gateway}; + my $gateway_interface = $anvil->data->{config}{gateway_interface}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { gateway => $gateway, gateway_interface => $gateway_interface, @@ -384,7 +390,8 @@ sub reconfigure_network { my $ip_key = $network_type.$network_count."_ip"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_key => $ip_key }}); - if ((exists $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}) && ($anvil->data->{variables}{form}{config_step2}{$ip_key}{value} eq "dhcp")) + + if ((exists $anvil->data->{config}{$ip_key}) && ($anvil->data->{config}{$ip_key} eq "dhcp")) { $gateway_interface = $network_type.$network_count; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { gateway_interface => $gateway_interface }}); @@ -393,27 +400,6 @@ sub reconfigure_network } } } - - ### NOTE: Not disconnecting anymore, we'll reboot on changes. - # Disconnect from the database, as we're about to tear down our connection. -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0466"}); -# $anvil->Database->disconnect(); - -# # Close all open SSH connections -# foreach my $ssh_fh_key (sort {$a cmp $b} 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 => { ssh_fh => $ssh_fh }}); -# -# next if $ssh_fh !~ /^Net::OpenSSH/; -# $ssh_fh->disconnect(); -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "message_0009", variables => { target => $ssh_fh_key }}); -# -# # For good measure, blank both variables. -# $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = ""; -# $ssh_fh = ""; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }}); -# } # Before we continue, see if there's two interfaces pointing at the same NIC. If so, the node would # endlessly reboot. @@ -467,17 +453,19 @@ ORDER BY else { # Fail out! - my $variables = { - mac_address => $variable_value, - iface1 => $macs->{$variable_value}, - iface2 => $device, - }; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0376", variables => $variables}); $anvil->Job->update_progress({ progress => 100, message => "error_0376", - variables => $variables, job_status => "failed", + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + mac_address => $variable_value, + iface1 => $macs->{$variable_value}, + iface2 => $device, + }, }); $anvil->nice_exit({exit_code => 8}); } @@ -487,1107 +475,1818 @@ ORDER BY # We'll set this to '1' if we reconfigure the network $anvil->data->{sys}{reboot} = 0; + # Read the existing network data + $anvil->Network->collect_data({debug => 2, start => 1}); + # This will be set to '1' if we make a change. my $changes = 0; my $new_interfaces = []; - foreach my $network_type ("bcn", "sn", "mn", "ifn") + + my $network_type = $anvil->System->check_network_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + + # Configure the network using Network Manager + reconfigure_interfaces($anvil); + + ### NOTE: If we're not a striker, the update the job to say we're disconnecting to + ### reconfigure the network. + 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 ne "striker") { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); - - my $count = 0; - if ($network_type eq "bcn") { $count = $bcn_count; } - elsif ($network_type eq "sn") { $count = $sn_count; } - elsif ($network_type eq "ifn") { $count = $ifn_count; } - elsif ($network_type eq "mn") { $count = $mn_count; } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); - - next if not $count; - foreach my $network_count (1..$count) + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 50}), + message => "message_0415", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + }); + $anvil->Database->disconnect({debug => 2}); + } + + # These can brake the connection. + reconfigure_bonds($anvil); + reconfigure_bridges($anvil); + reconfigure_ip_addresses($anvil); + + # Reconnect! + if ($host_type ne "striker") + { + my $time_now = time; + my $wait_until = $time_now + 120; + my $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + time_now => $time_now, + wait_until => $wait_until, + }}); + while ($waiting) { - # If the user had the option to create a network but didn't, there will be no link1 - # mac to set. - my $this_network = $network_type.$network_count; - my $link1_key = $this_network."_link1_mac_to_set"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - this_network => $this_network, - link1_key => $link1_key, - }}); - - next if not exists $anvil->data->{variables}{form}{config_step2}{$link1_key}; - next if not $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}; - my $link2_key = $this_network."_link2_mac_to_set"; - my $subnet_mask_key = $this_network."_subnet_mask"; - my $ip_key = $this_network."_ip"; - my $bridge_key = $this_network."_create_bridge"; - my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}; - my $is_gateway = $this_network eq $gateway_interface ? 1 : 0; - my $link2_mac = defined $anvil->data->{variables}{form}{config_step2}{$link2_key}{value} ? $anvil->data->{variables}{form}{config_step2}{$link2_key}{value} : ""; - my $old_link1_iface = $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} ? $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} : ""; - my $old_link2_iface = defined $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface} ? $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface} : ""; - my $bridge = defined $anvil->data->{variables}{form}{config_step2}{$bridge_key}{value} ? $anvil->data->{variables}{form}{config_step2}{$bridge_key}{value} : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_key => $ip_key, - is_gateway => $is_gateway, - link1_mac => $link1_mac, - link2_key => $link2_key, - link2_mac => $link2_mac, - bridge_key => $bridge_key, - old_link1_iface => $old_link1_iface, - old_link2_iface => $old_link2_iface, - subnet_mask_key => $subnet_mask_key, - bridge => $bridge, - }}); + $anvil->refresh(); + $anvil->Database->connect({debug => 2}); - # Dig out the name that network manager knows the old interface(s) as. The - # 'old_link1_iface' is the name reported by 'ip', the 'DEVICE=xxx' value in the - # ifcfg-xxx file. - my $old_link1_nm_name = $old_link1_iface; - my $link1_nm_uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link1_iface}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - old_link1_nm_name => $old_link1_nm_name, - link1_nm_uuid => $link1_nm_uuid, - }}); - if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name})) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }}); + if ($anvil->data->{sys}{database}{connections}) { - $old_link1_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_nm_name => $old_link1_nm_name }}); + # We're back! + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); } - - # Is there a link 2? - my $old_link2_nm_name = ""; - if ($old_link2_iface) + else { - $old_link2_nm_name = $old_link2_iface; - my $link2_nm_uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_nm_name}; + # Sleep for a bit. + my $now_time = time; + my $time_left = $wait_until - $now_time; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - old_link2_nm_name => $old_link2_nm_name, - link2_nm_uuid => $link2_nm_uuid, + now_time => $now_time, + time_left => $time_left, }}); - if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name})) + if ($time_left > 0) { - $old_link2_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_nm_name => $old_link2_nm_name }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0829", variables => { time_left => $time_left }}); + sleep 5; + } + else + { + # Give up and reboot. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0169"}); + do_reboot($anvil); } } - - # Skip if this doesn't exist or isn't a valid IPv4 address. - if (not exists $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0176", variables => { ip_key => $ip_key }}); - next; - } - else + } + + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 75}), + message => "message_0416", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + }); + } + + # If any virtio bridges exist, remove it/them. + my $start = 0; + my ($bridges, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridges => $bridges, return_code => $return_code }}); + if ($return_code) + { + ### NOTE: We're doing a bunch of deletes, so to be safe we statically define the directory + ### here. + # Libvirtd isn't running, check the directory directly. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0478"}); + my $directory = "/etc/libvirt/qemu/networks/autostart"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); + + if (-d $directory) + { + # Delete all files. + local(*DIRECTORY); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "variables::form::config_step2::${ip_key}::value" => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value} }}); + next if $file eq "."; + next if $file eq ".."; + my $full_path = $directory."/".$file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + file => $file, + full_path => $full_path, + }}); + if (-l $full_path) + { + # It's a symlink, remove it. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0479", variables => { 'symlink' => $full_path }}); + unlink $full_path; + if (-l $full_path) + { + # It didn't work... + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 0, priority => "err", key => "error_0132", variables => { 'symlink' => $full_path }});; + } + } } - if (($anvil->data->{variables}{form}{config_step2}{$ip_key}{value}) && - ($anvil->data->{variables}{form}{config_step2}{$ip_key}{value} ne "dhcp") && - (not $anvil->Validate->ipv4({ip => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}}))) + closedir(DIRECTORY); + } + } + else + { + foreach my $line (split/\n/, $bridges) + { + $line = $anvil->Words->clean_spaces({string => $line}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^----------/) { - # Something was set, but it isn't valid. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0148", variables => { - network => $this_network, - ip => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}, - }}); + $start = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start => $start }}); next; } + next if not $start; + my $bridge = ($line =~ /(.*?)\s/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge => $bridge }}); + + $anvil->data->{virsh}{bridge}{$bridge} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "virsh::bridge::$bridge" => $anvil->data->{virsh}{bridge}{$bridge} }}); + } + + foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{virsh}{bridge}}) + { + # Destroy (stop) it. + my ($destroy, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$bridge}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { destroy => $destroy, return_code => $return_code }}); + + # Disable it from auto-start. + (my $disable, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-autostart ".$bridge." --disable"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disable => $disable, return_code => $return_code }}); - # The IP could be 'dhcp', we'll handle that in a bit. - my $ip_address = $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}; - my $subnet_mask = defined $anvil->data->{variables}{form}{config_step2}{$subnet_mask_key}{value} ? $anvil->data->{variables}{form}{config_step2}{$subnet_mask_key}{value} : ""; + # Undefine (delete) + (my $undefine, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$bridge}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { undefine => $undefine, return_code => $return_code }}); + } + } + + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + job_uuid => $anvil->data->{job}{uuid}, + }); + + return(0); +} + +sub reconfigure_bridges +{ + my ($anvil) = @_; + + my $local_host = $anvil->Get->short_host_name(); + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + bcn_count => $bcn_count, + ifn_count => $ifn_count, + type => $type, + }}); + + if ($type eq "striker") + { + # No bridges on strikers. + return(0); + } + + foreach my $network_type ("bcn", "ifn") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + my $count = 0; + if ($network_type eq "bcn") { $count = $bcn_count; } + elsif ($network_type eq "ifn") { $count = $ifn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + ### TODO: This is almost always going to be on the bond, but we need to handle + ### bridges on interfaces on DR hosts. + my $bridge_name = $network_type.$i."_bridge1"; + my $on_device = $network_type.$i."_bond1"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address => $ip_address, - subnet_mask => $subnet_mask, + bridge_name => $bridge_name, + on_device => $on_device, }}); - # Are we building bonded interfaces? - if ($anvil->Validate->mac({mac => $link2_mac})) + # Checking if the bridge exists and that it is on the requested device + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0400", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + bridge_name => $bridge_name, + on_device => $on_device, + }, + }); + + if (exists $anvil->data->{nmcli}{bridge}{$bridge_name}) { - # Yup! - my $say_network = ""; - my $say_interface = ""; - my $interface_prefix = ""; - my $say_defroute = $is_gateway ? "yes" : "no"; - if ($network_type eq "bcn") - { - $say_network = "Back-Channel Network ".$network_count; - $say_interface = "bcn".$network_count; - $interface_prefix = "BCN"; - } - elsif ($network_type eq "sn") - { - $say_network = "Storage Network ".$network_count; - $say_interface = "sn".$network_count; - $interface_prefix = "SN"; - } - elsif ($network_type eq "mn") - { - $say_network = "Migration Network ".$network_count; - $say_interface = "mn".$network_count; - $interface_prefix = "MN"; - } - elsif ($network_type eq "ifn") - { - $say_network = "Internet-Facing Network ".$network_count; - $say_interface = "ifn".$network_count; - $interface_prefix = "IFN"; - } - - # Gather variables - my $cidr = $ip_address eq "dhcp" ? "" : $anvil->Convert->cidr({subnet_mask => $subnet_mask}); - my $bridge_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bridge_1"; - my $bond_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bond_1"; - my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1"; - my $new_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_2"; - my $old_link1_file = $new_link1_file; - my $old_link2_file = $new_link2_file; - my $new_bridge_iface = $say_interface."_bridge1"; - my $new_bond_iface = $say_interface."_bond1"; - my $new_link1_iface = $say_interface."_link1"; - my $new_link2_iface = $say_interface."_link2"; - my $boot_proto = $ip_address eq "dhcp" ? "dhcp" : "none"; - my $link1_uuid = get_uuid_from_interface_file($anvil, $old_link1_file); - my $link2_uuid = get_uuid_from_interface_file($anvil, $old_link2_file); - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface})) - { - # This is the device name (ie: bcn1_link1, ens0, etc). If it doesn't - # exist, see if the new name exists already. - $old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); - if (not -f $old_link1_file) - { - # Does the new file already exist? - if (-f $new_link1_file) - { - # Set the old file to the new one. - $old_link1_file = $new_link1_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); - } - } - } - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) && ($anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface})) - { - $old_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_file => $old_link2_file }}); - if (not -f $old_link2_file) - { - # Does the new file already exist? - if (-f $new_link2_file) - { - # Set the old file to the new one. - $old_link2_file = $new_link2_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_file => $old_link2_file }}); - } - } - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - bond_file => $bond_file, - boot_proto => $boot_proto, - bridge_file => $bridge_file, - cidr => $cidr, - link1_uuid => $link1_uuid, - link2_uuid => $link2_uuid, - new_bond_iface => $new_bond_iface, - new_bridge_iface => $new_bridge_iface, - new_link1_file => $new_link1_file, - new_link1_iface => $new_link1_iface, - new_link2_file => $new_link2_file, - new_link2_iface => $new_link2_iface, - old_link1_file => $old_link1_file, - old_link2_file => $old_link2_file, - say_defroute => $say_defroute, - }}); - - ### NOTE: Bridges and bonds take a UUID, but it can be temperamental. It - ### works more reliably without defining it, so we don't. - # Are we building a bridge interface? - my $bridge_config = ""; - if ($bridge) + # The bridge exists. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0401", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => {}, + }); + } + else + { + # If there are ifcfg files for this bridge, move it. + my $network_type = $anvil->System->check_network_type({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") { - my $new_bridge1_nm_name = $interface_prefix." ".$network_count." - Bridge 1"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_bridge1_nm_name => $new_bridge1_nm_name }}); - - # Record that we need to start this. - push @{$new_interfaces}, $new_bridge1_nm_name; - - # Yup! - $bridge_config = "# $say_network - Bridge 1\n"; - $bridge_config .= "DEVICE=\"".$new_bridge_iface."\"\n"; - $bridge_config .= "NAME=\"".$new_bridge1_nm_name."\"\n"; - $bridge_config .= "TYPE=\"Bridge\"\n"; - $bridge_config .= "STP=\"yes\"\n"; - $bridge_config .= "BRIDGING_OPTS=\"priority=32768\"\n"; - $bridge_config .= "PROXY_METHOD=\"none\"\n"; - $bridge_config .= "BROWSER_ONLY=\"no\"\n"; - $bridge_config .= "IPV4_FAILURE_FATAL=\"no\"\n"; - $bridge_config .= "IPV6INIT=\"no\"\n"; - $bridge_config .= "BOOTPROTO=\"".$boot_proto."\"\n"; - - # If the IP is NOT 'dhcp', set it. - if ($ip_address ne "dhcp") + my $ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ifcfg_file => $ifcfg_file }}); + if (-f $ifcfg_file) { - $bridge_config .= "IPADDR=\"".$ip_address."\"\n"; - $bridge_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n"; - - # If this is the default gateway, add that info. - if ($is_gateway) - { - $bridge_config .= "GATEWAY=\"".$gateway."\"\n"; - for (my $i = 0; $i < @{$dns}; $i++) - { - $bridge_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; - } - } + # It exists, move it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0417", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $ifcfg_file }, + }); + $anvil->Storage->backup({debug => 2, file => $ifcfg_file}); + unlink $ifcfg_file; } - $bridge_config .= "DEFROUTE=\"".$say_defroute."\"\n"; - $bridge_config .= "ONBOOT=\"yes\"\n"; - $bridge_config .= "ZONE=\"".uc($say_interface)."\"\n"; } - # If this is DHCP, but there is a bridge, the bond's boot proto in 'none'. - $boot_proto = "none" if $bridge; - - # Make the rest of the network names. - my $new_bond1_nm_name = $interface_prefix." ".$network_count." - Bond 1"; - my $new_link1_nm_name = $interface_prefix." ".$network_count." - Link 1"; - my $new_link2_nm_name = $interface_prefix." ".$network_count." - Link 2"; + # Create the bridge. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bridge con-name ".$bridge_name." ifname ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - new_bond1_nm_name => $new_bond1_nm_name, - new_link1_nm_name => $new_link1_nm_name, - new_link2_nm_name => $new_link2_nm_name, + output => $output, + return_code => $return_code, }}); - # Record that we need to start this. - push @{$new_interfaces}, $new_bond1_nm_name; - push @{$new_interfaces}, $new_link1_nm_name; - push @{$new_interfaces}, $new_link2_nm_name; - - # Build the Bond config. - my $bond_config = "# $say_network - Bond 1\n"; - $bond_config .= "DEVICE=\"".$new_bond_iface."\"\n"; - $bond_config .= "NAME=\"".$new_bond1_nm_name."\"\n"; - $bond_config .= "TYPE=\"Bond\"\n"; - $bond_config .= "BONDING_OPTS=\"downdelay=0 miimon=100 mode=active-backup primary=".$say_interface."_link1 updelay=120000\"\n"; - $bond_config .= "BONDING_MASTER=\"yes\"\n"; - $bond_config .= "ONBOOT=\"yes\"\n"; - - # Is this connected to a bridge? - if ($bridge) - { - $bond_config .= "BRIDGE=\"".$new_bridge_iface."\"\n"; - } - else + if ($return_code) { - # Does this bond have an IP? - # If the IP is NOT 'dhcp', set it. - $bond_config .= "BOOTPROTO=\"".$boot_proto."\"\n"; - if ($ip_address ne "dhcp") - { - $bond_config .= "IPADDR=\"".$ip_address."\"\n"; - $bond_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n"; - - # If this is the default gateway, add that info. - if ($is_gateway) - { - $bond_config .= "GATEWAY=\"".$gateway."\"\n"; - for (my $i = 0; $i < @{$dns}; $i++) - { - $bond_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; - } - } - } - $bond_config .= "DEFROUTE=\"".$say_defroute."\"\n"; + # Failed to add the bridge + $anvil->Job->update_progress({ + progress => 100, + message => "error_0485", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + bridge_name => $bridge_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); } - # Rest of the config - $bond_config .= "ZONE=\"".uc($say_interface)."\"\n"; - - # Now build the links - my $link1_config = "# $say_network - Link 1\n"; - $link1_config .= "HWADDR=\"".uc($link1_mac)."\"\n"; - $link1_config .= "UUID=\"".$link1_uuid."\"\n"; - $link1_config .= "NAME=\"".$new_link1_nm_name."\"\n"; - $link1_config .= "DEVICE=\"".$new_link1_iface."\"\n"; - $link1_config .= "TYPE=\"Ethernet\"\n"; - $link1_config .= "BOOTPROTO=\"none\"\n"; - $link1_config .= "IPV6INIT=\"no\"\n"; - $link1_config .= "ONBOOT=\"yes\"\n"; - $link1_config .= "USERCTL=\"no\"\n"; -# $link1_config .= "MTU=\"1500\"\n"; # TODO: Make the MTU user-adjustable - $link1_config .= "NM_CONTROLLED=\"yes\"\n"; - $link1_config .= "SLAVE=\"yes\"\n"; - $link1_config .= "MASTER=\"".$say_interface."_bond1\"\n"; - $link1_config .= "ZONE=\"".uc($say_interface)."\"\n"; - - my $link2_config = "# $say_network - Link 2\n"; - $link2_config .= "HWADDR=\"".uc($link2_mac)."\"\n"; - $link2_config .= "UUID=\"".$link2_uuid."\"\n"; - $link2_config .= "NAME=\"".$new_link2_nm_name."\"\n"; - $link2_config .= "DEVICE=\"".$new_link2_iface."\"\n"; - $link2_config .= "TYPE=\"Ethernet\"\n"; - $link2_config .= "BOOTPROTO=\"none\"\n"; - $link2_config .= "IPV6INIT=\"no\"\n"; - $link2_config .= "ONBOOT=\"yes\"\n"; - $link2_config .= "USERCTL=\"no\"\n"; -# $link2_config .= "MTU=\"1500\"\n"; # TODO: Make the MTU user-adjustable - $link2_config .= "NM_CONTROLLED=\"yes\"\n"; - $link2_config .= "SLAVE=\"yes\"\n"; - $link2_config .= "MASTER=\"".$say_interface."_bond1\"\n"; - $link2_config .= "ZONE=\"".uc($say_interface)."\"\n"; - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - bridge_config => $bridge_config, - bond_config => $bond_config, - link1_config => $link1_config, - link2_config => $link2_config, - }}); - # Decide if we need to reboot. - if (($old_link1_file ne $new_link1_file) && (-e $new_link1_file)) - { - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - if (($old_link2_file ne $new_link2_file) && (-e $new_link2_file)) + my $bridge_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); + + if ($bridge_uuid) { - $changes = 1; - $anvil->data->{sys}{reboot} = 1; + # Disabling DHCP on the new bridge + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $bridge_name, + device_uuid => $bridge_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bridge_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bridge_uuid, variable => "ipv6.method", value => "disabled"}); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, + output => $output, + return_code => $return_code, }}); } - ### Write out the new configs, if needed - # Are we writing a bridge config? - if ($bridge) + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + + # Checking that the device is connected to this bridge + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0404", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { on_device => $on_device }, + }); + my $bridge_uuid = $anvil->data->{nmcli}{bridge}{$bridge_name}{uuid}; + my $on_device_uuid = $anvil->data->{nmcli}{device}{$on_device}{uuid} // ""; + my $on_device_parent = $anvil->data->{nmcli}{uuid}{$on_device_uuid}{'connection.master'} // ""; + my $on_device_child_type = $anvil->data->{nmcli}{uuid}{$on_device_uuid}{'connection.slave-type'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_uuid => $bridge_uuid, + on_device_uuid => $on_device_uuid, + on_device_parent => $on_device_parent, + on_device_child_type => $on_device_child_type, + }}); + + if ($on_device_parent) + { + if ($on_device_parent eq $bridge_name) { - # If the file already exists, see if it changed. - my $update = 1; - if (-e $bridge_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $bridge_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$bridge_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $bridge_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); - } - } - - if ($update) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - bridge_file => $bridge_file, - bridge_config => $bridge_config, - }}); - $anvil->Storage->write_file({ - file => $bridge_file, - body => $bridge_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } + # The device is connected to the bridge already. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0405", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + next; } - - # Bond, Link 1 and Link 2 - my $update_bond = 1; - if (-f $bond_file) + else { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $bond_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$bond_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $bond_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else + # The device is on another bridge, moving it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0406", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { on_device_parent => $on_device_parent }, + }); + } + } + else + { + # The device is not on this bridge, connecting it + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0407", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { on_device_parent => $on_device_parent }, + }); + } + + # Disabling DHCP on the device before connecting it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $on_device, + device_uuid => $on_device_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $on_device_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $on_device_uuid, variable => "ipv6.method", value => "disabled"}); + + # Connect it now. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0409", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." master ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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, + }}); + + if ($return_code) + { + # Failed to connect the device to the bridge. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0486", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + on_device => $on_device, + bridge_name => $bridge_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # Reset the device. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $on_device, + device_uuid => $on_device_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $on_device_uuid}); + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } + + return(0); +} + +sub reconfigure_bonds +{ + my ($anvil) = @_; + + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + prefix => $prefix, + sequence => $sequence, + domain => $domain, + type => $type, + }}); + foreach my $network_type ("bcn", "sn", "mn", "ifn") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + my $count = 0; + if ($network_type eq "bcn") { $count = $bcn_count; } + elsif ($network_type eq "sn") { $count = $sn_count; } + elsif ($network_type eq "ifn") { $count = $ifn_count; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + my $bond_name = $network_type.$i."_bond1"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_name => $bond_name }}); + + # Skip if this isn't marked to become a bond. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); + if (not $anvil->data->{config}{$bond_name}) + { + # No bond on this network. + next; + } + + my $link_nm_uuids = []; + my $link1_name = $network_type.$i."_link1"; + my $link1_mac_key = $network_type.$i."_link1_mac_to_set"; + my $link1_mac = $anvil->data->{config}{$link1_mac_key}; + my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link1_mac}{uuid}; + + my $link2_name = $network_type.$i."_link2"; + my $link2_mac_key = $network_type.$i."_link2_mac_to_set"; + my $link2_mac = $anvil->data->{config}{$link2_mac_key}; + my $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link2_mac}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + link1_name => $link1_name, + link1_mac_key => $link1_mac_key, + link1_mac => $link1_mac, + link1_nm_uuid => $link1_nm_uuid, + link2_name => $link2_name, + link2_mac_key => $link2_mac_key, + link2_mac => $link2_mac, + link2_nm_uuid => $link2_nm_uuid, + }}); + + # Push the two nm_uuids into the array for later checking/adding to the bond. + push @{$link_nm_uuids}, $link1_nm_uuid; + push @{$link_nm_uuids}, $link2_nm_uuid; + + # Check if the bond exists or not. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0390", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { bond_name => $bond_name }, + }); + if (exists $anvil->data->{nmcli}{bond}{$bond_name}) + { + # It does. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0391", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { nm_uuid => $anvil->data->{nmcli}{bond}{$bond_name}{uuid} }, + }); + } + else + { + # It doesn't, create it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0392", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + bond_name => $bond_name, + link1_name => $link1_name, + link1_mac => $link1_mac, + link1_nm_uuid => $link1_nm_uuid, + link2_name => $link2_name, + link2_mac => $link2_mac, + link2_nm_uuid => $link2_nm_uuid, + }, + }); + + # If there are ifcfg files for this bond, move it. + my $network_type = $anvil->System->check_network_type({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") + { + my $ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$bond_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ifcfg_file => $ifcfg_file }}); + if (-f $ifcfg_file) { - # No need to update - $update_bond = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_bond => $update_bond }}); + # It exists, move it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0417", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $ifcfg_file }, + }); + $anvil->Storage->backup({debug => 2, file => $ifcfg_file}); + unlink $ifcfg_file; } } - if ($update_bond) + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$link1_name."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, + }}); + + if ($return_code) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - bond_file => $bond_file, - bond_config => $bond_config, - }}); - $anvil->Storage->write_file({ - file => $bond_file, - body => $bond_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 + # Adding the bond failed. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0483", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + bond_name => $bond_name, + return_code => $return_code, + output => $output, + }, }); + $anvil->nice_exit({exit_code => 1}); } - # Link 1 - my $update_link1 = 1; - if (-f $new_link1_file) + my $bond_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); + + if ($bond_uuid) { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); + # Disabling DHCP on the new bond device + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $bond_name, + device_uuid => $bond_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bond_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bond_uuid, variable => "ipv6.method", value => "disabled"}); - my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link1_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link1 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); - } + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bond_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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, + }}); } - if ($update_link1) + + # Done! Rescanning the network config + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + }); + $anvil->Network->collect_data({debug => 2}); + } + + # Now add the interfaces, disabling their ipv4.method first. + my $uuid_count = @{$link_nm_uuids}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid_count => $uuid_count }}); + foreach my $nm_uuid (@{$link_nm_uuids}) + { + my $link_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{name}; + my $link_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + my $mac_address = $anvil->data->{nmcli}{uuid}{$nm_uuid}{mac_address}; + my $parent_bond_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.master'}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:nm_uuid' => $nm_uuid, + 's2:link_name' => $link_name, + 's3:link_device' => $link_device, + 's4:mac_address' => $mac_address, + 's5:parent_bond_name' => $parent_bond_name, + }}); + + if ($parent_bond_name eq "--") { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link1_file => $new_link1_file, - link1_config => $link1_config, - }}); - $anvil->Storage->write_file({ - file => $new_link1_file, - body => $link1_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); + $parent_bond_name = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { parent_bond_name => $parent_bond_name }}); } - # Link 2 - my $update_link2 = 1; - if (-f $new_link2_file) + if ($parent_bond_name) { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link2_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link2_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) + if ($parent_bond_name eq $bond_name) { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link2_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + # Already a member of the bond. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0395", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_device ? $link_device : $link_name, + nm_uuid => $nm_uuid, + }, + }); + next; } else { - # No need to update - $update_link2 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link2 => $update_link2 }}); + # The interface is a member of another bond, switching it to this bond.\n"; + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0396", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_device ? $link_device : $link_name, + nm_uuid => $nm_uuid, + old_bond => $parent_bond_name, + }, + }); } } - if ($update_link2) + else { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link2_file => $new_link2_file, - link2_config => $link2_config, - }}); - $anvil->Storage->write_file({ - file => $new_link2_file, - body => $link2_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 + # The interface needs to be connected to the bond. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0397", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_device ? $link_device : $link_name, + nm_uuid => $nm_uuid, + }, }); } - # Backup the old config files, if needed. - if (-e $old_link1_file) + # Disabling DHCP on the interface + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $link_device ? $link_device : $link_name, + device_uuid => $nm_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $nm_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $nm_uuid, variable => "ipv6.method", value => "disabled"}); + + # Connecting the interface to the bond + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0399", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_device ? $link_device : $link_name, + bond_name => $bond_name, + }, + }); + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.master ".$bond_name." connection.slave-type bond"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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, + }}); + + if ($return_code) { - $anvil->Storage->backup({file => $old_link1_file}); + # Adding the link failed. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0484", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + link_name => $link_device ? $link_device : $link_name, + bond_name => $bond_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); } - if (-e $old_link2_file) + + # Reset the interface. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $link_device ? $link_device : $link_name, + device_uuid => $nm_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $nm_uuid}); + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } + } + + return(0); +} + +sub reconfigure_ip_addresses +{ + my ($anvil) = @_; + + my $local_host = $anvil->Get->short_host_name(); + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $dns = $anvil->data->{config}{dns}; + my $gateway = $anvil->data->{config}{gateway}; + my $gw_interface = $anvil->data->{config}{gateway_interface}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + bcn_count => $bcn_count, + ifn_count => $ifn_count, + sn_count => $sn_count, + mn_count => $mn_count, + dns => $dns, + gateway => $gateway, + gw_interface => $gw_interface, + }}); + foreach my $network_type ("bcn", "sn", "mn", "ifn") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + my $count = 0; + if ($network_type eq "bcn") { $count = $bcn_count; } + elsif ($network_type eq "sn") { $count = $sn_count; } + elsif ($network_type eq "ifn") { $count = $ifn_count; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + my $ip_key = $network_type.$i."_ip"; + my $subnet_key = $network_type.$i."_subnet_mask"; + my $link1_name = $network_type.$i."_link1"; + my $link2_name = $network_type.$i."_link2"; + my $bond_name = $network_type.$i."_bond1"; + my $bridge_name = $network_type.$i."_bridge1"; + my $is_gateway = $gw_interface eq $network_type.$i ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_key => $ip_key, + subnet_key => $subnet_key, + link1_name => $link1_name, + link2_name => $link2_name, + bond_name => $bond_name, + bridge_name => $bridge_name, + is_gateway => $is_gateway, + }}); + + if ((not exists $anvil->data->{config}{$ip_key}) or (not $anvil->data->{config}{$ip_key})) + { + # No IP for this network + next; + } + + my $ip_address = $anvil->data->{config}{$ip_key}; + my $subnet_mask = $anvil->data->{config}{$subnet_key}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }}); + + if (($subnet_mask !~ /^\d+$/) or ($subnet_mask < 1) or ($subnet_mask > 32)) + { + # Convert to CIDR + my $cidr = $anvil->Convert->cidr({subnet_mask => $subnet_mask}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cidr => $cidr }}); + if (not $cidr) { - $anvil->Storage->backup({file => $old_link2_file}); + # The subnet_mask is not valid. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0487", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { subnet_mask => $subnet_mask }, + }); + $anvil->nice_exit({exit_code => 1}); } - # If the NICs names have changed, rename them now. - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && - ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && - ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} ne $new_link1_iface)) + $subnet_mask = $cidr; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subnet_mask => $subnet_mask }}); + } + + # What device are we assigning the IP address to? + my $on_device = ""; + my $on_device_uuid = ""; + if ((exists $anvil->data->{nmcli}{bridge}{$bridge_name}) && ($anvil->data->{nmcli}{bridge}{$bridge_name}{uuid})) + { + $on_device = $bridge_name; + $on_device_uuid = $anvil->data->{nmcli}{bridge}{$bridge_name}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + on_device => $on_device, + on_device_uuid => $on_device_uuid, + }}); + } + elsif ((exists $anvil->data->{nmcli}{bond}{$bond_name}) && ($anvil->data->{nmcli}{bond}{$bond_name}{uuid})) + { + $on_device = $bond_name; + $on_device_uuid = $anvil->data->{nmcli}{bond}{$bond_name}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + on_device => $on_device, + on_device_uuid => $on_device_uuid, + }}); + } + elsif ((exists $anvil->data->{nmcli}{interface}{$link1_name}) && ($anvil->data->{nmcli}{interface}{$link1_name}{uuid})) + { + $on_device = $link1_name; + $on_device_uuid = $anvil->data->{nmcli}{interface}{$link1_name}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + on_device => $on_device, + on_device_uuid => $on_device_uuid, + }}); + } + else + { + # Failed to find a device to assign this IP address to. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0488", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { + network => $network_type.$i, + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # Check to see if the IP address is assigned yet. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0393", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + device => $on_device, + }, + }); + my $clear_ip_from = ""; + if (exists $anvil->data->{nmcli}{ipv4}{$ip_address}) + { + my $ip_uuid = $anvil->data->{nmcli}{ipv4}{$ip_address}{on_uuid}; + my $current_device = $anvil->data->{nmcli}{uuid}{$ip_uuid}{device}; + my $ip_sequence = $anvil->data->{nmcli}{ipv4}{$ip_address}{sequence}; + my $current_subnet_mask = $anvil->data->{nmcli}{uuid}{$ip_uuid}{ipv4}{ip}{$ip_sequence}{subnet_mask}; + my $current_gateway = $anvil->data->{nmcli}{uuid}{$ip_uuid}{ipv4}{gateway}; + my $current_dns = $anvil->data->{nmcli}{uuid}{$ip_uuid}{ipv4}{dns}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ip_uuid' => $ip_uuid, + 's2:current_device' => $current_device, + 's3:ip_sequence' => $ip_sequence, + 's4:current_subnet_mask' => $current_subnet_mask, + 's5:current_gateway' => $current_gateway, + 's6:current_dns' => $current_dns, + }}); + if (not $ip_uuid) { - rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface); - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + # The IP exists, but wasn't translate to a network manager UUID. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0489", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { ip_address => $ip_address }, + }); + $anvil->nice_exit({exit_code => 1}); } - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) && - ($anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) && - ($anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface} ne $new_link2_iface)) + + # The IP exists, checking if it needs to be updated. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0398", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => {}, + }); + if ($on_device ne $current_device) { - rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}, $new_link2_iface); - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + # The IP address is on another device, we'll move it + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0402", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { device => $current_device }, + }); + $clear_ip_from = $current_device; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_ip_from => $clear_ip_from }}); } - - # Remove the old link if it was different, of down and up it if the same. - if ($old_link1_iface ne $new_link1_iface) + elsif ($subnet_mask ne $current_subnet_mask) { - # Delete the old interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0461", variables => { interface => $old_link1_nm_name }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); - - if (-e $old_link1_file) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0589", variables => { file => $old_link1_file }}); - unlink $old_link1_file; - } - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + # The current subnet mask is different, will update. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0410", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { current_subnet_mask => $current_subnet_mask }, + }); } - elsif ($update_link1) + elsif ($gateway ne $current_gateway) { - # Down the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link1_nm_name }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# $changes = 1; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + # The current gateway is different, will update. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0411", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { current_gateway => $current_gateway }, + }); + } + elsif ($dns ne $current_dns) + { + # The current DNS is different, will update. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0412", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { current_dns => $current_dns }, + }); + } + else + { + # No update is needed. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0413", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + next; } + } + else + { + # The IP address needs to be assigned. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0414", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + } + + if ($clear_ip_from) + { + # Clear the IP off the old device + my $old_uuid = $anvil->data->{nmcli}{device}{$clear_ip_from}{uuid}; + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $clear_ip_from, + device_uuid => $old_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $old_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $old_uuid, variable => "ipv6.method", value => "disabled"}); - # Shut down (and rename) Link 2 - if ($old_link2_iface ne $new_link2_iface) + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $clear_ip_from, + device_uuid => $old_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $old_uuid}); + } + + # Now assign the IP. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." ipv4.method manual ipv4.addresses ".$ip_address."/".$subnet_mask; + if ($is_gateway) + { + if ($gateway) + { + $shell_call .= " ipv4.gateway ".$gateway; + } + if ($dns) + { + $shell_call .= " ipv4.dns ".$dns; + } + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + 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, + }}); + + # Restart the interface + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $on_device, + device_uuid => $on_device_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $on_device_uuid}); + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } + + return(0); +} + +sub reconfigure_interfaces +{ + my ($anvil) = @_; + + # Before we start, we need to make sure all interfaces are up. Otherwise, there's no way to match a + # network manager device to the ip addr name or the biosdevname. + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + ### TODO: Left off here... any devices that are down, set: + ### nmcli connection modify ipv4.method manual ipv4.addresses 169.0.0.x/8' (x == Wired connection x) + my $connection_id = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.id'} // ""; + my $general_ip_iface = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.IP-IFACE'} // ""; + $general_ip_iface = "" if $general_ip_iface eq "--"; + my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'match.interface-name'} // ""; + my $active = $anvil->data->{nmcli}{uuid}{$uuid}{active}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:uuid' => $uuid, + 's2:connection_id' => $connection_id, + 's3:general_ip_iface' => $general_ip_iface, + 's4:device_type' => $device_type, + 's5:match_interface_name' => $match_interface_name, + 's6:active' => $active, + }}); + + # Try activating it. + if ((not $general_ip_iface) && (not $active)) + { + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } + + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + prefix => $prefix, + sequence => $sequence, + domain => $domain, + type => $type, + }}); + foreach my $network_type ("bcn", "sn", "mn", "ifn") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + my $count = 0; + if ($network_type eq "bcn") { $count = $bcn_count; } + elsif ($network_type eq "sn") { $count = $sn_count; } + elsif ($network_type eq "ifn") { $count = $ifn_count; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + my $link1_mac_key = $network_type.$i."_link1_mac_to_set"; + my $link2_mac_key = $network_type.$i."_link2_mac_to_set"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + i => $i, + link1_mac_key => $link1_mac_key, + link2_mac_key => $link2_mac_key, + }}); + + # This will get set to '1' if there's a link2 + my $bond_name = $network_type.$i."_bond1"; + $anvil->data->{config}{$bond_name} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); + + # If the user had the option to create a network but didn't, there will be no link1 + # mac to set. + next if not exists $anvil->data->{config}{$link1_mac_key}; + next if not $anvil->data->{config}{$link1_mac_key}; + + my $wanted_link1_name = $network_type.$i."_link1"; + my $wanted_link1_mac = $anvil->data->{config}{$link1_mac_key}; + my $wanted_link2_name = $network_type.$i."_link2"; + my $wanted_link2_mac = exists $anvil->data->{config}{$link2_mac_key} ? $anvil->data->{config}{$link2_mac_key} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + wanted_link1_name => $wanted_link1_name, + wanted_link1_mac => $wanted_link1_mac, + wanted_link2_name => $wanted_link2_name, + wanted_link2_mac => $wanted_link2_mac, + }}); + + # Loop through our interfaces to see if we can find this interface. + my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link1_mac}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_nm_uuid => $link1_nm_uuid }}); + + # Are the link(s) already configured? + my $configure_link1 = 0; + my $configure_link2 = 0; + + # Get the Network Manager UUIDs. + if ($link1_nm_uuid) + { + my $found = 0; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$link1_nm_uuid}{'match.interface-name'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + foreach my $interface (split/,/, $match_interface_name) { - # Delete the old interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0461", variables => { interface => $old_link2_nm_name }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link2_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); - - if (-e $old_link2_file) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }}); + if ($interface eq $wanted_link1_name) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0589", variables => { file => $old_link2_file }}); - unlink $old_link2_file; + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + last; } - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); } - elsif ($update_link1) + if (not $found) { - # Down the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link2_nm_name }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link2_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# $changes = 1; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + $configure_link1 = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); } } - elsif ((exists $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}) && ($anvil->Validate->mac({mac => $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}}))) + else { - ### NOTE: This only applies when configuring Striker dashboards. They can't - ### be 'dhcp', either, so no checks are made for those cases. Likewise, - ### bridges are not used. - # Single interface, set it up - my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_mac => $link1_mac }}); - - my $say_network = ""; - my $say_interface = ""; - my $interface_prefix = ""; - if ($network_type eq "bcn") - { - $say_network = "Back-Channel Network ".$network_count; - $say_interface = "bcn".$network_count; - $interface_prefix = "BCN"; - } - elsif ($network_type eq "sn") - { - $say_network = "Storage Network ".$network_count; - $say_interface = "sn".$network_count; - $interface_prefix = "SN"; - } - elsif ($network_type eq "ifn") - { - $say_network = "Internet-Facing Network ".$network_count; - $say_interface = "ifn".$network_count; - $interface_prefix = "IFN"; - } - elsif ($network_type eq "mn") - { - $say_network = "Migration Network ".$network_count; - $say_interface = "mn".$network_count; - $interface_prefix = "MN"; - } - my $say_defroute = $is_gateway ? "yes" : "no"; - my $cidr = $anvil->Convert->cidr({subnet_mask => $subnet_mask}); - my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1"; - my $old_link1_file = $new_link1_file; - my $new_link1_iface = $say_interface."_link1"; - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface})) + # We're dead. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0480", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + mac_address => $wanted_link1_mac, + interface_name => $wanted_link1_name, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); + if ($configure_link1) + { + rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); + } + + my $link2_nm_uuid = ""; + if ($wanted_link2_mac) + { + $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link2_mac}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link2_nm_uuid => $link2_nm_uuid }}); + if ($link2_nm_uuid) { - $old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}; - if (not -f $old_link1_file) + my $found = 0; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$link2_nm_uuid}{'match.interface-name'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + foreach my $interface (split/,/, $match_interface_name) { - # Does the new file already exist? - if (-f $new_link1_file) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }}); + if ($interface eq $wanted_link2_name) { - # Set the old file to the new one. - $old_link1_file = $new_link1_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + last; } } - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - cidr => $cidr, - new_link1_file => $new_link1_file, - new_link1_iface => $new_link1_iface, - old_link1_file => $old_link1_file, - say_defroute => $say_defroute, - }}); - - my $new_link1_nm_name = $interface_prefix." ".$network_count." - Link 1"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_link1_nm_name => $new_link1_nm_name }}); - push @{$new_interfaces}, $new_link1_nm_name; - - # Gather (or create) UUIDs - my $link1_uuid = get_uuid_from_interface_file($anvil, $old_link1_file); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_uuid => $link1_uuid }}); - - my $link1_config = "# $say_network - Link 1\n"; - $link1_config .= "HWADDR=\"".uc($link1_mac)."\"\n"; - $link1_config .= "UUID=\"".$link1_uuid."\"\n"; - $link1_config .= "NAME=\"".$new_link1_nm_name."\"\n"; - $link1_config .= "DEVICE=\"".$new_link1_iface."\"\n"; - $link1_config .= "TYPE=\"Ethernet\"\n"; - $link1_config .= "BOOTPROTO=\"none\"\n"; - $link1_config .= "IPV6INIT=\"no\"\n"; - $link1_config .= "ONBOOT=\"yes\"\n"; - $link1_config .= "IPADDR=\"".$ip_address."\"\n"; - $link1_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n"; - if ($is_gateway) - { - $link1_config .= "GATEWAY=\"".$gateway."\"\n"; - for (my $i = 0; $i < @{$dns}; $i++) - { - $link1_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; - } - } - $link1_config .= "DEFROUTE=\"".$say_defroute."\"\n"; - $link1_config .= "USERCTL=\"no\"\n"; -# $link1_config .= "MTU=\"1500\"\n"; # TODO: Make the MTU user-adjustable - $link1_config .= "NM_CONTROLLED=\"yes\"\n"; - $link1_config .= "ZONE=\"".uc($say_interface)."\""; - - # Link 1 - my $update_link1 = 1; - if (-f $new_link1_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link1_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else + if (not $found) { - # No need to update - $update_link1 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); + $configure_link2 = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); } } - if ($update_link1) + else { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link1_file => $new_link1_file, - link1_config => $link1_config, - }}); - $anvil->Storage->write_file({ - file => $new_link1_file, - body => $link1_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 + $anvil->Job->update_progress({ + progress => 100, + message => "error_0480", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + job_status => "failed", + variables => { + mac_address => $wanted_link2_mac, + interface_name => $wanted_link2_name, + }, }); + $anvil->nice_exit({exit_code => 1}); } - # Backup the existing link1 file, if it exists and is different. - if (-e $old_link1_file) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link2 => $configure_link2 }}); + if ($configure_link2) { - $anvil->Storage->backup({file => $old_link1_file}); + rename_interface($anvil, $wanted_link2_name, $link2_nm_uuid); } - # If the name differs from old, delete the old interface. - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && - ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && - ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} ne $new_link1_iface)) - { - # Delete the old interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0461", variables => { interface => $old_link1_nm_name }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# $anvil->System->call({debug => 2, shell_call => $shell_call}); -# -# rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) - { - # Down the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link1_nm_name }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# $anvil->System->call({debug => 2, shell_call => $shell_call}); -# -# $changes = 1; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - } - else - { - # Doesn't exist, skip. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0149", variables => { network => $this_network }}); - next; + # There's a second interface, so create a bond. + $anvil->data->{config}{$bond_name} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); } } } - # If we should reset, do so now. - if ($anvil->data->{sys}{reboot}) + # There is no way (that we've found) to get the network interface ames to be updated without a reboot. + if ($anvil->data->{sys}{reboot_needed}) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); do_reboot($anvil); } - if ($changes) - { - # In an attempt to make network changes more reliable, we'll just reboot. This shouldn't - # actually be hit anymore as any change should have triggered the reboot above. - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); - do_reboot($anvil); - -# # Re-read the config -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0463"}); -# -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection reload"; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# # Give a couple seconds for the reload -# sleep 2; -# -# # Now check the bonds -# my $repaired = $anvil->Network->check_network({heal => "all"}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { repaired => $repaired }}); -# if ($repaired) -# { -# # It can take a bit for the bonds to allow traffic, so sleep for a bit. -# sleep 30; -# } - } + return(0); +} + +sub rename_interface +{ + my ($anvil, $wanted_link_name, $nm_uuid) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + wanted_link_name => $wanted_link_name, + nm_uuid => $nm_uuid, + }}); - # Wait for a DB connection. We'll wait up to 130 seconds, as sometimes it takes a while for the network - # to start routing traffic. -# my $wait_until = time + 130; -# until ($anvil->data->{sys}{database}{connections}) -# { -# $anvil->refresh(); -# $anvil->Database->connect(); -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0132"}); -# if (not $anvil->data->{sys}{database}{connections}) -# { -# if (time > $wait_until) -# { -# # Failed to reconnect, reboot. Hopefully the network comes up cleanly -# # next time.. -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0107"}); -# do_reboot($anvil); -# } -# -# # No databases, sleep and then try again. -# sleep 10; -# } -# } + my $old_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + my $name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.id'}; + my $mac_address = $anvil->data->{nmcli}{uuid}{$nm_uuid}{mac_address}; + my $type = $anvil->data->{nmcli}{uuid}{$nm_uuid}{type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:wanted_link_name' => $wanted_link_name, + 's2:nm_uuid' => $nm_uuid, + 's3:old_device' => $old_device, + 's4:name' => $name, + 's5:mac_address' => $mac_address, + 's6:type' => $type, + }}); - # We're half-way there. + # Tell the user what we're about to rename $anvil->Job->update_progress({ - progress => 50, - job_uuid => $anvil->data->{job}{uuid}, + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0383", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { + mac_address => $mac_address, + old_device => $old_device, + old_name => $name, + new_name => $wanted_link_name, + nm_uuid => $nm_uuid, + }, }); - # If any virtio bridges exist, remove it/them. - my $start = 0; - my ($bridges, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridges => $bridges, return_code => $return_code }}); - if ($return_code) + # If there are ifcfg files for this device, move them. + my $network_type = $anvil->System->check_network_type({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") { - ### NOTE: We're doing a bunch of deletes, so to be safe we statically define the directory - ### here. - # Libvirtd isn't running, check the directory directly. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0478"}); - my $directory = "/etc/libvirt/qemu/networks/autostart"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); - - if (-d $directory) + my $old_ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$old_device; + my $new_ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$wanted_link_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_ifcfg_file => $old_ifcfg_file, + new_ifcfg_file => $new_ifcfg_file, + }}); + foreach my $file ($old_ifcfg_file, $new_ifcfg_file) { - # Delete all files. - local(*DIRECTORY); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); + if (-f $file) { - next if $file eq "."; - next if $file eq ".."; - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - file => $file, - full_path => $full_path, - }}); - if (-l $full_path) - { - # It's a symlink, remove it. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0479", variables => { 'symlink' => $full_path }}); - unlink $full_path; - if (-l $full_path) - { - # It didn't work... - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 0, priority => "err", key => "error_0132", variables => { 'symlink' => $full_path }});; - } - } + # It exists, move it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0417", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $file }, + }); + $anvil->Storage->backup({debug => 2, file => $file}); + unlink $file; } - closedir(DIRECTORY); } } - else + + # Read persistent-net and see if it needs to be updated. + my $new_persistent_net = ""; + my $old_persistent_net = ""; + if (-e $anvil->data->{path}{configs}{'persistent-net'}) { - foreach my $line (split/\n/, $bridges) + $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); + } + foreach my $line (split/\n/, $old_persistent_net) + { + # If this MAC or device name exists already, delete the line. + if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_link_name"/)) { - $line = $anvil->Words->clean_spaces({string => $line}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^----------/) - { - $start = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start => $start }}); - next; - } - next if not $start; - my $bridge = ($line =~ /(.*?)\s/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge => $bridge }}); + next; + } + $new_persistent_net .= $line."\n"; + } + $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_link_name."\"\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); + + my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + + # Write the new file. + if ($difference) + { + # Updating the udev file + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0384", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, + }); + my $problem = $anvil->Storage->write_file({ + file => $anvil->data->{path}{configs}{'persistent-net'}, + body => $new_persistent_net, + overwrite => 1, + user => "admin", + group => "admin", + mode => "0644", - $anvil->data->{virsh}{bridge}{$bridge} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "virsh::bridge::$bridge" => $anvil->data->{virsh}{bridge}{$bridge} }}); + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if ($problem) + { + # Failed to write the udev file + $anvil->Job->update_progress({ + progress => 100, + message => "error_0043", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, + }); + $anvil->nice_exit({exit_code => 1}); } + } + + # Update the connection.interface-name + my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.interface-name'} ? $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); + if ($connection_interface_name) + { + # Removing the old 'connection.interface-name' + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0385", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { name => $connection_interface_name }, + }); + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.interface-name \"\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, + }}); - foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{virsh}{bridge}}) + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$nm_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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, + }}); + + if ($output) { - # Destroy (stop) it. - my ($destroy, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$bridge}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { destroy => $destroy, return_code => $return_code }}); - - # Disable it from auto-start. - (my $disable, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-autostart ".$bridge." --disable"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disable => $disable, return_code => $return_code }}); - - # Undefine (delete) - (my $undefine, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$bridge}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { undefine => $undefine, return_code => $return_code }}); + # Failed to delete the 'connection.interface-name', This should have been blank + $anvil->Job->update_progress({ + progress => 100, + message => "error_0481", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { output => $output }, + }); + $anvil->nice_exit({exit_code => 1}); } } + # We'll log what it was, and change it anyway + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} ? $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); $anvil->Job->update_progress({ - progress => 75, - job_uuid => $anvil->data->{job}{uuid}, + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0386", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + new_name => $wanted_link_name, + old_device => $old_device, + }, }); - - return(0); -} - -# This renames a network interface -sub rename_interface -{ - my ($anvil, $old_link_name, $new_link_name) = @_; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0465", variables => { - old_interface => $old_link_name, - new_interface => $new_link_name, + if ($old_device eq $wanted_link_name) + { + # Both the netbios name and the old device name are the same, match would break! + $anvil->Job->update_progress({ + progress => 100, + message => "error_0490", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + wanted_link_name => $wanted_link_name, + old_device => $old_device, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." match.interface-name \"".$wanted_link_name." ".$old_device."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, }}); - # Take the old name down. - my $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." down"; + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$nm_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, + output => $output, return_code => $return_code, }}); - # Rename - $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." name ".$new_link_name; + if (($output ne $wanted_link_name.",".$old_device) && ($output ne $old_device.",".$wanted_link_name)) + { + # This should have been blank + $anvil->Job->update_progress({ + progress => 100, + message => "error_0482", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { + new_name => $wanted_link_name, + old_device => $old_device, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # Set the connection.id to the old name. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0387", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { old_device => $old_device }, + }); + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.id \"".$old_device."\""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, + output => $output, return_code => $return_code, }}); - # Bring up the new interface - $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$new_link_name." up"; + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$nm_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, + output => $output, return_code => $return_code, }}); - return(0); -} - -# This will read a network interface file and return the UUID="x" value. If the file doesn't exist or the -# UUID was not found, a new UUID is generated and returned. -sub get_uuid_from_interface_file -{ - my ($anvil, $file) = @_; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 'print' => 1, key => "log_0131", variables => { function => "get_uuid_from_interface_file" }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }}); + # Re-read the updated data + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); - my $uuid = ""; - if (-e $file) - { - my $body = $anvil->Storage->read_file({file => $file}); - foreach my $line (split/\n/, $body) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); - $line =~ s/#.*//; - if ($line =~ /UUID=\"(.*?)\"/) - { - my $test_uuid = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { test_uuid => $test_uuid }}); - if ($anvil->Validate->uuid({uuid => $test_uuid})) - { - $uuid = $test_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }}); - } - last; - } - } - } - if (not $uuid) - { - $uuid = $anvil->Get->uuid(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }}); - } + # Set the reboot flag. + $anvil->data->{sys}{reboot_needed} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }}); - return($uuid); + return(0); } # This will pick up the job, or exit. @@ -1630,9 +2329,26 @@ sub pickup_job_details }}); } + ### These are the new variables + $anvil->data->{config}{striker_password} = ""; + $anvil->data->{config}{prefix} = ""; + $anvil->data->{config}{sequence} = ""; + $anvil->data->{config}{domain} = ""; + $anvil->data->{config}{host_name} = ""; + $anvil->data->{config}{organization} = ""; + $anvil->data->{config}{bcn_count} = 1; + $anvil->data->{config}{ifn_count} = 1; + $anvil->data->{config}{sn_count} = 0; + $anvil->data->{config}{mn_count} = 0; + $anvil->data->{config}{dns} = ""; + $anvil->data->{config}{gateway} = ""; + $anvil->data->{config}{gateway_interface} = ""; + + ### TODO: Remove this later # This will store the variables from the database $anvil->data->{variables} = {}; + ### TODO: Remove this, it shouldn't be needed once we confirm everything is in the job_data. # If we're still alive, pick up the details. my $query = " SELECT @@ -1670,6 +2386,7 @@ AND $anvil->_make_hash_reference($anvil->data->{variables}, $this_variable, $this_value); } + ### TODO: This is the only way we should do it, but the variable names need to change to be more sensible. # Overwrite variables with job data. foreach my $line (split/\n/, $anvil->data->{jobs}{job_data}) { @@ -1681,6 +2398,37 @@ AND }}); $anvil->_make_hash_reference($anvil->data->{variables}, $1, $2); } + elsif ($line =~ /^(.*?)=(.*)$/) + { + my $variable = $1; + my $value = $2; + my $secure = $variable =~ /passw/ ? 1 : 0; + $anvil->data->{config}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable' => $variable, + 's2:value' => $anvil->Log->is_secure($value), + "s3:config::${variable}" => $anvil->Log->is_secure($anvil->data->{config}{$variable}), + }}); + } + } + + ### TODO: Remove this when no longer needed. + # Convert old variables to new ones. + foreach my $config_step (sort {$a cmp $b} keys %{$anvil->data->{variables}{form}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { config_step => $config_step }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{variables}{form}{$config_step}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + + if (exists $anvil->data->{variables}{form}{$config_step}{$variable}{value}) + { + $anvil->data->{config}{$variable} = $anvil->data->{variables}{form}{$config_step}{$variable}{value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${variable}" => $anvil->data->{config}{$variable}, + }}); + } + } } # Clear previous data @@ -1692,9 +2440,13 @@ AND # Record that we've picked up this job. $anvil->Job->update_progress({ - progress => 1, - message => "message_0015", - job_uuid => $anvil->data->{job}{uuid}, + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0015", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, }); # If we're in a cluster, abort. @@ -1711,11 +2463,15 @@ AND { # We're in a cluster, abort. $anvil->Job->update_progress({ - progress => 100, - message => "error_0250", - job_uuid => $anvil->data->{job}{uuid}, + progress => 100, + message => "error_0250", + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0250"}); $anvil->nice_exit({exit_code => 7}); } } diff --git a/tools/anvil-daemon b/tools/anvil-daemon index eeea2e2e..05e6cdd0 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -75,6 +75,7 @@ $anvil->System->wait_on_dnf(); $anvil->Database->connect({ check_if_configured => 1, check_for_resync => 2, + debug => 2, }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"}); @@ -100,6 +101,9 @@ if (not $anvil->data->{sys}{database}{connections}) } else { + # Striker can't initialize us unless it can ssh into us, so make sure root login is enabled. + chech_sshd($anvil); + # Wait until we have one. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0075"}); @@ -200,7 +204,7 @@ while(1) # Reload defaults, re-read the config and then connect to the database(s) $anvil->refresh(); - # If, so some reason, anvil.conf is lost, create it. + # If, for some reason, anvil.conf is lost, create it. $anvil->System->_check_anvil_conf(); $anvil->Database->connect({check_if_configured => $check_if_database_is_configured, check_for_resync => 2}); @@ -208,26 +212,13 @@ while(1) # Mark that we don't want to check the database now. $check_if_database_is_configured = 0; - - # If this host is mapping the network, we'll skip a lot of stuff. If set for over an hour, we'll - # clear it. - $anvil->data->{sys}{mapping_network} = check_if_mapping($anvil); - if ($anvil->data->{sys}{database}{connections}) { # Run the normal tasks keep_running($anvil); # Handle periodic tasks - handle_periodic_tasks($anvil) if not $anvil->data->{sys}{mapping_network}; - } - else - { - # No databases available, we'll update the state file in case this host is having it's - # network mapped and the interface used to talk to the databases went down. That's all we - # can do though. - update_state_file($anvil); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "log_0202"}); + handle_periodic_tasks($anvil); } # Exit if 'run-once' selected. @@ -312,85 +303,6 @@ sub check_ram return(0); } -# Check to see if we're mapping the network on this host. -sub check_if_mapping -{ - my ($anvil) = @_; - - $anvil->data->{sys}{mapping_network} = 0; - if ($anvil->data->{sys}{database}{connections}) - { - my ($map_network_value, $map_network_uuid, $map_network_mtime, $map_network_modified_date) = $anvil->Database->read_variable({ - debug => 3, - variable_name => "config::map_network", - variable_source_table => "hosts", - variable_source_uuid => $anvil->data->{sys}{host_uuid}, - }); - # We'll run for a day (should be cancelled by the program when the user's done, so this - # shouldn't fire in practice). - my $expire_age = 86400; - my $map_network_age = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:map_network_value' => $map_network_value, - 's2:map_network_mtime' => $map_network_mtime, - 's3:map_network_modified_date' => $map_network_modified_date, - 's4:map_network_uuid' => $map_network_uuid, - }}); - if ($map_network_uuid) - { - $map_network_age = time - $map_network_mtime; - $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? - $anvil->data->{switches}{'clear-mapping'} = "" if not defined $anvil->data->{switches}{'clear-mapping'}; - if (($map_network_age >= $expire_age) or ($anvil->data->{switches}{'clear-mapping'})) - { - # Clear it. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0470"}); - $anvil->Database->insert_or_update_variables({ - debug => 3, - variable_value => 0, - variable_uuid => $map_network_uuid, - update_value_only => 1, - }); - } - 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 => 1, key => "log_0471", variables => { - age => $say_age, - timeout => $timeout, - }}); - - $anvil->data->{sys}{mapping_network} = 1; - $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 => 3, list => { - ssh_fh_key => $ssh_fh_key, - ssh_fh => $ssh_fh, - }}); - if ($ssh_fh =~ /^Net::OpenSSH/) - { - $ssh_fh->disconnect(); - } - delete $anvil->data->{cache}{ssh_fh}{$ssh_fh_key}; - } - } - } - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::mapping_network" => $anvil->data->{sys}{mapping_network} }}); - return($anvil->data->{sys}{mapping_network}); -} - # This decides if the local system will delay daily runs on start-up. sub set_delay { @@ -431,6 +343,7 @@ sub check_network { my ($anvil) = @_; + ### TODO: Remove this when EL8 support is dropped. This was an issue with the old ifcfg configured bonds # The network sometimes doesn't come up, but we don't want to try recovering it too soon. As such, # we'll start watching the network after the uptime is 2 minutes. my $uptime = $anvil->Get->uptime; @@ -450,19 +363,11 @@ sub check_network $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); } - #$anvil->Network->check_network({heal => "all"}); - $anvil->data->{sys}{network}{initial_checks} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::network::initial_checks" => $anvil->data->{sys}{network}{initial_checks}, }}); } - else - { - ### NOTE: This is constantly trying to "fix" healthy bonds, without a know way to - ### trigger to debug. As such, disabling for now. - #$anvil->Network->check_network({heal => "down_only"}); - } check_firewall($anvil); } @@ -500,6 +405,27 @@ sub check_network } } + # Check that there's at least one entry in 'network_interfaces' and, if not, call scan-network. + if (1) + { + my $query = "SELECT COUNT(*) FROM network_interfaces WHERE network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $count = $anvil->Database->query({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) + { + # Run scan-network + my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/scan-network/scan-network".$anvil->Log->switches; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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); } @@ -530,7 +456,7 @@ sub handle_periodic_tasks # Check that the users we care about have ssh public keys and they're recorded in ssh_keys. $anvil->System->check_ssh_keys({debug => 2}); - $anvil->System->update_hosts({debug => 3}); + $anvil->System->update_hosts({debug => 2}); # Check if the files on disk have changed. Even if it is time to check, don't if a job is # running. @@ -560,9 +486,6 @@ sub handle_periodic_tasks return_code => $return_code, }}); - # Scan the local network. - update_state_file($anvil); - # Check shared files. check_files($anvil); @@ -1100,6 +1023,9 @@ sub run_once # Check journald is configured for persistent storage. check_journald($anvil); + # Make sure root can ssh + chech_sshd($anvil); + if ($anvil->data->{switches}{'startup-only'}) { $anvil->nice_exit({exit_code => 0}); @@ -1108,6 +1034,50 @@ sub run_once return(0); } +sub chech_sshd +{ + my ($anvil) = @_; + + # On EL8, the 'sshd_config.d' directory doesn't exist and root is enabled. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'path::directories::sshd_config.d' => $anvil->data->{path}{directories}{'sshd_config.d'} }}); + if (not -d $anvil->data->{path}{directories}{'sshd_config.d'}) + { + return(0); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'path::configs::sshd_root_password' => $anvil->data->{path}{configs}{sshd_root_password} }}); + if (not -f $anvil->data->{path}{configs}{sshd_root_password}) + { + # Write it out + my $body = "# This file was added to enable root login by password, which is needed while +# forming the Anvil! cluster. Once the cluster is formed, passwordless SSH +# should be enabled and you can disable this feature. Please remove during a +# maintanence window or after testing in a lab environment. +PermitRootLogin yes +"; + # Update the config + $anvil->Storage->write_file({ + debug => 2, + secure => 0, + file => $anvil->data->{path}{configs}{sshd_root_password}, + body => $body, + mode => "0644", + }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0418", variables => { file => $anvil->data->{path}{configs}{sshd_root_password} }}); + + # Restart the journald service. + my $shell_call = $anvil->data->{path}{exe}{systemctl}." restart sshd.service"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + return(0); +} + sub check_journald { my ($anvil) = @_; @@ -1200,7 +1170,7 @@ sub check_journald return(0); } -# This creates, as needed, the setuid wrappers used by apache to make certain system calls. +# This creates, as needed, the setuid wrappers used by striker-ui-api to make certain system calls. sub check_setuid_wrappers { my ($anvil) = @_; @@ -1432,7 +1402,7 @@ AND } # Make sure /etc/hosts is updated. - $anvil->System->update_hosts(); + $anvil->System->update_hosts({debug => 2}); # This handles weird bits for things like bug work-arounds. handle_special_cases($anvil); @@ -1443,14 +1413,6 @@ AND # Check the firewall needs to be updated. check_firewall($anvil); - # If we're a striker, check apache - 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") - { - $anvil->Striker->check_httpd_conf({debug => 3}); - } - return(0); } @@ -1541,7 +1503,7 @@ sub keep_running my ($anvil) = @_; # Check for jobs that were running and now exited. - if ((not $anvil->data->{sys}{mapping_network}) && (exists $anvil->data->{processes})) + if (exists $anvil->data->{processes}) { foreach my $job_uuid (%{$anvil->data->{jobs}{handles}}) { @@ -1572,18 +1534,13 @@ sub keep_running # If we're configured, write out the status JSON file. If we're not configured, Update hardware state files. my $configured = $anvil->System->check_if_configured; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }}); - if ((not $anvil->data->{sys}{mapping_network}) && ($configured)) + if ($configured) { # Write out state information for all known Anvil! systems and the information from # unconfigured nods and DR hosts, using just database data (hence, fast enough to run # constantly). $anvil->System->generate_state_json({debug => 2}); } - else - { - # Run this to monitor the network in real time. - update_state_file($anvil); - } # Run any pending jobs by calling 'anvil-jobs' with the 'job_uuid' as a background process. run_jobs($anvil, 0); @@ -1620,10 +1577,6 @@ sub run_jobs # changed on disk. $anvil->data->{sys}{jobs_running} = 0; - # If we're not configured, we won't hold on starting jobs - my $configured = $anvil->System->check_if_configured; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }}); - # We'll also update the jobs.json file. my $jobs_file = "{\"jobs\":[\n"; @@ -1676,11 +1629,16 @@ sub run_jobs 's12:job_status' => $job_status, 's13:started_seconds_ago' => $started_seconds_ago, 's14:updated_seconds_ago' => $updated_seconds_ago, - 's15:sys::mapping_network' => $anvil->data->{sys}{mapping_network}, }}); - # If we're mapping, we'll only run 'anvil-configure-host' jobs on this host. - next if (($anvil->data->{sys}{mapping_network}) && ($job_command !~ /anvil-configure-host/)); + # If we're not configured, we will only run the 'anvil-configure-host' job + my $configured = $anvil->System->check_if_configured; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }}); + + if ((not $configured) && ($job_command !~ /anvil-configure-host/)) + { + next; + } # To minimize the chance of race conditions, any given command will be called only # once at a time. If two jobs of the same command exist, only one will be called. @@ -1793,9 +1751,9 @@ sub run_jobs } # Convert the double-banged strings into a proper message. - my $say_title = $job_title ? $anvil->Words->parse_banged_string({key_string => $job_title}) : ""; - my $say_description = $job_description ? $anvil->Words->parse_banged_string({key_string => $job_description}) : ""; - my $say_status = $job_status ? $anvil->Words->parse_banged_string({key_string => $job_status}) : ""; + my $say_title = $job_title ? $anvil->Words->parse_banged_string({debug => 2, key_string => $job_title}) : ""; + my $say_description = $job_description ? $anvil->Words->parse_banged_string({debug => 2, key_string => $job_description}) : ""; + my $say_status = $job_status ? $anvil->Words->parse_banged_string({debug => 2, key_string => $job_status}) : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { job_title => $job_title, say_description => $say_description, @@ -1963,8 +1921,8 @@ sub run_jobs overwrite => 1, backup => 0, mode => "0644", - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", }); return(0); @@ -2004,8 +1962,8 @@ sub check_files { my $failed = $anvil->Storage->make_directory({ directory => $directory, - group => "apache", - user => "apache", + group => "striker-ui-api", + user => "striker-ui-api", mode => "0777", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { failed => $failed }}); @@ -2032,24 +1990,3 @@ sub check_files return(0); } - -# This calls 'anvil-update-states' which will scan the local machine's state (hardware and software) and -# record write it out to an HTML file -sub update_state_file -{ - my ($anvil) = @_; - - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0480"}); - - #my $shell_call = $anvil->data->{path}{exe}{'anvil-update-states'}.$anvil->Log->switches; - my $shell_call = $anvil->data->{path}{exe}{'anvil-update-states'}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); - - my ($states_output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - states_output => $states_output, - return_code => $return_code, - }}); - - return(0); -} diff --git a/tools/anvil-download-file b/tools/anvil-download-file index a28e49ce..a5937a73 100755 --- a/tools/anvil-download-file +++ b/tools/anvil-download-file @@ -222,8 +222,8 @@ sub download_file debug => 2, directory => $save_to, mode => "0777", - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); } @@ -233,8 +233,8 @@ sub download_file debug => 2, directory => $anvil->data->{path}{directories}{shared}{temp}, mode => "0777", - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); } diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index e4952005..5202beed 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -22,6 +22,7 @@ use Anvil::Tools; use Data::Dumper; use String::ShellQuote; use Text::Diff; +use NetAddr::IP; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; @@ -54,6 +55,9 @@ if (not $anvil->data->{sys}{database}{connections}) # Get the job details load_job($anvil); +# Make sure the hosts file has entries for all nets for both subnodes +wait_for_etc_hosts($anvil); + # Hold until both subnodes are marked as configured and not in maintenance mode. wait_for_subnodes($anvil); @@ -63,6 +67,10 @@ update_passwords($anvil); # Check if we need to change any IPs or our hostname. check_local_network($anvil); +# Wait until we can ping our peer on all networks. +wait_for_access($anvil); + +### TODO: Change corosync.conf to use IPs, including MN if it exists. # (wait for out peer and) Configure pacemaker configure_pacemaker($anvil); @@ -98,6 +106,426 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# +# Make sure the hosts file has entries for all nets for both subnodes +sub wait_for_etc_hosts +{ + my ($anvil) = @_; + + my $anvil_uuid = $anvil->data->{sys}{anvil_uuid}; + my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; + my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; + my $manifest_uuid = $anvil->data->{sys}{manifest_uuid}; + my $i_am = $anvil->data->{sys}{machine}; + my $peer_is = $i_am eq "node1" ? "node2" : "node1"; + my $peer_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{"anvil_".$peer_is."_host_uuid"}; + my $peer_short_host_name = $anvil->data->{hosts}{host_uuid}{$peer_host_uuid}{short_host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:anvil_uuid' => $anvil_uuid, + 's2:manifest_uuid' => $manifest_uuid, + 's3:node1_host_uuid' => $node1_host_uuid, + 's4:node2_host_uuid' => $node2_host_uuid, + 's5:i_am' => $i_am, + 's6:peer_is' => $peer_is, + 's7:peer_host_uuid' => $peer_host_uuid, + 's8:peer_short_host_name' => $peer_short_host_name, + }}); + + 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 => $anvil->data->{sys}{manifest_uuid}, + problem => $problem, + }}); + if ($problem) + { + # Something went wrong, fatally. Abort the job. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "job_0076", variables => { uuid => $anvil->data->{sys}{manifest_uuid} }}); + update_progress($anvil, 100, "job_0076,!!uuid!".$anvil->data->{sys}{manifest_uuid}."!!"); + $anvil->nice_exit({exit_code => 2}); + } + + # Create the list of host names we need to see in /etc/hosts and the hostnames to use in corosync. + foreach my $machine (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}}) + { + my $this_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{"anvil_".$machine."_host_uuid"}; + my $this_short_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; + my $bcn_name = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine => $machine }}); + foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}}) + { + my $host_name = $this_short_host_name.".".$network_name; + my $ip_address = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}{$network_name}{ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:network_name' => $network_name, + 's2:host_name' => $host_name, + 's3:ip_address' => $ip_address, + }}); + + $anvil->data->{networks}{$host_name}{ip_address} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:networks::${host_name}::ip_address" => $anvil->data->{networks}{$host_name}{ip_address}, + }}); + + # If this is the first BCN, record it's name (in case BCN1 isn't used here) and IP + # address, and add the short and full host names. + if (($network_name =~ /^bcn/) && (not $bcn_name)) + { + $bcn_name = $network_name; + my $this_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bcn_name => $bcn_name }}); + + $anvil->data->{networks}{$this_short_host_name}{ip_address} = $ip_address; + $anvil->data->{networks}{$this_host_name}{ip_address} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:networks::${this_short_host_name}::ip_address" => $anvil->data->{networks}{$this_short_host_name}{ip_address}, + "s2:networks::${this_host_name}::ip_address" => $anvil->data->{networks}{$this_host_name}{ip_address}, + }}); + } + } + } + + my $waiting = 1; + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0477"); + while($waiting) + { + # Update the /etc/hosts file. Note that this doesn't add hosts that are not yet trusted, so + # anything not found will be inserted here. + $anvil->System->update_hosts({debug => 2}); + + # Now lets see if all expected hosts names are in the /etc/hosts file yet. + my $ready = 1; + my $hosts_file = $anvil->Storage->read_file({ + file => $anvil->data->{path}{configs}{hosts}, + force_read => 1, + cache => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hosts_file => $hosts_file }}); + + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{networks}}) + { + my $found = 0; + my $ip_address = $anvil->data->{networks}{$host_name}{ip_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:host_name' => $host_name, + 's2:ip_address' => $ip_address, + }}); + + foreach my $line (split/\n/, $hosts_file) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + $line =~ s/#.*$//; + if ($line =~ /^(\d.*?)\s+(.*)$/) + { + my $this_ip = $1; + my $hosts = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_ip => $this_ip, + hosts => $hosts, + }}); + + if ($anvil->Validate->ip({ip => $this_ip})) + { + foreach my $this_host (split/\s+/, $hosts) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_host => $this_host }}); + + if ($host_name eq $this_host) + { + my $variables = { + host_name => $host_name, + ip_address => $ip_address, + found_ip => $this_ip, + }; + if ($ip_address eq $this_ip) + { + # Found it + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0830", variables => $variables }); + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + } + else + { + # Found the host, but the IP doesn't match. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0831", variables => $variables }); + } + } + last if $found; + } + } + } + last if $found; + } + + if (not $found) + { + $ready = 0; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0832", variables => { host_name => $host_name }}); + + # Add the IP to be added to /etc/hosts. + $anvil->data->{to_add}{$host_name} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "to_add::${ip_address}" => $anvil->data->{to_add}{$host_name} }}); + } + } + + if ($ready) + { + # Ready! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0833"}); + + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + } + else + { + # Not ready, wait a bit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0834"}); + + # Add the values to /etc/hosts. + my $new_hosts_body = ""; + foreach my $line (split/\n/, $hosts_file) + { + # See if this line needs to be modified. + if ($line =~ /^(\d.*?)\s+(.*)$/) + { + my $this_ip = $1; + my $hosts = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_ip => $this_ip, + hosts => $hosts, + }}); + if ($anvil->Validate->ip({ip => $this_ip})) + { + my $changes = 0; + my $new_hosts = ""; + my $comment = ($hosts =~ /(#.*)$/)[0]; + $comment = "" if not defined $comment; + $hosts =~ s/#.*?//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + comment => $comment, + hosts => $hosts, + }}); + foreach my $host_name (split/\s+/, $hosts) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }}); + + if ((exists $anvil->data->{to_add}{$host_name}) && + ($anvil->data->{to_add}{$host_name}) && + ($this_ip ne $anvil->data->{to_add}{$host_name})) + { + # Remove this host. + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + delete $anvil->data->{to_add}{$host_name}; + next; + } + $new_hosts .= $host_name." "; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_hosts => $new_hosts }}); + } + + # Do we have any names to add to this IP? + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{to_add}}) + { + if ($this_ip eq $anvil->data->{to_add}{$host_name}) + { + # Add it. + $new_hosts .= $host_name." "; + + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + delete $anvil->data->{to_add}{$host_name}; + } + } + + if ($changes) + { + $new_hosts_body .= $this_ip."\t".$new_hosts.$comment."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + next; + } + } + } + + # If we're alive here, just add the old line. + $new_hosts_body .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_hosts_body => $new_hosts_body }}); + } + + # Add any hosts still not processed. + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{to_add}}) + { + $new_hosts_body .= $anvil->data->{to_add}{$host_name}."\t".$host_name."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_hosts_body => $new_hosts_body }}); + + delete $anvil->data->{to_add}{$host_name}; + } + + # If there's a difference, write the new hosts file. + my $difference = diff \$new_hosts_body, \$hosts_file, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + + if ($difference) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0112"}); + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0112"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0835"}); + my $failed = $anvil->Storage->write_file({ + debug => 2, + overwrite => 1, + file => $anvil->data->{path}{configs}{hosts}, + body => $new_hosts_body, + user => "root", + group => "root", + mode => "0644", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); + } + sleep 1; + } + } + + return(0); +} + +sub wait_for_access +{ + my ($anvil) = @_; + + # NOTE: This logic is a copy of anvil-safe-start. + $anvil->Database->get_hosts(); + $anvil->Database->get_anvils(); + my $host_uuid = $anvil->Get->host_uuid(); + my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name}; + my $peer_host_uuid = $anvil->data->{sys}{peer_host_uuid}; + my $peer_short_host_name = $anvil->data->{hosts}{host_uuid}{$peer_host_uuid}{short_host_name}; + my $peer_password = $anvil->data->{sys}{peer_password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host_uuid => $host_uuid, + short_host_name => $short_host_name, + peer_host_uuid => $peer_host_uuid, + peer_short_host_name => $peer_short_host_name, + peer_password => $anvil->Log->is_secure($peer_password), + }}); + + my $waiting = 1; + while ($waiting) + { + # This will get set back to '1' if + $waiting = 0; + + # Load IPs (again, to catch changes that might be delaying startup) + $anvil->Network->load_ips({ + clear => 1, + host => $short_host_name, + host_uuid => $host_uuid, + + }); + $anvil->Network->load_ips({ + clear => 1, + host => $peer_short_host_name, + host_uuid => $peer_host_uuid, + + }); + + # Loop through our interfaces and then loop our peers. Test access over them and set + # 'waiting' back to '1' if the connection fails. + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$short_host_name}{interface}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + waiting => $waiting, + }}); + + # Only care about our networks. + next if $waiting; + if (not $anvil->Network->is_our_interface({interface => $interface})) + { + # Not an interface we care about + next; + } + + my $this_network = ($interface =~ /^(.*?)_/)[0]; + my $ip_address = $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip}; + my $subnet_mask = $anvil->data->{network}{$short_host_name}{interface}{$interface}{subnet_mask}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:this_network' => $this_network, + 's2:ip_address' => $ip_address, + 's3:subnet_mask' => $subnet_mask, + }}); + + ### NOTE: I know I could match interface names, but that's not certain enough. It's + ### possible (if unlikely) that the network name+numbre differs on our peer. So + ### this is safer. + # Loop through my peer's interfaces and see if we're sharing this one. + my $local_network = NetAddr::IP->new($ip_address."/".$subnet_mask); + my $peer_match_found = 0; + foreach my $peer_interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$peer_short_host_name}{interface}}) + { + last if $peer_match_found; + my $peer_ip_address = $anvil->data->{network}{$peer_short_host_name}{interface}{$peer_interface}{ip}; + my $peer_subnet_mask = $anvil->data->{network}{$peer_short_host_name}{interface}{$peer_interface}{subnet_mask}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + peer_interface => $peer_interface, + peer_ip_address => $peer_ip_address, + peer_subnet_mask => $peer_subnet_mask, + }}); + + # This the matching network? + next if $subnet_mask ne $peer_subnet_mask; + + my $peer_network = NetAddr::IP->new($peer_ip_address."/".$peer_subnet_mask); + if ($peer_network->within($local_network)) + { + # Match, test access. + $peer_match_found = 1; + my $access = $anvil->Remote->test_access({ + target => $peer_ip_address, + password => $peer_password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); + if ($access) + { + # This network is good. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0604", variables => { + peer => $peer_short_host_name, + network => $this_network, + peer_ip => $peer_ip_address, + }}); + + $anvil->data->{sys}{peer_target_ip} = $peer_ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sys::peer_target_ip" => $anvil->data->{sys}{peer_target_ip}, + }}); + } + else + { + # No access, wait and try it again. + $waiting = 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0605", variables => { + peer => $peer_short_host_name, + network => $this_network, + peer_ip => $peer_ip_address, + }}); + } + } + + } + } + + if ($waiting) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0606", variables => { peer => $peer_short_host_name }}); + sleep 5; + } + } + + # All networks are up. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0607", variables => { peer => $peer_short_host_name }}); + + return(0); +} + # Configure DRBD sub configure_drbd { @@ -495,20 +923,52 @@ sub configure_pacemaker } if (time > $start_again) { - # Call cluster start again. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0272"}); - $start_again = time + 60; - my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster start --all"; + ### NOTE: We can't just call 'start --all' again anymore. Now we need to + ### stop -> start. Before we do this, make sure there are no servers + ### running. + $start_again = time + 60; + my $restart = 1; + my $server_count = keys %{$anvil->data->{cib}{parsed}{data}{server}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - start_again => $start_again, - shell_call => $shell_call, + start_again => $start_again, + server_count => $server_count, }}); + foreach my $server (sort {$a cmp $b} keys %{$anvil->data->{cib}{parsed}{data}{server}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cib::parsed::data::server::${server}::active" => $anvil->data->{cib}{parsed}{data}{server}{$server}{active}, + }}); + if ($anvil->data->{cib}{parsed}{data}{server}{$server}{active}) + { + $restart = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { restart => $restart }}); + } + } - my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { restart => $restart }}); + if ($restart) + { + # Call cluster start again. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0272"}); + my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster stop --all"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + start_again => $start_again, + shell_call => $shell_call, + }}); + + my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{pcs}." cluster start --all"; + ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } } sleep 5 if not $both_online; } @@ -1155,7 +1615,7 @@ sub configure_pacemaker } } - # Update (if needed) corosync.conf to use the BCN1 and SN1 as knet networks. + # Update (if needed) corosync.conf to use the BCN1, MN1 and SN1 as knet networks. if ($machine eq "node1") { update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0344"); @@ -1189,6 +1649,7 @@ sub check_corosync my $new_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; while ($waiting) { + ### TODO: Add MN where appropriate my $problem = $anvil->Cluster->parse_cib({debug => 3}); my $peer_ready = $anvil->data->{cib}{parsed}{peer}{ready}; my $peer_name = $anvil->data->{cib}{parsed}{peer}{name}; @@ -2258,11 +2719,6 @@ sub check_local_network } } - # Update the hosts file. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0112"}); - update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0112"); - $anvil->System->update_hosts({debug => 3}); - # Configure SSH by adding ours and our peer's SSH keys to ~/.ssh/known_hosts $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0113"}); update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0113"); diff --git a/tools/anvil-manage-dr b/tools/anvil-manage-dr index ad2286e0..b9e9cef8 100755 --- a/tools/anvil-manage-dr +++ b/tools/anvil-manage-dr @@ -1945,7 +1945,7 @@ sub process_remove ### If we're here, we can now update the resource config file to remove the DR host. # Refresh the IP info (usually scrubbed by this point) - $anvil->Database->get_ip_addresses(); + $anvil->Database->get_ip_addresses({debug => 2}); # First loop to build the node sections, then we'll loop to build the connections my $node1_volumes = ""; @@ -2901,7 +2901,7 @@ sub process_protect } # Refresh the IP info (usually scrubbed by this point) - $anvil->Database->get_ip_addresses(); + $anvil->Database->get_ip_addresses({debug => 2}); # The connections. Node 1 to 2 always uses the BCN, Either node to DR needs my $storage_network = "sn1"; diff --git a/tools/anvil-manage-host b/tools/anvil-manage-host index 97f7894d..9b3ce96c 100755 --- a/tools/anvil-manage-host +++ b/tools/anvil-manage-host @@ -29,12 +29,9 @@ $anvil->Get->switches({list => [ "auto-grow-pv", "check-configured", "check-database", - "check-network-mapping", "confirm", "database-active", "database-inactive", - "disable-network-mapping", - "enable-network-mapping", "mark-configured", "mark-unconfigured", "resync-database"], man => $THIS_FILE}); @@ -58,10 +55,6 @@ elsif (($anvil->data->{switches}{'database-active'}) or ($anvil->data->{switches { update_database($anvil); } -elsif (($anvil->data->{switches}{'enable-network-mapping'}) or ($anvil->data->{switches}{'disable-network-mapping'}) or ($anvil->data->{switches}{'check-network-mapping'})) -{ - update_network_mapping($anvil); -} elsif ($anvil->data->{switches}{'age-out-database'}) { age_out_data($anvil); @@ -279,118 +272,6 @@ sub update_database return(0); } -sub update_network_mapping -{ - my ($anvil) = @_; - - my $variable_name = "config::map_network"; - my ($map_network_value, $map_network_uuid, $map_network_mtime, $map_network_modified_date) = $anvil->Database->read_variable({ - variable_name => $variable_name, - variable_source_table => "hosts", - variable_source_uuid => $anvil->data->{sys}{host_uuid}, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:variable_name' => $variable_name, - 's2:map_network_value' => $map_network_value, - 's3:map_network_mtime' => $map_network_mtime, - 's4:map_network_modified_date' => $map_network_modified_date, - 's5:map_network_uuid' => $map_network_uuid, - }}); - if ($anvil->data->{switches}{'check-network-mapping'}) - { - # We'll run for a day (should be cancelled by the program when the user's done, so this - # shouldn't fire in practice). - my $expire_age = 86400; - my $map_network_age = 0; - if ($map_network_uuid) - { - $map_network_age = time - $map_network_mtime; - $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? - $anvil->data->{switches}{'clear-mapping'} = "" if not defined $anvil->data->{switches}{'clear-mapping'}; - if (($map_network_age >= $expire_age) or ($anvil->data->{switches}{'clear-mapping'})) - { - # Clear it. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0470"}); - $anvil->Database->insert_or_update_variables({ - debug => 3, - variable_value => 0, - variable_uuid => $map_network_uuid, - update_value_only => 1, - }); - } - 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__, 'print' => 1, level => 1, key => "log_0471", variables => { - age => $say_age, - timeout => $timeout, - }}); - } - } - else - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0820"}); - } - return(0); - } - - if ($anvil->data->{switches}{'enable-network-mapping'}) - { - if ($map_network_value) - { - # Nothing to do. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0353"}); - } - else - { - # Enable network configuring. - my $variable_uuid = $anvil->Database->insert_or_update_variables({ - variable_name => $variable_name, - variable_value => 1, - variable_default => "", - variable_description => "striker_0202", - variable_section => "config", - variable_source_uuid => $anvil->Get->host_uuid, - variable_source_table => "hosts", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0354"}); - } - } - - if ($anvil->data->{switches}{'disable-network-mapping'}) - { - if ($map_network_value) - { - # Disable network configuring. - my $variable_uuid = $anvil->Database->insert_or_update_variables({ - variable_name => $variable_name, - variable_value => 0, - variable_default => "", - variable_description => "striker_0202", - variable_section => "config", - variable_source_uuid => $anvil->Get->host_uuid, - variable_source_table => "hosts", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0356"}); - } - else - { - # Nothing to do. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0355"}); - } - } - - return(0); -} - sub update_config { my ($anvil) = @_; diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network new file mode 100755 index 00000000..dab33a0e --- /dev/null +++ b/tools/anvil-monitor-network @@ -0,0 +1,505 @@ +#!/usr/bin/perl +# +# This daemon watches for network interface link change (unplugged or plugged in network cables). +# +# At this point, the only thing this does is call 'scan-network' when a change is detected. +# +# NOTE: This is designed to be minimal overhead, so there is no attempt to connect to the database. As such, +# be mindful of what this daemon is used for. +# + +use strict; +use warnings; +use Data::Dumper; +use Text::Diff; +use Anvil::Tools; + +my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; +my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; +if (($running_directory =~ /^\./) && ($ENV{PWD})) +{ + $running_directory =~ s/^\./$ENV{PWD}/; +} + +# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. +$| = 1; + +my $anvil = Anvil::Tools->new(); + +# Read switches +$anvil->Get->switches({list => [], man => $THIS_FILE}); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); + +# Calculate my sum so that we can exit if it changes later. +$anvil->Storage->record_md5sums; +my $next_md5sum_check = time + 30; + +my $directory = "/sys/class/net"; +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); + +# Now go into the main loop +while(1) +{ + ### NOTE: A lot of this logic comes from scan-network + my $scan_time = time; + my $trigger = 0; + + # Look for interfaces. + local(*DIRECTORY); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) + { + next if $file eq "."; + next if $file eq ".."; + next if $file eq "lo"; + my $full_path = $directory."/".$file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); + if (-d $full_path) + { + # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. + my $interface = $file; + my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; + $link_state =~ s/\n$//; + my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; + $mtu =~ s/\n$//; + my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? + $duplex =~ s/\n$//; + my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down + $operational =~ s/\n$//; + my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; + $modalias =~ s/\n$//; + my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link + $speed =~ s/\n$//; + my $media = "unknown"; + my $type = "interface"; + my $driver = ""; + my $tx_bytes = 0; # How many bytes transmitted + my $rx_bytes = 0; # How many bytes received + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + link_state => $link_state, + mtu => $mtu, + duplex => $duplex, + operational => $operational, + speed => $speed, + modalias => $modalias, + }}); + + # Get the MAC address + my $mac_address = ""; + my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + 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, + }}); + if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) + { + $mac_address = lc($1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + else + { + # Get it by reading the address file. + if (-e $full_path."/bonding_slave/perm_hwaddr") + { + $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + elsif (-e $full_path."/address") + { + $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); + $mac_address =~ s/\n//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + } + + # These are variables that will be needed if this is a bond interface. + my $ip_address = ""; + my $subnet_mask = ""; + my $bond_mode = ""; + my $primary_interface = ""; + my $primary_reselect = ""; + my $active_interface = ""; + my $mii_polling_interval = ""; + my $up_delay = ""; + my $down_delay = ""; + my $bond_parent = ""; + + # These are variables that will be needed if this is a bridge interface + my $bridge_id = ""; + my $bridge_stp_enabled = ""; + + # If this interface is already a bond slave, the real mac address will be in a + # sub-directory. + my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; + if (-e $mac_bond_file) + { + # It's a slave. + $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + + # Pick out our driver. + if ($modalias =~ /^virtio:/) + { + $driver = "virtio"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); + } + + # If this is a virtual interface, set some fake values that don't actually exist on + # the system for the sake of a cleaner display. + if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) + { + ### Set some fake values. + # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. + if ((not $speed) or ($speed eq "-1")) + { + $speed = 10000; + } + if ((not $duplex) or ($duplex eq "unknown")) + { + $duplex = "full"; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + speed => $speed, + duplex => $duplex, + }}); + } + # If the state is 'down', set the speed to '0'. + if (not $link_state) + { + $speed = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); + } + + # Is this a bond interface? + if (-e "/proc/net/bonding/".$interface) + { + # Yup, we'll neet to dig into the bond proc files to get the proper slaved + # interface MAC addresses. + $type = "bond"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + + # Read the bond mode. + $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); + $bond_mode =~ s/\s.*//; + $bond_mode =~ s/\n$//; + $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); + $primary_interface =~ s/\n$//; + $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); + $primary_reselect =~ s/\s.*//; + $primary_reselect =~ s/\n$//; + $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); + $active_interface =~ s/\n$//; + $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); + $mii_polling_interval =~ s/\n$//; + $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); + $up_delay =~ s/\n$//; + $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); + $down_delay =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + active_interface => $active_interface, + bond_mode => $bond_mode, + mii_polling_interval => $mii_polling_interval, + primary_reselect => $primary_reselect, + primary_interface => $primary_interface, + type => $type, + }}); + } + elsif ((-e $full_path."/master") && ($interface !~ /^vnet/)) + { + # We're in a bond. + my $target = readlink($full_path."/master"); + $bond_parent = ($target =~ /^.*\/(.*)$/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + target => $target, + bond_parent => $bond_parent, + }}); + } + elsif (-d $full_path."/bridge") + { + # It's a bridge + $type = "bridge"; + $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); + $bridge_id =~ s/\n$//; + $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); + $bridge_stp_enabled =~ s/\n$//; + $speed = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + type => $type, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, + }}); + if ($bridge_stp_enabled eq "0") + { + $bridge_stp_enabled = "disabled"; + } + elsif ($bridge_stp_enabled eq "1") + { + $bridge_stp_enabled = "enabled_kernel"; + } + elsif ($bridge_stp_enabled eq "2") + { + $bridge_stp_enabled = "enabled_userland"; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); + } + + # If this is a 'vnet' device, set 'operational' to up + if ($interface =~ /^vnet/) + { + ### TODO: We can't assume this, we need to detect virsh net up/down + $operational = "up"; + $media = "virtual"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + operational => $operational, + media => $media, + }}); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + active_interface => $active_interface, + bond_parent => $bond_parent, + bond_mode => $bond_mode, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, + down_delay => $down_delay, + duplex => $duplex, + interface => $interface, + mac_address => $mac_address, + mii_polling_interval => $mii_polling_interval, + mtu => $mtu, + operational => $operational, + primary_reselect => $primary_reselect, + primary_interface => $primary_interface, + speed => $speed, + subnet_mask => $subnet_mask, + type => $type, + up_delay => $up_delay, + }}); + + # Find the media, if possible. + (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." ".$interface}); + foreach my $line (split/\n/, $ethtool) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /Supported ports: \[ (.*?) \]/i) + { + $media = lc($1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + + # This can be 'tp mii', which breaks json. + if ($media =~ /\t/) + { + $media =~ s/\t/,/g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + } + last; + } + } + + # Trigger? + if (not exists $anvil->data->{last_scan}{$interface}) + { + print "The interface: [".$interface."] has been found. We will now monitor it for changes.\n"; + $trigger = 1; + } + else + { + # Now look for differences. + if ($anvil->data->{last_scan}{$interface}{active_interface} ne $active_interface) + { + print "The ".$type.": [".$interface."] has a different active interface: [".$anvil->data->{last_scan}{$interface}{active_interface}."] -> [".$active_interface."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{bond_mode} ne $bond_mode) + { + print "The ".$type.": [".$interface."] mode has changed from: [".$anvil->data->{last_scan}{$interface}{bond_mode}."] -> [".$bond_mode."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{bond_parent} ne $bond_parent) + { + print "The ".$type.": [".$interface."] bond parent has changed from: [".$anvil->data->{last_scan}{$interface}{bond_parent}."] -> [".$bond_parent."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{bridge_id} ne $bridge_id) + { + print "The ".$type.": [".$interface."] bridge ID has changed from: [".$anvil->data->{last_scan}{$interface}{bridge_id}."] -> [".$bridge_id."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{bridge_stp_enabled} ne $bridge_stp_enabled) + { + print "The ".$type.": [".$interface."] spanning tree protocol (STP) setting has changed from: [".$anvil->data->{last_scan}{$interface}{bridge_stp_enabled}."] -> [".$bridge_stp_enabled."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{down_delay} ne $down_delay) + { + print "The ".$type.": [".$interface."] down delay has changed from: [".$anvil->data->{last_scan}{$interface}{bridge_stp_enabled}."ms] -> [".$bridge_stp_enabled."ms].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{up_delay} ne $up_delay) + { + print "The ".$type.": [".$interface."] up delay has changed from: [".$anvil->data->{last_scan}{$interface}{up_delay}."ms] -> [".$up_delay."ms].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{duplex} ne $duplex) + { + print "The ".$type.": [".$interface."] duplex has changed from: [".$anvil->data->{last_scan}{$interface}{duplex}."] -> [".$duplex."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{ip_address} ne $ip_address) + { + print "The ".$type.": [".$interface."] ip address has changed from: [".$anvil->data->{last_scan}{$interface}{ip_address}."] -> [".$ip_address."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{subnet_mask} ne $subnet_mask) + { + print "The ".$type.": [".$interface."] subnet_mask has changed from: [".$anvil->data->{last_scan}{$interface}{subnet_mask}."] -> [".$subnet_mask."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{link_state} ne $link_state) + { + print "The ".$type.": [".$interface."] link status has changed from: [".$anvil->data->{last_scan}{$interface}{link_state}."] -> [".$link_state."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{mac_address} ne $mac_address) + { + print "The ".$type.": [".$interface."] MAC address has changed from: [".$anvil->data->{last_scan}{$interface}{mac_address}."] -> [".$mac_address."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{media} ne $media) + { + print "The ".$type.": [".$interface."] media has changed from: [".$anvil->data->{last_scan}{$interface}{media}."] -> [".$media."]. (Excuse me, how?!)\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{mii_polling_interval} ne $mii_polling_interval) + { + print "The ".$type.": [".$interface."] media independent interface (mii) polling interval has changed from: [".$anvil->data->{last_scan}{$interface}{mii_polling_interval}."ms] -> [".$mii_polling_interval."ms].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{mtu} ne $mtu) + { + print "The ".$type.": [".$interface."] maximum transmission unit (mtu) has changed from: [".$anvil->data->{last_scan}{$interface}{mtu}." bytes] -> [".$mtu." bytes].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{operational} ne $operational) + { + print "The ".$type.": [".$interface."] operational status has changed from: [".$anvil->data->{last_scan}{$interface}{operational}."] -> [".$operational."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{primary_reselect} ne $primary_reselect) + { + print "The ".$type.": [".$interface."] primary reselect policy has changed from: [".$anvil->data->{last_scan}{$interface}{primary_reselect}."] -> [".$primary_reselect."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{primary_interface} ne $primary_interface) + { + print "The ".$type.": [".$interface."] primary interface has changed from: [".$anvil->data->{last_scan}{$interface}{primary_interface}."] -> [".$primary_interface."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{speed} ne $speed) + { + print "The ".$type.": [".$interface."] speed has changed from: [".$anvil->data->{last_scan}{$interface}{speed}." Mbps] -> [".$speed." Mbps].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{type} ne $type) + { + print "The device: [".$interface."] type has changed from: [".$anvil->data->{last_scan}{$interface}{type}."] -> [".$type."].\n"; + $trigger = 1; + } + } + + # We'll use this to determine when an interface has disappeared. + $anvil->data->{last_scan}{$interface}{seen} = $scan_time; + + # Store new information we found. + $anvil->data->{last_scan}{$interface}{active_interface} = $active_interface; + $anvil->data->{last_scan}{$interface}{bond_mode} = $bond_mode; + $anvil->data->{last_scan}{$interface}{bond_parent} = $bond_parent; + $anvil->data->{last_scan}{$interface}{bridge_id} = $bridge_id; + $anvil->data->{last_scan}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; + $anvil->data->{last_scan}{$interface}{down_delay} = $down_delay; + $anvil->data->{last_scan}{$interface}{duplex} = $duplex; + $anvil->data->{last_scan}{$interface}{ip_address} = $ip_address; + $anvil->data->{last_scan}{$interface}{link_state} = $link_state; + $anvil->data->{last_scan}{$interface}{mac_address} = $mac_address; + $anvil->data->{last_scan}{$interface}{media} = $media; + $anvil->data->{last_scan}{$interface}{mii_polling_interval} = $mii_polling_interval; + $anvil->data->{last_scan}{$interface}{mtu} = $mtu; + $anvil->data->{last_scan}{$interface}{operational} = $operational; + $anvil->data->{last_scan}{$interface}{primary_reselect} = $primary_reselect; + $anvil->data->{last_scan}{$interface}{primary_interface} = $primary_interface; + $anvil->data->{last_scan}{$interface}{speed} = $speed; + $anvil->data->{last_scan}{$interface}{subnet_mask} = $subnet_mask; + $anvil->data->{last_scan}{$interface}{type} = $type; + $anvil->data->{last_scan}{$interface}{up_delay} = $up_delay; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "last_scan::${interface}::seen" => $anvil->data->{last_scan}{$interface}{seen}, + "last_scan::${interface}::active_interface" => $anvil->data->{last_scan}{$interface}{active_interface}, + "last_scan::${interface}::bond_mode" => $anvil->data->{last_scan}{$interface}{bond_mode}, + "last_scan::${interface}::bond_parent" => $anvil->data->{last_scan}{$interface}{bond_parent}, + "last_scan::${interface}::bridge_id" => $anvil->data->{last_scan}{$interface}{bridge_id}, + "last_scan::${interface}::bridge_stp_enabled" => $anvil->data->{last_scan}{$interface}{bridge_stp_enabled}, + "last_scan::${interface}::down_delay" => $anvil->data->{last_scan}{$interface}{down_delay}, + "last_scan::${interface}::duplex" => $anvil->data->{last_scan}{$interface}{duplex}, + "last_scan::${interface}::ip_address" => $anvil->data->{last_scan}{$interface}{ip_address}, + "last_scan::${interface}::link_state" => $anvil->data->{last_scan}{$interface}{link_state}, + "last_scan::${interface}::mac_address" => $anvil->data->{last_scan}{$interface}{mac_address}, + "last_scan::${interface}::media" => $anvil->data->{last_scan}{$interface}{media}, + "last_scan::${interface}::mii_polling_interval" => $anvil->data->{last_scan}{$interface}{mii_polling_interval}, + "last_scan::${interface}::mtu" => $anvil->data->{last_scan}{$interface}{mtu}, + "last_scan::${interface}::operational" => $anvil->data->{last_scan}{$interface}{operational}, + "last_scan::${interface}::primary_reselect" => $anvil->data->{last_scan}{$interface}{primary_reselect}, + "last_scan::${interface}::primary_interface" => $anvil->data->{last_scan}{$interface}{primary_interface}, + "last_scan::${interface}::speed" => $anvil->data->{last_scan}{$interface}{speed}, + "last_scan::${interface}::subnet_mask" => $anvil->data->{last_scan}{$interface}{subnet_mask}, + "last_scan::${interface}::type" => $anvil->data->{last_scan}{$interface}{type}, + "last_scan::${interface}::up_delay" => $anvil->data->{last_scan}{$interface}{up_delay}, + }}); + } + } + closedir(DIRECTORY); + + # Now look for interfaces that disappeared. + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{last_scan}}) + { + next if $anvil->data->{last_scan}{$interface}{seen} == $scan_time; + print "The device: [".$interface."] appears to have disappeared!\n"; + delete $anvil->data->{last_scan}{$interface}; + + $trigger = 1; + } + + # Trigger? + if ($trigger) + { + my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/scan-network/scan-network".$anvil->Log->switches; + print "Triggering the call to run: [".$shell_call."]\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + 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, + }}); + } + + if (time > $next_md5sum_check) + { + $next_md5sum_check = time + 30; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { next_md5sum_check => $next_md5sum_check }}); + if ($anvil->Storage->check_md5sums) + { + # NOTE: We exit with '0' to prevent systemctl from showing a scary red message. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "message_0014"}); + $anvil->nice_exit({exit_code => 0}); + } + } + + sleep 2; +} diff --git a/tools/anvil-parse-fence-agents b/tools/anvil-parse-fence-agents index c4ee440b..d8ffb8b5 100755 --- a/tools/anvil-parse-fence-agents +++ b/tools/anvil-parse-fence-agents @@ -91,8 +91,8 @@ sub refresh_unified_metadata backup => 0, file => $anvil->data->{path}{data}{fences_unified_metadata}, body => $anvil->data->{fences}{unified_xml}, - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", mode => "0666", }); } diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index e358456a..5a87605a 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -321,8 +321,11 @@ sub run_jobs # Make sure the VNC port is open. $anvil->Network->manage_firewall(); - # Add the server to the cluster. - add_server_to_cluster($anvil); + # If we're not the peer, add the server to the cluster. + if (not $anvil->data->{job}{peer_mode}) + { + add_server_to_cluster($anvil); + } # Update the database by calling select scan agents $anvil->Job->update_progress({ @@ -368,8 +371,9 @@ sub add_server_to_cluster # Is our peer in the cluster? For that matter, are we? my $problem = $anvil->Cluster->add_server({ - debug => 2, - server_name => $anvil->data->{job}{server_name}, + debug => 2, + server_name => $anvil->data->{job}{server_name}, + ok_if_exists => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); if ($problem) diff --git a/tools/anvil-safe-start b/tools/anvil-safe-start index c37cd869..c890e7fe 100755 --- a/tools/anvil-safe-start +++ b/tools/anvil-safe-start @@ -44,6 +44,11 @@ $anvil->Get->switches({list => [], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); +### TODO: Remove before PR! +# Force up the logging. +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + # Make sure we're running as 'root' # $< == real UID, $> == effective UID if (($< != 0) && ($> != 0)) @@ -94,7 +99,7 @@ if (not $anvil->data->{sys}{database}{connections}) # Check to see if we should run. Also checks/sets enable/disable requests. prerun_checks($anvil); -# Wait until I can ping the peer on all three networks. This will not return until access is available on all +# Wait until I can ping the peer on all networks. This will not return until access is available on all # networks. There is no timeout. wait_for_access($anvil); @@ -343,7 +348,7 @@ sub start_pacemaker while ($waiting) { $waiting = 0; - my ($problem) = $anvil->Cluster->parse_cib({debug => 3}); + my ($problem) = $anvil->Cluster->parse_cib({debug => 2}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); if ($problem) { diff --git a/tools/anvil-sync-shared b/tools/anvil-sync-shared index a0497555..a821c8ca 100755 --- a/tools/anvil-sync-shared +++ b/tools/anvil-sync-shared @@ -483,7 +483,7 @@ sub process_incoming_file $anvil->nice_exit({exit_code => 1}); } - # Change the owner as it'll be apache, which won't be a valid users on anvil members. + # Change the owner as it'll be striker-ui-api, which won't be a valid users on anvil members. $anvil->Storage->change_owner({ debug => 2, path => $target_file, diff --git a/tools/anvil-update-states b/tools/anvil-update-states deleted file mode 100755 index e9df6781..00000000 --- a/tools/anvil-update-states +++ /dev/null @@ -1,1161 +0,0 @@ -#!/usr/bin/perl -# -# This updates things like the current network configuration, shared file data and writes it out to a json file. -# -# TODO: -# - Retire this once scan-network is finished. -# -use strict; -use warnings; -use Anvil::Tools; -use Data::Dumper; - -# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. -$| = 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(); - -$anvil->Get->switches; -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); - -# If there's no DB (or cached data isn't recorded to the database yet), this will store those records. -$anvil->data->{cache}{new_file} = "# interface,timestamp,mac_address,speed,link_state,operational\n"; - -$anvil->Database->connect(); -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); -if (not $anvil->data->{sys}{database}{connections}) -{ - # No database, but we need to keep going. If the user unplugged the only cable connecting us to the - # network, we'll lose all DBs, but we still need to record the order the NICs went up and down. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0016"}); -} - -process_interface_cache($anvil); - -update_network($anvil); - -# Write out the interface cache -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "cache::new_file" => $anvil->data->{cache}{new_file}, - "path::data::network_cache" => $anvil->data->{path}{data}{network_cache}, -}}); -$anvil->Storage->write_file({ - debug => 3, - body => $anvil->data->{cache}{new_file}, - file => $anvil->data->{path}{data}{network_cache}, - overwrite => 1, - backup => 0, -}); - -$anvil->nice_exit({exit_code => 0}); - - -############################################################################################################# -# Functions # -############################################################################################################# - -# This reads in the interface cache file and looks for records that haven't been stored in the database yet. -sub process_interface_cache -{ - my ($anvil) = @_; - - # Does the file exist? If so, read it in. - if (-e $anvil->data->{path}{data}{network_cache}) - { - my $body = $anvil->Storage->read_file({debug => 2, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}}); - foreach my $line (split/\n/, $body) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - next if $line =~ /^#/; - my ($interface, $timestamp, $mac_address, $speed, $link_state, $operational) = (split/,/, $line); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - timestamp => $timestamp, - speed => $speed, - mac_address => $mac_address, - link_state => $link_state, - operational => $operational, - }}); - - if ($anvil->data->{sys}{database}{connections}) - { - my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({ - debug => 2, - link_only => 1, - timestamp => $timestamp, - network_interface_name => $interface, - network_interface_link_state => $link_state, - network_interface_mac_address => $mac_address, - network_interface_operational => $operational, - network_interface_speed => $speed, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }}); - if (not $network_interface_uuid) - { - # Failed to update, could be that we cached data for an interface not yet - # seen. If so, the coming scan will add it and this cache should flush out - # next time. - $anvil->data->{cache}{new_file} .= $line."\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); - } - } - else - { - # No database, re-cache - $anvil->data->{cache}{new_file} .= $line."\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); - } - } - } - - return(0); -} - -# This reports the current network interface states, tracked by the MAC address. -sub update_network -{ - my ($anvil) = @_; - - # Run 'ip addr' to see what IPs are in use. - $anvil->Network->get_ips(); - - # We'll read through '/sys/class/net' looking for network interfaces. - # * 'network::${local_host}::interface::::ip' - If an IP address is set - # * 'network::${local_host}::interface::::subnet_mask' - If an IP is set - my $local_host = $anvil->Get->short_host_name(); - my $directory = "/sys/class/net"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }}); - - # We'll need to know what interfaces to remove, if any. This will store the interfaces we've seen and - # any others will be removed. - $anvil->data->{seen} = { - interface => {}, - bond => {}, - bridge => {}, - ip => {}, - }; - - # Make sure there are no virsh bridges, removing any found. - 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 "node") or ($host_type eq "dr")) - { - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list --all --name"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - - 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, - }}); - if (not $return_code) - { - # Virsh is up. - foreach my $line (split/\n/, $output) - { - $line =~ s/^\s+//; - $line =~ s/\s+$//; - next if not $line; - next if $line =~ /^error/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "striker_0287", variables => { bridge => $line }}); - - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$line; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - 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, - }}); - - $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$line; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($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, - }}); - } - } - } - - # Walk through the sysfs files. - local(*DIRECTORY); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }}); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) - { - next if $file eq "."; - next if $file eq ".."; - next if $file eq "lo"; - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path }}); - if (-d $full_path) - { - # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. - my $interface = $file; - my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; - my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; - my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? - my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down - my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; - my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link - my $media = "unknown"; - my $type = "interface"; - my $driver = ""; - - # Clean up some newlines. - $link_state =~ s/\n$//; - $mtu =~ s/\n$//; - $duplex =~ s/\n$//; - $operational =~ s/\n$//; - $speed =~ s/\n$//; - $modalias =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - link_state => $link_state, - mtu => $mtu, - duplex => $duplex, - operational => $operational, - speed => $speed, - modalias => $modalias, - }}); - - ### NOTE: This only parses virtio so far. - # Pick out our driver. - if ($modalias =~ /^virtio:/) - { - $driver = "virtio"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); - } - - # The MAC address can faked by a number of ways, so we make an explicit call to 'ethtool' to get the permanent mac address. - my $mac_address = ""; - my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - - 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, - }}); - if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) - { - $mac_address = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - else - { - # Get it by reading the address file. - if (-e $full_path."/bonding_slave/perm_hwaddr") - { - $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - elsif (-e $full_path."/address") - { - $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); - $mac_address =~ s/\n//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - } - - # These are variables that will be needed if this is a bond interface. - my $ip_address = ""; - my $subnet_mask = ""; - my $bond_mode = ""; - my $primary_interface = ""; - my $primary_reselect = ""; - my $active_interface = ""; - my $mii_polling_interval = ""; - my $up_delay = ""; - my $down_delay = ""; - my $bond_master = ""; - - # These are variables that will be needed if this is a bridge interface - my $bridge_id = ""; - my $bridge_stp_enabled = ""; - - # Explicitly check for the existing of the hash so that we don't auto-vivivate the interface. - if (exists $anvil->data->{network}{$local_host}{interface}{$interface}) - { - $ip_address = defined $anvil->data->{network}{$local_host}{interface}{$interface}{ip} ? $anvil->data->{network}{$local_host}{interface}{$interface}{ip} : ""; - $subnet_mask = defined $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} : ""; - $type = defined $anvil->data->{network}{$local_host}{interface}{$interface}{type} ? $anvil->data->{network}{$local_host}{interface}{$interface}{type} : "interface"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address => $ip_address, - subnet_mask => $subnet_mask, - type => $type, - }}); - } - - # If this interface is already a bond slave, the real mac address will be in a - # sub-directory. - my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; - if (-e $mac_bond_file) - { - # It's a slave. - $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); - $mac_address =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { mac_address => $mac_address }}); - } - - # If this is a virtual interface, set some fake values that don't actually exist on - # the system for the sake of a cleaner display. - if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) - { - ### Set some fake values. - # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. - if ((not $speed) or ($speed eq "-1")) - { - $speed = 10000; - } - if ((not $duplex) or ($duplex eq "unknown")) - { - $duplex = "full"; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - speed => $speed, - duplex => $duplex, - }}); - } - # If the state is 'down', set the speed to '0'. - if (not $link_state) - { - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); - } - - # Is this a bond interface? - if (-e "/proc/net/bonding/".$interface) - { - # Yup, we'll neet to dig into the bond proc files to get the proper slaved - # interface MAC addresses. - $type = "bond"; - - # Read the bond mode. - $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); - $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); - $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); - $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); - $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); - $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); - $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); - $bond_mode =~ s/\s.*//; - $bond_mode =~ s/\n$//; - $primary_interface =~ s/\n$//; - $primary_reselect =~ s/\s.*//; - $primary_reselect =~ s/\n$//; - $active_interface =~ s/\n$//; - $mii_polling_interval =~ s/\n$//; - $up_delay =~ s/\n$//; - $down_delay =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - active_interface => $active_interface, - bond_mode => $bond_mode, - mii_polling_interval => $mii_polling_interval, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - type => $type, - }}); - } - elsif (-e $full_path."/master") - { - # No, but it's slaved to one. - my $target = readlink($full_path."/master"); - $bond_master = ($target =~ /^.*\/(.*)$/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - target => $target, - bond_master => $bond_master, - }}); - } - elsif (-d $full_path."/bridge") - { - # It's a bridge - $type = "bridge"; - $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); - $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); - $bridge_id =~ s/\n$//; - $bridge_stp_enabled =~ s/\n$//; - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - bridge_id => $bridge_id, - bridge_stp_enabled => $bridge_stp_enabled, - type => $type, - }}); - if ($bridge_stp_enabled eq "0") - { - $bridge_stp_enabled = "disabled"; - } - elsif ($bridge_stp_enabled eq "1") - { - $bridge_stp_enabled = "enabled_kernel"; - } - elsif ($bridge_stp_enabled eq "2") - { - $bridge_stp_enabled = "enabled_userland"; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bridge_stp_enabled => $bridge_stp_enabled }}); - } - - # If this a vnet device, set 'operational' to 'up'. - if ($interface =~ /^vnet/) - { - $operational = "up"; - $media = "virtual"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - operational => $operational, - media => $media, - }}); - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - active_interface => $active_interface, - bond_master => $bond_master, - bond_mode => $bond_mode, - bridge_id => $bridge_id, - bridge_stp_enabled => $bridge_stp_enabled, - down_delay => $down_delay, - duplex => $duplex, - interface => $interface, - mac_address => $mac_address, - mii_polling_interval => $mii_polling_interval, - mtu => $mtu, - operational => $operational, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - speed => $speed, - subnet_mask => $subnet_mask, - type => $type, - up_delay => $up_delay, - }}); - - # If the MAC address starts with '52:54:00', we've got a virtio NIC. - if ((not defined $speed) or ($speed eq "")) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0001", variables => { file => $full_path."/speed" }}); - next; - } - if ($speed =~ /\D/) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0002", variables => { - file => $full_path."/speed", - speed => $speed, - }}); - next; - } - if ($speed > 100000) - { - # NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable - # and we'll need to change this. - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { speed => $speed }}); - } - - # Find the media, if possible. - (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); - foreach my $line (split/\n/, $ethtool) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); - if ($line =~ /Supported ports: \[ (.*?) \]/i) - { - $media = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - - # This can be 'tp mii', which breaks json. - if ($media =~ /\t/) - { - $media =~ s/\t/,/g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - } - last; - } - } - - # Record this interface - $anvil->data->{seen}{$type}{$interface} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "seen::${type}::${interface}" => $anvil->data->{seen}{$type}{$interface} }}); - - # Record the IP, if set. - if ($ip_address) - { - $anvil->data->{seen}{ip}{$ip_address} = $interface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "seen::ip::${ip_address}" => $anvil->data->{seen}{ip}{$ip_address} }}); - } - - # Store new information we found. - $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; - $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; - $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; - $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id} = $bridge_id; - $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; - $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay} = $down_delay; - $anvil->data->{network}{$local_host}{interface}{$interface}{duplex} = $duplex; - $anvil->data->{network}{$local_host}{interface}{$interface}{ip} = $ip_address; - $anvil->data->{network}{$local_host}{interface}{$interface}{link_state} = $link_state; - $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address} = $mac_address; - $anvil->data->{network}{$local_host}{interface}{$interface}{media} = $media; - $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval; - $anvil->data->{network}{$local_host}{interface}{$interface}{mtu} = $mtu; - $anvil->data->{network}{$local_host}{interface}{$interface}{operational} = $operational; - $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect} = $primary_reselect; - $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface} = $primary_interface; - $anvil->data->{network}{$local_host}{interface}{$interface}{speed} = $speed; - $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} = $subnet_mask; - $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; - $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, - "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, - "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, - "network::${local_host}::interface::${interface}::bridge_id" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}, - "network::${local_host}::interface::${interface}::bridge_stp_enabled" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}, - "network::${local_host}::interface::${interface}::down_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}, - "network::${local_host}::interface::${interface}::duplex" => $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}, - "network::${local_host}::interface::${interface}::ip" => $anvil->data->{network}{$local_host}{interface}{$interface}{ip}, - "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, - "network::${local_host}::interface::${interface}::mac_address" => $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}, - "network::${local_host}::interface::${interface}::media" => $anvil->data->{network}{$local_host}{interface}{$interface}{media}, - "network::${local_host}::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}, - "network::${local_host}::interface::${interface}::mtu" => $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}, - "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, - "network::${local_host}::interface::${interface}::primary_reselect" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}, - "network::${local_host}::interface::${interface}::primary_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}, - "network::${local_host}::interface::${interface}::speed" => $anvil->data->{network}{$local_host}{interface}{$interface}{speed}, - "network::${local_host}::interface::${interface}::subnet_mask" => $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}, - "network::${local_host}::interface::${interface}::type" => $anvil->data->{network}{$local_host}{interface}{$interface}{type}, - "network::${local_host}::interface::${interface}::up_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}, - }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, - "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, - }}); - - # If this is a link and there's no database connections, cache the data. - if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) - { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "cache::new_file" => $anvil->data->{cache}{new_file}, - }}); - } - } - } - closedir(DIRECTORY); - - # Find what interfaces are connected to which bridges - $anvil->Network->bridge_info({debug => 2}); - - # We need to record bridges first so we know their UUIDs when looking at bonds and interfaces that - # might be connected to them. Then we need to look at bonds so that their UUIDs are available when - # recording interfaces. - foreach my $processing ("bridge", "bond", "interface") - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { processing => $processing }}); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) - { - # Skip if this isn't the device type we're working on. - next if not defined $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:interface' => $interface, - 's2:type' => $type, - 's3:processing' => $processing, - }}); - next if $processing ne $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - - my $active_interface = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}; - my $bond_mode = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; - my $bond_master = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; - my $bridge_id = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; - my $bridge_stp_enabled = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}; - my $down_delay = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}; - my $duplex = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}; - my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; - my $link_state = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; - my $mac_address = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; - my $media = $anvil->data->{network}{$local_host}{interface}{$interface}{media}; - my $mii_polling_interval = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}; - my $mtu = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; - my $operational = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; - my $primary_reselect = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}; - my $primary_interface = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}; - my $speed = $anvil->data->{network}{$local_host}{interface}{$interface}{speed}; - my $subnet_mask = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; - my $up_delay = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}; - my $default_gateway = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway}; - my $gateway = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway}; - my $dns = $anvil->data->{network}{$local_host}{interface}{$interface}{dns}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - active_interface => $active_interface, - bond_mode => $bond_mode, - bond_master => $bond_master, - default_gateway => $default_gateway, - down_delay => $down_delay, - dns => $dns, - duplex => $duplex, - gateway => $gateway, - interface => $interface, - ip_address => $ip_address, - link_state => $link_state, - mac_address => $mac_address, - media => $media, - mii_polling_interval => $mii_polling_interval, - mtu => $mtu, - operational => $operational, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - speed => $speed, - subnet_mask => $subnet_mask, - up_delay => $up_delay, - }}); - - if (($type eq $processing) && ($type eq "bridge")) - { - if ($anvil->data->{sys}{database}{connections}) - { - my $bridge_uuid = $anvil->Database->insert_or_update_bridges({ - debug => 3, - file => $THIS_FILE, - line => __LINE__, - bridge_name => $interface, - bridge_id => $bridge_id, - bridge_mac_address => $mac_address, - bridge_mtu => $mtu, - bridge_stp_enabled => $bridge_stp_enabled, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); - - $anvil->data->{bridge_by_name}{$interface} = $bridge_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bridge_by_name::${interface}" => $anvil->data->{bridge_by_name}{$interface} }}); - if (($bridge_uuid) && ($ip_address)) - { - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - ip_address_on_type => $type, - ip_address_on_uuid => $bridge_uuid, - ip_address_address => $ip_address, - ip_address_subnet_mask => $subnet_mask, - ip_address_gateway => $gateway, - ip_address_default_gateway => $default_gateway, - ip_address_dns => $dns, - ip_address_note => "", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_uuid => $ip_address_uuid }}); - } - } - } - - if (($type eq $processing) && ($type eq "bond")) - { - # Is this bond connected to a bridge? - my $bond_bridge_uuid = ""; - my $bond_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_on_bridge => $bond_on_bridge }}); - if ($bond_on_bridge) - { - $bond_bridge_uuid = $anvil->data->{bridge_by_name}{$bond_on_bridge}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_bridge_uuid => $bond_bridge_uuid }}); - } - - if ($anvil->data->{sys}{database}{connections}) - { - my $bond_uuid = $anvil->Database->insert_or_update_bonds({ - debug => 3, - file => $THIS_FILE, - line => __LINE__, - bond_name => $interface, - bond_mode => $bond_mode, - bond_mtu => $mtu, - bond_link_state => $link_state, - bond_operational => $operational, - bond_mac_address => $mac_address, - bond_primary_interface => $primary_interface, - bond_primary_reselect => $primary_reselect, - bond_active_interface => $active_interface, - bond_mii_polling_interval => $mii_polling_interval, - bond_up_delay => $up_delay, - bond_down_delay => $down_delay, - bond_bridge_uuid => $bond_bridge_uuid, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_uuid => $bond_uuid }}); - - $anvil->data->{bond_by_name}{$interface} = $bond_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "bond_by_name::${interface}" => $anvil->data->{bond_by_name}{$interface} }}); - - if (($bond_uuid) && ($ip_address)) - { - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - ip_address_on_type => $type, - ip_address_on_uuid => $bond_uuid, - ip_address_address => $ip_address, - ip_address_subnet_mask => $subnet_mask, - ip_address_gateway => $gateway, - ip_address_default_gateway => $default_gateway, - ip_address_dns => $dns, - ip_address_note => "", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_uuid => $ip_address_uuid }}); - } - } - } - - if (($type eq $processing) && ($type eq "interface")) - { - # Is this interface connected to a bridge? - my $network_interface_bridge_uuid = ""; - my $network_interface_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_on_bridge => $network_interface_on_bridge }}); - if ($network_interface_on_bridge) - { - $network_interface_bridge_uuid = $anvil->data->{bridge_by_name}{$network_interface_on_bridge}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_bridge_uuid => $network_interface_bridge_uuid }}); - } - - my $say_bond_uuid = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_master => $bond_master }}); - if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master})) - { - $say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master}, - say_bond_uuid => $say_bond_uuid, - }}); - } - if ($anvil->data->{sys}{database}{connections}) - { - my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - network_interface_bond_uuid => $say_bond_uuid, - network_interface_bridge_uuid => $network_interface_bridge_uuid, - network_interface_name => $interface, - network_interface_duplex => $duplex, - network_interface_link_state => $link_state, - network_interface_operational => $operational, - network_interface_mac_address => $mac_address, - network_interface_medium => $media, - network_interface_mtu => $mtu, - network_interface_speed => $speed, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); - - $anvil->data->{interface_by_name}{$interface} = $network_interface_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }}); - if (($network_interface_uuid) && ($ip_address)) - { - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - ip_address_on_type => $type, - ip_address_on_uuid => $network_interface_uuid, - ip_address_address => $ip_address, - ip_address_subnet_mask => $subnet_mask, - ip_address_gateway => $gateway, - ip_address_default_gateway => $default_gateway, - ip_address_dns => $dns, - ip_address_note => "", - }); - } - } - } - } - } - - if (not $anvil->data->{sys}{database}{connections}) - { - return(0); - } - - # I need to read back in the interface and bridge data and splice it together before I write out the - # XML and JSON files. - my $query = " -SELECT - bond_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 -FROM - bonds -WHERE - bond_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -AND - bond_mode != 'DELETED' -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { 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 => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) - { - my $bond_uuid = $row->[0]; - my $bond_name = $row->[1]; - $anvil->data->{bonds}{$bond_uuid} = { - bond_name => $bond_name, - bond_mode => $row->[2], - bond_mtu => $row->[3], - bond_primary_interface => $row->[4], - bond_primary_reselect => $row->[5], - bond_active_interface => $row->[6], - bond_mii_polling_interval => $row->[7], - bond_up_delay => $row->[8], - bond_down_delay => $row->[9], - bond_mac_address => $row->[10], - bond_operational => $row->[11], - }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "bonds::${bond_uuid}::bond_name" => $anvil->data->{bonds}{$bond_uuid}{bond_name}, - "bonds::${bond_uuid}::bond_mode" => $anvil->data->{bonds}{$bond_uuid}{bond_mode}, - "bonds::${bond_uuid}::bond_mtu" => $anvil->data->{bonds}{$bond_uuid}{bond_mtu}, - "bonds::${bond_uuid}::bond_primary_interface" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_interface}, - "bonds::${bond_uuid}::bond_primary_reselect" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_reselect}, - "bonds::${bond_uuid}::bond_active_interface" => $anvil->data->{bonds}{$bond_uuid}{bond_active_interface}, - "bonds::${bond_uuid}::bond_mii_polling_interval" => $anvil->data->{bonds}{$bond_uuid}{bond_mii_polling_interval}, - "bonds::${bond_uuid}::bond_up_delay" => $anvil->data->{bonds}{$bond_uuid}{bond_up_delay}, - "bonds::${bond_uuid}::bond_down_delay" => $anvil->data->{bonds}{$bond_uuid}{bond_down_delay}, - "bonds::${bond_uuid}::bond_mac_address" => $anvil->data->{bonds}{$bond_uuid}{bond_mac_address}, - "bonds::${bond_uuid}::bond_operational" => $anvil->data->{bonds}{$bond_uuid}{bond_operational}, - }}); - - # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. - if ((not exists $anvil->data->{seen}{bond}{$bond_name}) or (not $anvil->data->{seen}{bond}{$bond_name})) - { - # Mark it as deleted. - my $query = " -UPDATE - bonds -SET - bond_mode = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - bond_uuid = ".$anvil->Database->quote($bond_uuid)." -;"; - $anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); - - # Remove it from the hash so we don't add it to the .json and .xml files. - delete $anvil->data->{bonds}{$bond_uuid}; - } - } - - $query = " -SELECT - bridge_uuid, - bridge_name, - bridge_id, - bridge_mac_address, - bridge_mtu, - bridge_stp_enabled -FROM - bridges -WHERE - bridge_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -AND - bridge_id != 'DELETED' -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) - { - my $bridge_uuid = $row->[0]; - my $bridge_name = $row->[1]; - my $bridge_id = $row->[2]; - my $bridge_mac_address = $row->[3]; - my $bridge_mtu = $row->[4]; - my $bridge_stp_enabled = $row->[5]; - $anvil->data->{bridges}{$bridge_uuid} = { - bridge_name => $bridge_name, - bridge_id => $bridge_id, - bridge_mac_address => $bridge_mac_address, - bridge_mtu => $bridge_mtu, - bridge_stp_enabled => $bridge_stp_enabled, - }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "bridges::${bridge_uuid}::bridge_name" => $anvil->data->{bridges}{$bridge_uuid}{bridge_name}, - "bridges::${bridge_uuid}::bridge_id" => $anvil->data->{bridges}{$bridge_uuid}{bridge_id}, - "bridges::${bridge_uuid}::bridge_mac_address" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mac_address}, - "bridges::${bridge_uuid}::bridge_mtu" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mtu}, - "bridges::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{bridges}{$bridge_uuid}{bridge_stp_enabled}, - }}); - - # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. - if ((not exists $anvil->data->{seen}{bridge}{$bridge_name}) or (not $anvil->data->{seen}{bridge}{$bridge_name})) - { - # Mark it as deleted. - my $query = " -UPDATE - bridges -SET - bridge_id = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; - $anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); - - # Remove it from the hash so we don't add it to the .json and .xml files. - delete $anvil->data->{bridges}{$bridge_uuid}; - } - } - - # Process interfaces - $query = " -SELECT - network_interface_uuid, - network_interface_mac_address, - network_interface_name, - 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 -FROM - network_interfaces -WHERE - network_interface_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -ORDER BY - modified_date DESC -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - - # The order will track the order the interfaces were last modified, which is a way to determine when - # they came up. - my $network_xml = "\n"; - $network_xml .= "\n"; - my $network_json = "{\"networks\":[\n"; - my $order = 1; - foreach my $row (@{$results}) - { - my $network_interface_uuid = $row->[0]; - my $network_interface_name = $row->[2]; - $anvil->data->{network_interfaces}{$network_interface_uuid} = { - network_interface_mac_address => $row->[1], - network_interface_name => $network_interface_name, - network_interface_speed => $row->[3], - network_interface_mtu => $row->[4], - network_interface_link_state => $row->[5], - network_interface_operational => $row->[6], - network_interface_duplex => $row->[7], - network_interface_medium => $row->[8], - network_interface_bond_uuid => defined $row->[9] ? $row->[9] : 'NULL', - network_interface_bridge_uuid => defined $row->[10] ? $row->[10] : 'NULL', - }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "network_interfaces::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}, - "network_interfaces::${network_interface_uuid}::network_interface_name" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}, - "network_interfaces::${network_interface_uuid}::network_interface_speed" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}, - "network_interfaces::${network_interface_uuid}::network_interface_mtu" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}, - "network_interfaces::${network_interface_uuid}::network_interface_link_state" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}, - "network_interfaces::${network_interface_uuid}::network_interface_operational" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}, - "network_interfaces::${network_interface_uuid}::network_interface_duplex" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}, - "network_interfaces::${network_interface_uuid}::network_interface_medium" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}, - "network_interfaces::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid}, - "network_interfaces::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid}, - order => $order, - }}); - - # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. - if (not exists $anvil->data->{network}{$local_host}{interface}{$network_interface_name}) - { - if ($anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational} ne "DELETED") - { - # Mark it as deleted. - my $query = " -UPDATE - network_interfaces -SET - network_interface_operational = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid)." -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0124", variables => { query => $query }}); - $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); - } - - # Remove it from the hash so we don't add it to the .json and .xml files. - delete $anvil->data->{interface}{$network_interface_uuid}; - - # Loop so we don't try to process any further. - next; - } - - my $say_bond = ""; - my $network_interface_bond_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid}; - my $network_interface_bridge_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid}; - if (($network_interface_bond_uuid) && ($network_interface_bond_uuid ne 'NULL')) - { - $say_bond = $anvil->data->{bonds}{$network_interface_bond_uuid}{bond_name}; - } - my $say_bridge = ""; - if (($network_interface_bridge_uuid) && ($network_interface_bridge_uuid ne 'NULL')) - { - $say_bridge = $anvil->data->{bridges}{$network_interface_bridge_uuid}{bridge_name}; - } - - $network_json .= " { \"name\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}."\", \"mac\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}."\", \"link\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}."\", \"speed\":\"".$anvil->Convert->add_commas({number => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}})."\", \"mtu\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}."\", \"duplex\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}."\", \"state\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}."\", \"media\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}."\", \"bond\":\"".$say_bond."\", \"bridge\":\"".$say_bridge."\", \"order\":\"".$order."\" },\n"; - $network_xml .= " data->{network_interfaces}{$network_interface_uuid}{network_interface_name}."\" mac=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}."\" link=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}."\" speed=\"".$anvil->Convert->add_commas({number => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}})."\" mtu=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}."\" duplex=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}."\" state=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}."\" media=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}."\" bond=\"".$say_bond."\" bridge=\"".$say_bridge."\" order=\"".$order."\" />\n"; - $order++; - } - - $network_json =~ s/,$//s; - $network_json .= "],\n"; - $network_json .= "\"ips\":[\n"; - - # Now record the IPs. - $query = " -SELECT - ip_address_uuid, - ip_address_on_type, - ip_address_on_uuid, - ip_address_address, - ip_address_subnet_mask, - ip_address_gateway, - ip_address_default_gateway, - ip_address_dns, - ip_address_note -FROM - ip_addresses -WHERE - ip_address_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) - { - my $ip_address_uuid = $row->[0]; - my $ip_address_on_type = $row->[1]; - my $ip_address_on_uuid = $row->[2]; - my $ip_address_address = $row->[3]; - my $ip_address_subnet_mask = $row->[4]; - my $ip_address_gateway = $row->[5]; - my $ip_address_default_gateway = $row->[6]; - my $ip_address_dns = $row->[7]; - my $ip_address_note = $row->[8]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address_on_type => $ip_address_on_type, - ip_address_on_uuid => $ip_address_on_uuid, - ip_address_address => $ip_address_address, - ip_address_subnet_mask => $ip_address_subnet_mask, - ip_address_gateway => $ip_address_gateway, - ip_address_default_gateway => $ip_address_default_gateway, - ip_address_dns => $ip_address_dns, - ip_address_note => $ip_address_note, - }}); - - if ((not exists $anvil->data->{seen}{ip}{$ip_address_address}) or (not $anvil->data->{seen}{ip}{$ip_address_address})) - { - # This IP address no longer exists on this host, removing it. - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - 'delete' => 1, - ip_address_uuid => $ip_address_uuid, - }); - next; - } - - my $say_on = ""; - if ($ip_address_on_type eq "interface") - { - $say_on = $anvil->data->{network_interfaces}{$ip_address_on_uuid}{network_interface_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }}); - } - elsif ($ip_address_on_type eq "bond") - { - $say_on = $anvil->data->{bonds}{$ip_address_on_uuid}{bond_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }}); - } - elsif ($ip_address_on_type eq "bridge") - { - $say_on = $anvil->data->{bridges}{$ip_address_on_uuid}{bridge_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }}); - } - - $network_json .= " { \"address\":\"$ip_address_address\", \"on\":\"$say_on\", \"subnet_mask\":\"$ip_address_subnet_mask\", \"gateway\":\"$ip_address_gateway\", \"default_gateway\":\"$ip_address_default_gateway\", \"dns\":\"$ip_address_dns\" },\n"; - $network_xml .= " \n"; - } - - $network_json =~ s/,$//s; - $network_json .= "]}\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }}); - - $network_xml .= "\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_xml => $network_xml }}); - - # Write the JSON file, if we're a dashboard. Nodes and DR hosts don't have a WebUI, so they're not - # needed. - if ($anvil->Get->host_type eq "striker") - { - my $output_json = $anvil->data->{path}{directories}{html}."/status/network.json"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_json }}); - $anvil->Storage->write_file({ - backup => 0, - file => $output_json, - body => $network_json, - overwrite => 1, - mode => "0644", - user => "apache", - group => "apache" - }); - - # Write the XML file. - my $output_xml = $anvil->data->{path}{directories}{html}."/status/network.xml"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_xml }}); - $anvil->Storage->write_file({ - backup => 0, - file => $output_xml, - body => $network_xml, - overwrite => 1, - mode => "0644", - user => "apache", - group => "apache" - }); - } - - return(0); -} diff --git a/tools/anvil-version-changes b/tools/anvil-version-changes index c49176e9..602b3dc3 100755 --- a/tools/anvil-version-changes +++ b/tools/anvil-version-changes @@ -63,12 +63,17 @@ sub striker_checks { my ($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 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 replaces anvil_uuid with host_uuid to support more granular location info to support the new # multi-target DR system @@ -243,12 +248,300 @@ CREATE TRIGGER trigger_dr_links 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';"; diff --git a/tools/anvil-watch-servers b/tools/anvil-watch-servers index dbcf4acb..28a5183e 100755 --- a/tools/anvil-watch-servers +++ b/tools/anvil-watch-servers @@ -132,7 +132,7 @@ sub show_status if ($anvil->data->{switches}{watch}) { my $date = $anvil->Get->date_and_time(); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0382", variables => { date => $date }}); + print $anvil->Words->string({key => "message_0382", variables => { date => $date }})."\n"; } print $anvil->data->{display}{status}; diff --git a/tools/fence_pacemaker b/tools/fence_pacemaker index 352656bf..325b4276 100755 --- a/tools/fence_pacemaker +++ b/tools/fence_pacemaker @@ -192,19 +192,19 @@ sub create_constraint my $rule_found = 0; my $rule_name = "drbd-fenced_".$target_server; my $shell_call = $conf->{path}{exe}{pcs}." constraint location config show ".$target_server; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if ($line =~ /Expression: $rule_name /) { $rule_found = 1; - to_log($conf, {message => "rule_found: [".$rule_found."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_found: [".$rule_found."]", 'line' => __LINE__, level => 1}); last; } } @@ -220,14 +220,14 @@ sub create_constraint # Set the node attribute my $rule_set = 0; $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --update 1"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); } close $file_handle; @@ -235,19 +235,19 @@ sub create_constraint $rule_set = 0; my $rule_output = ""; $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --query"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if (($line =~ /name=$rule_name/) && ($line =~ /value=1/)) { $rule_set = 1; - to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 1}); last; } else diff --git a/tools/scancore b/tools/scancore index 5c387936..1743dce7 100755 --- a/tools/scancore +++ b/tools/scancore @@ -91,8 +91,10 @@ $anvil->Storage->record_md5sums(); # Connect to DBs. wait_for_database($anvil); +### NOTE: We need to collect data from the start. Once confirmed this isn't introducing old problems, remove +### this function # If we're not configured, sleep. -wait_until_configured($anvil); +#wait_until_configured($anvil); # Startup tasks. startup_tasks($anvil); @@ -141,7 +143,7 @@ while(1) if ($anvil->data->{sys}{database}{connections}) { # Run the normal tasks - $anvil->ScanCore->call_scan_agents(); + $anvil->ScanCore->call_scan_agents({debug => 2}); # Do post-scan analysis. $anvil->ScanCore->post_scan_analysis({debug => 2}); diff --git a/tools/striker-auto-initialize-all b/tools/striker-auto-initialize-all index ce4fc90d..6687dcd0 100755 --- a/tools/striker-auto-initialize-all +++ b/tools/striker-auto-initialize-all @@ -1288,6 +1288,7 @@ fi; remote_user => "root", }}); my ($host_uuid, $error, $return_code) = $anvil->Remote->call({ + debug => 2, shell_call => $shell_call, target => $ip, password => $anvil->data->{base}{password}{desired}, diff --git a/tools/striker-collect-debug b/tools/striker-collect-debug index 888dd859..1f5a5b08 100755 --- a/tools/striker-collect-debug +++ b/tools/striker-collect-debug @@ -353,12 +353,13 @@ sub collect_remote_data # Copying the file print "Done! Copying to here... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/tmp/journalctl-previous-boot.log", destination => $target_directory."/", }); my $test_file = $target_directory."/tmp/journalctl-previous-boot.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -392,12 +393,13 @@ sub collect_remote_data # Copying the file print "Done! Copying to here... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/tmp/journalctl-current-boot.log", destination => $target_directory."/", }); $test_file = $target_directory."/journalctl-current-boot.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -431,12 +433,13 @@ sub collect_remote_data { print "- Grabbing cloud-init logs... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/var/log/cloud-init*", destination => $target_directory."/", }); $test_file = $target_directory."/cloud-init.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -499,12 +502,13 @@ sub collect_remote_data print "- Grabbing hosts file... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/etc/hosts", destination => $target_directory."/", }); $test_file = $target_directory."/hosts"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -522,12 +526,13 @@ sub collect_remote_data print "- Grabbing Anvil! log... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/var/log/anvil.log", destination => $target_directory."/", }); $test_file = $target_directory."/anvil.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -559,12 +564,13 @@ sub collect_remote_data # Copying the file print "Done! Copying to here... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/tmp/cib.xml", destination => $target_directory."/", }); my $test_file = $target_directory."/cib.xml"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -586,6 +592,7 @@ sub collect_remote_data { print "- Collecting server definitions... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/mnt/shared/definitions", destination => $target_directory."/", }); @@ -593,6 +600,7 @@ sub collect_remote_data print "- Collecting replicated storage config... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/etc/drbd.d", destination => $target_directory."/", }); diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host index a55e7b87..3b4d0030 100755 --- a/tools/striker-initialize-host +++ b/tools/striker-initialize-host @@ -163,7 +163,7 @@ sub add_databases $anvil->Network->get_ips({debug => 3}); $anvil->Network->get_ips({ - debug => 3, + debug => 2, target => $target, remote_user => "root", password => $anvil->data->{data}{password}, @@ -171,7 +171,7 @@ sub add_databases }); my $local_host = $anvil->Get->short_host_name(); my ($match) = $anvil->Network->find_matches({ - debug => 3, + debug => 2, first => $local_host, second => $target, source => $THIS_FILE, @@ -283,6 +283,7 @@ sub add_databases # Find a match between the target and the peer. my ($match) = $anvil->Network->find_matches({ + debug => 2, first => $target, second => $uuid, source => $THIS_FILE, diff --git a/tools/striker-manage-install-target b/tools/striker-manage-install-target index 73660356..10c5185a 100755 --- a/tools/striker-manage-install-target +++ b/tools/striker-manage-install-target @@ -709,7 +709,7 @@ sub setup_boot_environment { # Updated $anvil->Storage->change_mode({path => $kickstart_file, mode => "0664"}); - $anvil->Storage->change_owner({path => $kickstart_file, user => "apache", group => "apache" }); + $anvil->Storage->change_owner({path => $kickstart_file, user => "striker-ui-api", group => "striker-ui-api" }); print $anvil->Words->string({key => "message_0097", variables => { file => $kickstart_file }})."\n"; update_progress($anvil, $progress, "message_0097,!!file!".$kickstart_file."!!"); diff --git a/tools/striker-prep-database b/tools/striker-prep-database index 275a09ba..efe04be2 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -475,7 +475,7 @@ if ($local_uuid) ##################################################################################################### ### TODO: This will need to set the proper SELinux context. - # Apache run scripts can't call the system UUID, so we'll write it to a text file. + # striker-ui-api run scripts can't call the system UUID, so we'll write it to a text file. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::data::host_uuid" => $anvil->data->{path}{data}{host_uuid} }}); if (not -e $anvil->data->{path}{data}{host_uuid}) { @@ -483,8 +483,8 @@ if ($local_uuid) debug => 3, file => $anvil->data->{path}{data}{host_uuid}, body => $anvil->Get->host_uuid, - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", mode => "0666", overwrite => 0, }); diff --git a/tools/unfence_pacemaker b/tools/unfence_pacemaker index 1d26103c..75cae101 100755 --- a/tools/unfence_pacemaker +++ b/tools/unfence_pacemaker @@ -158,19 +158,19 @@ sub remove_constraint my $rule_found = 0; my $rule_output = ""; my $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --query"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if (($line =~ /name=$rule_name/) && ($line =~ /value=0/)) { $rule_set = 0; - to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 1}); last; } else @@ -189,33 +189,33 @@ sub remove_constraint # Clear the node attribute $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --update 0"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 3}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); } close $file_handle; # Check that the rule was set. $rule_output = ""; $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --query"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if (($line =~ /name=$rule_name/) && ($line =~ /value=0/)) { $rule_set = 0; - to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 1}); last; } else diff --git a/units/Makefile.am b/units/Makefile.am index 6c518615..d25cbf05 100644 --- a/units/Makefile.am +++ b/units/Makefile.am @@ -3,6 +3,7 @@ MAINTAINERCLEANFILES = Makefile.in servicedir = $(SYSTEMD_UNIT_DIR) dist_service_DATA = \ anvil-daemon.service \ + anvil-monitor-network.service \ anvil-safe-start.service \ scancore.service \ striker-ui-api.service diff --git a/units/anvil-monitor-network.service b/units/anvil-monitor-network.service new file mode 100644 index 00000000..9e33cd1d --- /dev/null +++ b/units/anvil-monitor-network.service @@ -0,0 +1,12 @@ +[Unit] +Description=Anvil! Intelligent Availability Platform - Network Monitor Daemon +Wants=network.target + +[Service] +Type=simple +ExecStart=/usr/sbin/anvil-monitor-network +ExecStop=/bin/kill -WINCH ${MAINPID} +Restart=always + +[Install] +WantedBy=multi-user.target