* Created Storage->backup() that makes a backup of the given file under the Anvil! backup directory with a time-stamped suffix and preserving the original directory path.

* Got anvil-configure-network writing out the new network config properly, but renaming already-active interfaces isn't working yet.
* Updated System->get_ips() to record the interface name of a given network by MAC address using 'sys::mac::<mac_address>::iface'.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 7 years ago
parent c88cbf4531
commit e4f7bcf661
  1. 1
      Anvil/Tools.pm
  2. 2
      Anvil/Tools/Database.pm
  3. 97
      Anvil/Tools/Storage.pm
  4. 19
      Anvil/Tools/System.pm
  5. 6
      share/words.xml
  6. 154
      tools/anvil-configure-network

@ -781,6 +781,7 @@ sub _set_paths
psql => "/usr/bin/psql", psql => "/usr/bin/psql",
'postgresql-setup' => "/usr/bin/postgresql-setup", 'postgresql-setup' => "/usr/bin/postgresql-setup",
pwd => "/usr/bin/pwd", pwd => "/usr/bin/pwd",
rsync => "/usr/bin/rsync",
su => "/usr/bin/su", su => "/usr/bin/su",
systemctl => "/usr/bin/systemctl", systemctl => "/usr/bin/systemctl",
touch => "/usr/bin/touch", touch => "/usr/bin/touch",

@ -1618,7 +1618,7 @@ sub insert_or_update_jobs
my $self = shift; my $self = shift;
my $parameter = shift; my $parameter = shift;
my $anvil = $self->parent; my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_jobs()" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_jobs()" }});
my $id = defined $parameter->{id} ? $parameter->{id} : ""; my $id = defined $parameter->{id} ? $parameter->{id} : "";

@ -12,6 +12,7 @@ our $VERSION = "3.0.0";
my $THIS_FILE = "Storage.pm"; my $THIS_FILE = "Storage.pm";
### Methods; ### Methods;
# backup_file
# change_mode # change_mode
# change_owner # change_owner
# check_md5sums # check_md5sums
@ -87,6 +88,102 @@ sub parent
# Public methods # # Public methods #
############################################################################################################# #############################################################################################################
=head2 backup
This will create a copy of the file under the C<< path::directories::backups >> directory with the datestamp as a suffix. The path is preserved under the backup directory. The path and file name are returned.
By default, a failure to backup will be fatal with return code C<< 1 >> for safety reasons. If the file is critical, you can set C<< fatal => 0 >> and an empty string will be returned on error.
Parameters;
=head3 fatal (optional, default 1)
If set to C<< 0 >>, any problem with the backup will be ignored and an empty string will be returned.
=head3 file (required)
This is the path and file name of the file to be backed up. Fully paths must be used.
=cut
sub backup
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2;
my $fatal = defined $parameter->{fatal} ? $parameter->{fatal} : 1;
my $source_file = defined $parameter->{file} ? $parameter->{file} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
source_file => $source_file,
fatal => $fatal,
}});
my $target_file = "";
if (not $source_file)
{
# No file passed in
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->backup()", parameter => "target" }});
if ($fatal) { $anvil->nice_exit({code => 1}); }
}
elsif ($source_file !~ /^\//)
{
# Isn't a full path
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0150", variables => { source_file => $source_file }});
if ($fatal) { $anvil->nice_exit({code => 1}); }
}
elsif (not -e $source_file)
{
# File doesn't exist.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0151", variables => { source_file => $source_file }});
if ($fatal) { $anvil->nice_exit({code => 1}); }
}
elsif (not -f $source_file)
{
# Not a file
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0153", variables => { source_file => $source_file }});
if ($fatal) { $anvil->nice_exit({code => 1}); }
}
elsif (not -r $source_file)
{
# Can't read the file.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0152", variables => { source_file => $source_file }});
if ($fatal) { $anvil->nice_exit({code => 1}); }
}
else
{
# Proceed with the backup. We'll recreate the path
my ($directory, $file) = ($source_file =~ /^(\/.*)\/(.*)$/);
my $timestamp = $anvil->Get->date_and_time({file_name => 1});
my $backup_directory = $anvil->data->{path}{directories}{backups}.$directory;
my $backup_target = $file.".".$timestamp;
$target_file = $backup_directory."/".$backup_target;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
directory => $directory,
file => $file,
timestamp => $timestamp,
backup_directory => $backup_directory,
backup_target => $backup_target,
target_file => $target_file,
}});
# Backup! It will create the target directory, if needed.
$anvil->Storage->copy_file({
source => $source_file,
target => $target_file,
debug => 2,
});
# Log that the file was backed up.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0154", variables => { source_file => $source_file, target_file => $target_file }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_file => $target_file }});
return($target_file);
}
=cut
=head2 change_mode =head2 change_mode
This changes the mode of a file or directory. This changes the mode of a file or directory.

