You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2016/07/18 22:34:21 UTC
svn commit: r1753324 - /vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
Author: arkurth
Date: Mon Jul 18 22:34:21 2016
New Revision: 1753324
URL: http://svn.apache.org/viewvc?rev=1753324&view=rev
Log:
VCL-961
Added subroutines to Linux.pm:
get_ifcfg_file_info
get_network_bridge_info
Rewrote Linux.pm::enable_dhcp. It now checks if an interface is bridged and does not overwrite bridge or most other custom configurations. It selectively removes certain parameters which are specific to a particular network or computer.
Added ifcfg-* backup files to $CAPTURE_DELETE_FILE_PATHS to prevent backups from accumulating. When an image is captured, a single backup should remain since enable_dhcp is called after clean_known_files.
Modified:
vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=1753324&r1=1753323&r2=1753324&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Mon Jul 18 22:34:21 2016
@@ -102,6 +102,7 @@ our $CAPTURE_DELETE_FILE_PATHS = [
'/root/.ssh/id_rsa.pub',
'/etc/sysconfig/iptables*old*',
'/etc/sysconfig/iptables_pre*',
+ '/etc/sysconfig/network-scripts/ifcfg-*.20*-*',
'/etc/udev/rules.d/70-persistent-net.rules',
'/var/log/*.0',
'/var/log/*.gz',
@@ -406,8 +407,12 @@ sub pre_capture {
}
# Configure the private and public interfaces to use DHCP
- if (!$self->enable_dhcp()) {
- notify($ERRORS{'WARNING'}, 0, "failed to enable DHCP on the public and private interfaces");
+ if (!$self->enable_dhcp($self->get_private_interface_name())) {
+ notify($ERRORS{'WARNING'}, 0, "failed to enable DHCP on the private interface");
+ return;
+ }
+ if (!$self->enable_dhcp($self->get_public_interface_name())) {
+ notify($ERRORS{'WARNING'}, 0, "failed to enable DHCP on the public interface");
return;
}
@@ -3287,55 +3292,218 @@ sub enable_dhcp {
my $computer_node_name = $self->data->get_computer_node_name();
- my $interface_name_argument = shift;
- my @interface_names;
- if (!$interface_name_argument) {
- push(@interface_names, $self->get_private_interface_name());
- push(@interface_names, $self->get_public_interface_name());
+ my $interface_name = shift;
+ if (!$interface_name) {
+ notify($ERRORS{'WARNING'}, 0, "interface name argument was not supplied");
+ return;
}
- elsif ($interface_name_argument =~ /private/i) {
- push(@interface_names, $self->get_private_interface_name());
+
+ my $calling_subroutine = get_calling_subroutine();
+
+ my $ifcfg_directory_path = "/etc/sysconfig/network-scripts";
+ my $ifcfg_file_name = "ifcfg-$interface_name";
+ my $ifcfg_file_path = "$ifcfg_directory_path/$ifcfg_file_name";
+
+ if ($self->file_exists($ifcfg_file_path)) {
+ my $timestamp = POSIX::strftime("%Y-%m-%d_%H-%M-%S\n", localtime);
+ my $ifcfg_backup_file_path = "$ifcfg_directory_path/$ifcfg_file_name.$timestamp";
+ $self->copy_file($ifcfg_file_path, $ifcfg_backup_file_path);
}
- elsif ($interface_name_argument =~ /public/i) {
- push(@interface_names, $self->get_public_interface_name());
+
+ my $ifcfg_file_info = $self->get_ifcfg_file_info($interface_name) || {};
+
+ if ($calling_subroutine !~ /enable_dhcp/) {
+ # Check if interface is configured as a bridge
+ my @bridge_interface_names;
+ if ($ifcfg_file_info->{BRIDGE}) {
+ push @bridge_interface_names, $ifcfg_file_info->{BRIDGE};
+ }
+ elsif ($ifcfg_file_info->{TYPE} && $ifcfg_file_info->{TYPE} =~ /Bridge/i) {
+ # For ifcfg-br* files, the name of the physical interface usually isn't listed in the file
+ # Get the network bridge info
+ my $network_bridge_info = $self->get_network_bridge_info();
+ if (defined($network_bridge_info) && defined($network_bridge_info->{$interface_name})) {
+ @bridge_interface_names = @{$network_bridge_info->{$interface_name}{interfaces}};
+ }
+ }
+ for my $bridge_interface_name (@bridge_interface_names) {
+ # Make sure the bridge isn't the same name as the interface being checked to avoid recurive loop
+ next if ($bridge_interface_name eq $interface_name);
+
+ notify($ERRORS{'DEBUG'}, 0, "$interface_name is bridged, attempting to enable DHCP on bridge interface: $bridge_interface_name");
+ $self->enable_dhcp($bridge_interface_name) || return;
+ }
}
- else {
- push(@interface_names, $interface_name_argument);
+
+ # Add/overwrite required parameters to file contents
+ my $set_parameters = {
+ 'BOOTPROTO' => 'dhcp',
+ 'DEVICE' => $interface_name,
+ 'NAME' => $interface_name,
+ 'ONBOOT' => 'yes',
+ };
+ for my $parameter (keys %$set_parameters) {
+ my $value = $set_parameters->{$parameter};
+ $ifcfg_file_info->{$parameter} = $value;
+ }
+
+ # Remove parameters which are specific to a particular network or computer
+ my @remove_parameter_patterns = (
+ 'ADDR',
+ 'BROADCAST',
+ 'DNS',
+ 'GATEWAY',
+ 'HOSTNAME',
+ 'METRIC',
+ 'NETMASK',
+ 'NETWORK',
+ 'PREFIX',
+ 'UUID',
+ );
+ for my $remove_pattern (@remove_parameter_patterns) {
+ my @matching_properties = grep { $_ =~ /.*$remove_pattern.*/ } sort keys %$ifcfg_file_info;
+ if (@matching_properties) {
+ notify($ERRORS{'DEBUG'}, 0, "removing parameters from ifcfg-$interface_name file matching pattern '$remove_pattern': " . join(', ', @matching_properties));
+ map { delete $ifcfg_file_info->{$_} } @matching_properties;
+ }
}
- for my $interface_name (@interface_names) {
- my $ifcfg_file_path = "/etc/sysconfig/network-scripts/ifcfg-$interface_name";
- notify($ERRORS{'DEBUG'}, 0, "attempting to enable DHCP on interface: $interface_name\nifcfg file path: $ifcfg_file_path");
-
- my $ifcfg_file_contents = <<EOF;
-DEVICE=$interface_name
-BOOTPROTO=dhcp
-ONBOOT=yes
-EOF
-
- # Remove any Windows carriage returns
- $ifcfg_file_contents =~ s/\r//g;
-
- # Remove the last newline
- $ifcfg_file_contents =~ s/\n$//s;
-
- # Write the contents to the ifcfg file
- if ($self->create_text_file($ifcfg_file_path, $ifcfg_file_contents)) {
- notify($ERRORS{'DEBUG'}, 0, "updated $ifcfg_file_path:\n" . string_to_ascii($ifcfg_file_contents));
+ # Convert the parameter/value hash to a string
+ my $updated_ifcfg_contents;
+ for my $parameter (sort keys %$ifcfg_file_info) {
+ my $value = $ifcfg_file_info->{$parameter};
+ $updated_ifcfg_contents .= "$parameter=$value\n";
+ }
+
+ # Create the text file
+ notify($ERRORS{'DEBUG'}, 0, "updated ifcfg-$interface_name contents:\n$updated_ifcfg_contents");
+ return $self->create_text_file($ifcfg_file_path, $updated_ifcfg_contents);
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+=head2 get_ifcfg_file_info
+
+ Parameters : $interface_name
+ Returns : hash reference
+ Description : Parses the file:
+ /etc/sysconfig/network-scripts/ifcfg-<interface name>
+
+ A hash is constructed such as:
+ {
+ "BOOTPROTO" => "dhcp",
+ "DEVICE" => "eth0",
+ "ONBOOT" => "yes"
+ }
+
+ The hash key names are guaranteed to be uppercase.
+
+=cut
+
+sub get_ifcfg_file_info {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my $interface_name = shift;
+ if (!$interface_name) {
+ notify($ERRORS{'WARNING'}, 0, "interface name argument was not supplied");
+ return;
+ }
+
+ my $ifcfg_file_path = "/etc/sysconfig/network-scripts/ifcfg-$interface_name";
+
+ my $info = {};
+ my @lines = $self->get_file_contents($ifcfg_file_path);
+ for my $line (@lines) {
+ next if $line =~ /^\s*#/;
+ my ($property, $value) = $line =~ /^\s*([^=]+)\s*=\s*(.*)\s*$/g;
+ if (defined($property)) {
+ $info->{uc($property)} = $value;
}
else {
- notify($ERRORS{'WARNING'}, 0, "failed to update $ifcfg_file_path");
- return;
+ notify($ERRORS{'WARNING'}, 0, "failed to parse line from $ifcfg_file_path: '$line'");
+ }
+ }
+
+ notify($ERRORS{'DEBUG'}, 0, "parsed $ifcfg_file_path:\n" . format_data($info));
+ return $info;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+=head2 get_network_bridge_info
+
+ Parameters : none
+ Returns : hash reference
+ Description : Executes 'brctl show' and parses the output. A hash is
+ constructed:
+ {
+ "br1" => {
+ "bridge_id" => "",
+ "interfaces" => [
+ "eth1",
+ "eth2"
+ ],
+ "stp_enabled" => ""
+ }
+ }
+
+=cut
+
+sub get_network_bridge_info {
+ my $self = shift;
+ if (ref($self) !~ /VCL::Module/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my $computer_name = $self->data->get_computer_short_name();
+
+ # It's possible that a bridge will have multiple interfaces:
+ # [root@bn19-183 network-scripts]# brctl show
+ # bridge name bridge id STP enabled interfaces
+ # br1 8000.000c29494c97 no eth1
+ # eth2
+
+ my $command = "brctl show";
+ my ($exit_status, $output) = $self->execute($command);
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute command on $computer_name: $command");
+ return;
+ }
+ elsif ($exit_status ne '0') {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve network bridge configuration from $computer_name, exit status: $exit_status, command:\n$command\noutput:\n" . join("\n", @$output));
+ return 0;
+ }
+
+ my $network_bridge_info = {};
+ my $current_bridge_name;
+ for my $line (@$output) {
+ my ($bridge_name, $bridge_id, $stp_enabled, $interface_name) = $line =~ /^([^\s]*)\s+([^\s]*)\s+([^\s]*)\s+([^\s]+)\s*$/g;
+ if (!defined($interface_name)) {
+ notify($ERRORS{'DEBUG'}, 0, "ignoring line, interface name was not found: '$line'");
+ next;
}
- # Remove any leftover ifcfg-*.bak files
- $self->delete_file('/etc/sysconfig/network-scripts/ifcfg-eth*.bak');
+ if ($bridge_name) {
+ $current_bridge_name = $bridge_name;
+ }
+ elsif (!$current_bridge_name) {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve network bridge configuration from $computer_name, bridge name unknown\n" .
+ "line: '$line'\n" .
+ "output:\n" . join("\n", @$output)
+ );
+ return;
+ }
- # Remove dhclient lease files
- $self->delete_file('/var/lib/dhclient/*.leases');
+ $network_bridge_info->{$current_bridge_name}{bridge_id} = $bridge_id if defined($bridge_id);
+ $network_bridge_info->{$current_bridge_name}{stp_enabled} = $bridge_id if defined($stp_enabled);
+ push @{$network_bridge_info->{$current_bridge_name}{interfaces}}, $interface_name if defined($interface_name);
}
- return 1;
+ notify($ERRORS{'OK'}, 0, "retrieved network bridge configuration from $computer_name:" . format_data($network_bridge_info));
+ return $network_bridge_info;
}
#/////////////////////////////////////////////////////////////////////////////
@@ -6660,6 +6828,9 @@ sub mount_nfs_share {
# dmesg | tail or so
if (!$self->command_exists('mount.nfs')) {
$self->install_package('nfs-utils');
+
+ # On Ubuntu:
+ $self->install_package('nfs-common');
}
# Check if the rpcbind service exists, if not, try to install it