@ -368,7 +368,13 @@ sub enable_daemon
=head2 get_ips =head2 get_ips
This method checks the local system for interfaces with IP addresses and stores them in C<< sys::network::interface::<iface_name>::ip >> and C<< sys::network::interface::<iface_name>::subnet >> This method checks the local system for interfaces and stores them in:
* C<< sys::network::interface::<iface_name>::ip >> - If an IP address is set
* C<< sys::network::interface::<iface_name>::subnet >> - If an IP is set
* C<< sys::network::interface::<iface_name>::mac >> - Always set.
To aid in look-up by MAC address, C<< sys::mac::<mac_address>::iface >> is also set.
=cut =cut
sub get_ips sub get_ips
@ -376,7 +382,7 @@ sub get_ips
my $self = shift; my $self = shift;
my $parameter = shift; my $parameter = shift;
my $anvil = $self->parent; my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->get_ips()" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->get_ips()" }});
my $in_iface = ""; my $in_iface = "";
@ -418,8 +424,13 @@ sub get_ips
} }
if ($line =~ /ether ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}) /i) if ($line =~ /ether ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}) /i)
{ {
$anvil->data->{sys}{networks}{$in_iface}{mac} = $1; my $mac = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::networks::${in_iface}::mac" => $anvil->data->{sys}{networks}{$in_iface}{mac} }}); $anvil->data->{sys}{networks}{$in_iface}{mac} = $mac;
$anvil->data->{sys}{mac}{$mac}{iface} = $in_iface;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::networks::${in_iface}::mac" => $anvil->data->{sys}{networks}{$in_iface}{mac},
"sys::mac::${mac}::iface" => $anvil->data->{sys}{mac}{$mac}{iface},
}});
} }
} }

@ -223,6 +223,12 @@ The database connection error was:
<key name="log_0147">A job to configure the network was found, and it was picked up by: [#!variable!pid!#], but that process is not running and it appears to only be: [#!variable!percent!# %] complete. Taking the job.</key> <key name="log_0147">A job to configure the network was found, and it was picked up by: [#!variable!pid!#], but that process is not running and it appears to only be: [#!variable!percent!# %] complete. Taking the job.</key>
<key name="log_0148">The network: [#!variable!network!#] has something set for the IP [#!variable!ip!#], but it appears to be invalid. Ignoring this network.</key> <key name="log_0148">The network: [#!variable!network!#] has something set for the IP [#!variable!ip!#], but it appears to be invalid. Ignoring this network.</key>
<key name="log_0149">The network: [#!variable!network!#] is not set to be configured. Skipping it.</key> <key name="log_0149">The network: [#!variable!network!#] is not set to be configured. Skipping it.</key>
<key name="log_0150">The Storage->backup() method was called with the source file: [#!variable!source_file!#], which does not appear to be a full path and file name (should start with '/').</key>
<key name="log_0151">The Storage->backup() method was called with the source file: [#!variable!source_file!#], which does not appear to exist.</key>
<key name="log_0152">The Storage->backup() method was called with the source file: [#!variable!source_file!#], which can not be read (please check permissions and SELinux).</key>
<key name="log_0153">The Storage->backup() method was called with the source file: [#!variable!source_file!#], which isn't actually a file.</key>
<key name="log_0154">The file: [#!variable!source_file!#] has been backed up as: [#!variable!target_file!#].</key>
<key name="log_0155">Removing the old network configuration file: [#!variable!file!#] as part of the network reconfiguration.</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. --> <!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key> <key name="t_0000">Test</key>

@ -120,13 +120,16 @@ sub reconfigure_network
$anvil->nice_exit({code => 2}); $anvil->nice_exit({code => 2});
} }
# Get the current list of IPs and MAC addresses.
$anvil->System->get_ips();
# Now configure the network. # 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 = defined $anvil->data->{variables}{form}{config_step2}{dns}{value} ? [split/,/, $anvil->data->{variables}{form}{config_step2}{dns}{value}] : [];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dns => $dns }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dns => $dns }});
for (my $i = 0; $i < @{$dns}; $i++) for (my $i = 0; $i < @{$dns}; $i++)
{ {
$dns->[$i] = $anvil->Words->clean_spaces({ string => $dns->[$i] }); $dns->[$i] = $anvil->Words->clean_spaces({ string => $dns->[$i] });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "dns->[$i]" => $dns->[$i] }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 = defined $anvil->data->{variables}{form}{config_step2}{gateway}{value} ? $anvil->data->{variables}{form}{config_step2}{gateway}{value} : "";
@ -215,21 +218,47 @@ sub reconfigure_network
$say_interface = "ifn".$network_count; $say_interface = "ifn".$network_count;
$interface_prefix = "IFN"; $interface_prefix = "IFN";
} }
my $bond_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bond_1"; my $say_defroute = $is_gateway ? "yes" : "no";
my $link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_2"; my $cidr = $anvil->Convert->cidr({subnet => $subnet});
my $link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1"; my $bond_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bond_1";
my $bond_uuid = get_uuid_from_interface_file($anvil, $bond_file); my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1";
my $link2_uuid = get_uuid_from_interface_file($anvil, $link2_file); my $new_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_2";
my $link1_uuid = get_uuid_from_interface_file($anvil, $link1_file); my $old_link1_file = $new_link1_file;
my $say_defroute = $is_gateway ? "yes" : "no"; my $old_link2_file = $new_link2_file;
my $cidr = $anvil->Convert->cidr({subnet => $subnet}); if ((exists $anvil->data->{sys}{mac}{$link1_mac}{iface}) && ($anvil->data->{sys}{mac}{$link1_mac}{iface}))
{
$old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{sys}{mac}{$link1_mac}{iface};
}
if ((exists $anvil->data->{sys}{mac}{$link2_mac}{iface}) && ($anvil->data->{sys}{mac}{$link2_mac}{iface}))
{
$old_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{sys}{mac}{$link2_mac}{iface};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_defroute => $say_defroute,
cidr => $cidr,
bond_file => $bond_file,
new_link2_file => $new_link2_file,
new_link1_file => $new_link1_file,
old_link1_file => $old_link1_file,
old_link2_file => $old_link2_file,
}});
# Gather (or create) UUIDs
my $bond_uuid = get_uuid_from_interface_file($anvil, $bond_file);
my $link1_uuid = get_uuid_from_interface_file($anvil, $old_link1_file);
my $link2_uuid = get_uuid_from_interface_file($anvil, $old_link2_file);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bond_uuid => $bond_uuid,
link1_uuid => $link1_uuid,
link2_uuid => $link2_uuid,
}});
### TODO: Set the firewall Zone appropriately. ### TODO: Set the firewall Zone appropriately.
# Build the Bond config. # Build the Bond config.
my $bond_config = "# $say_network - Bond 1\n"; my $bond_config = "# $say_network - Bond 1\n";
$bond_config .= "DEVICE=\"".$say_interface."_bond1\"\n";
$bond_config .= "NAME=\"".$interface_prefix." ".$network_count." - Bond 1\"\n";
$bond_config .= "UUID=\"".$bond_uuid."\"\n"; $bond_config .= "UUID=\"".$bond_uuid."\"\n";
$bond_config .= "NAME=\"".$interface_prefix." ".$network_count." - Bond 1\"\n";
$bond_config .= "DEVICE=\"".$say_interface."_bond1\"\n";
$bond_config .= "BONDING_OPTS=\"mode=active-backup primary=".$say_interface."_link1 updelay=120000 downdelay=0 miimon=100 primary_reselect=better\"\n"; $bond_config .= "BONDING_OPTS=\"mode=active-backup primary=".$say_interface."_link1 updelay=120000 downdelay=0 miimon=100 primary_reselect=better\"\n";
$bond_config .= "TYPE=\"Bond\"\n"; $bond_config .= "TYPE=\"Bond\"\n";
$bond_config .= "BONDING_MASTER=\"yes\"\n"; $bond_config .= "BONDING_MASTER=\"yes\"\n";
@ -248,12 +277,103 @@ sub reconfigure_network
} }
$bond_config .= "DEFROUTE=\"".$say_defroute."\"\n"; $bond_config .= "DEFROUTE=\"".$say_defroute."\"\n";
$bond_config .= "ZONE=\"".$say_interface."\""; $bond_config .= "ZONE=\"".$say_interface."\"";
my $link1_config = "# $say_network - Link 1\n";
$link1_config .= "HWADDR=\"".uc($link1_mac)."\"\n";
$link1_config .= "UUID=\"".$link1_uuid."\"\n";
$link1_config .= "NAME=\"".$interface_prefix." ".$network_count." - Link 1\"\n";
$link1_config .= "DEVICE=\"".$say_interface."_link1\"\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=\"".$say_interface."";
my $link2_config = "# $say_network - Link 2\n";
$link2_config .= "HWADDR=\"".uc($link2_mac)."\"\n";
$link2_config .= "UUID=\"".$link2_uuid."\"\n";
$link2_config .= "NAME=\"".$interface_prefix." ".$network_count." - Link 2\"\n";
$link2_config .= "DEVICE=\"".$say_interface."_link2\"\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=\"".$say_interface."";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bond_config => $bond_config, bond_config => $bond_config,
link1_config => $link1_config,
link2_config => $link2_config,
}}); }});
my $link1_config = ""; # Make backups of existing files
my $link2_config = ""; if (-e $bond_file) { $anvil->Storage->backup({file => $bond_file}); }
if (-e $old_link1_file) { $anvil->Storage->backup({file => $old_link1_file}); }
if (-e $old_link2_file) { $anvil->Storage->backup({file => $old_link1_file}); }
if (-e $new_link1_file) { $anvil->Storage->backup({file => $new_link1_file}); }
if (-e $new_link2_file) { $anvil->Storage->backup({file => $new_link1_file}); }
### Write out the new configs
# Bond
$anvil->Storage->write_file({
file => $bond_file,
body => $bond_config,
user => "root",
group => "root",
mode => 0644,
});
# Link 1
$anvil->Storage->write_file({
file => $new_link1_file,
body => $link1_config,
user => "root",
group => "root",
mode => 0644,
});
# Link 2
$anvil->Storage->write_file({
file => $new_link2_file,
body => $link2_config,
user => "root",
group => "root",
mode => 0644,
});
# Drop the old interfaces and remove their configs if the interface name has changed.
if ($old_link1_file ne $new_link1_file)
{
# Doesn't match, unlink the old file.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "log_0155", variables => { file => $old_link1_file }});
unlink $old_link1_file;
# Stop the old network interface and rename it.
my $old_iface = $anvil->data->{sys}{mac}{$link1_mac}{iface};
my $new_iface = $say_interface."_link1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_iface => $old_iface,
new_iface => $new_iface,
}});
### TODO: This isn't working for already-active interfaces... Says the new interface can't be found.
# Drop the old interface
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_iface." down"});
# Rename it
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_iface." name ".$new_iface});
# Bring up the interface with the new name
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_iface." up"});
}
} }
elsif ((exists $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}) && ($anvil->Validate->is_mac({mac => $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}}))) elsif ((exists $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}) && ($anvil->Validate->is_mac({mac => $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}})))
{ {
@ -269,6 +389,8 @@ sub reconfigure_network
} }
} }
} }
# Reload the network
return(0); return(0);
} }

Loading…
Cancel
Save