Author: arkurth
Date: Tue Jul 19 20:56:54 2016
New Revision: 1753423

URL: http://svn.apache.org/viewvc?rev=1753423&view=rev
Log:
VCL-961
Added generate_ifcfg_file subroutines to Linux.pm. Updated enable_dhcp and 
set_static_public_address to use it.

Reworked Linux.pm::set_static_public_address to not simply overwrite the 
ifcfg-* file. Changed set_static_public_address to use set_default_gateway and 
update_resolv_conf subroutines rather than using duplicated code.

Updated Linux.pm::get_network_configuration to retrieve network bridge 
information and add it to the hash returned. Updated 
OS.pm::get_public_interface_name to check if the configuration for an interface 
contains a 'master' key indicating that the interface is a slave -- usually 
because it is bridged. If this key is set then the interface isn't considered.

Fixed some regex/parsing issues with Linux.pm::get_network_bridge_info.


VCL-970
Added code to create a route-* file in Linux.pm::set_default_gateway so that 
the default gateway persists across reboots. Also added code to enable_dhcp to 
delete an interface's route-* file.


VCL-969
Added code to Linux.pm::pre_capture to disable the 'firstboot' service if it 
exists.

Modified:
    vcl/trunk/managementnode/lib/VCL/Module/OS.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS.pm?rev=1753423&r1=1753422&r2=1753423&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS.pm Tue Jul 19 20:56:54 2016
@@ -1718,6 +1718,7 @@ sub get_public_interface_name {
        INTERFACE: for my $check_interface_name (sort keys 
%$network_configuration) {
                
                my $description = 
$network_configuration->{$check_interface_name}{description} || '';
+               my $master = 
$network_configuration->{$check_interface_name}{master};
                
                # Check if the interface should be ignored based on the name or 
description
                if ($check_interface_name =~ /^(lo|sit\d)$/i) {
@@ -1732,6 +1733,10 @@ sub get_public_interface_name {
                        notify($ERRORS{'DEBUG'}, 0, "interface 
'$check_interface_name' ignored because its description contains '$1'");
                        next INTERFACE;
                }
+               elsif ($master) {
+                       notify($ERRORS{'DEBUG'}, 0, "interface 
'$check_interface_name' ignored because it is a slave to $master");
+                       next INTERFACE;
+               }
                
                # If $public_interface_name hasn't been set yet, set it and 
continue checking the next interface
                if (!$public_interface_name) {
@@ -1764,7 +1769,7 @@ sub get_public_interface_name {
                        }
                        else {
                                # Does not match private IP address
-                               notify($ERRORS{'DEBUG'}, 0, 
"'$check_interface_name' could potententially be public interface, not assigned 
private IP address");
+                               notify($ERRORS{'DEBUG'}, 0, 
"'$check_interface_name' could potentially be public interface, not assigned 
private IP address");
                                $public_interface_name = $check_interface_name;
                        }
                        

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=1753423&r1=1753422&r2=1753423&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Tue Jul 19 20:56:54 2016
@@ -102,8 +102,8 @@ 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',
+       '/tmp/ifcfg-*',
        '/var/log/*.0',
        '/var/log/*.gz',
 ];
@@ -390,6 +390,11 @@ sub pre_capture {
        # This is useful for troubleshooting image problems
        $self->set_password("root", $WINDOWS_ROOT_PASSWORD);
        
+       # Prevent the "Text Mode Setup Utility" - "Choose a Tool" screen from 
appearing
+       if ($self->service_exists('firstboot')) {
+               $self->disable_service('firstboot');
+       }
+       
        if (!$self->configure_default_sshd()) {
                return;
        }
@@ -824,212 +829,113 @@ sub set_static_public_address {
                return 0;
        }
        
-       my $computer_name           = $self->data->get_computer_short_name();
-       my $server_request_id       = $self->data->get_server_request_id();
+       my $computer_name = $self->data->get_computer_short_name();
+       my $ip_configuration = 
$self->data->get_management_node_public_ip_configuration();
+       my $public_ip_address = $self->data->get_computer_public_ip_address();
+       my $subnet_mask = $self->data->get_management_node_public_subnet_mask();
+       my $default_gateway = 
$self->data->get_management_node_public_default_gateway();
+       my @dns_servers = $self->data->get_management_node_public_dns_servers();
+       
+       # TODO: Get this out of here. OS modules shouldn't have to figure this 
out. $self->data should always return correct value.
        my $server_request_fixed_ip = 
$self->data->get_server_request_fixed_ip();
+       if ($server_request_fixed_ip) {
+               $public_ip_address = $server_request_fixed_ip;
+               $subnet_mask = $self->data->get_server_request_netmask();
+               $default_gateway = $self->data->get_server_request_router();
+               @dns_servers = $self->data->get_server_request_dns_servers();
+       }
        
        # Make sure public IP configuration is static or this is a server 
request
-       
-       my $ip_configuration = 
$self->data->get_management_node_public_ip_configuration();
-       if ($ip_configuration !~ /static/i) {
-               if (!$server_request_fixed_ip) {
-                       notify($ERRORS{'WARNING'}, 0, "static public address 
can only be set if IP configuration is static or is a server request, current 
value: $ip_configuration \nserver_request_fixed_ip=$server_request_fixed_ip");
-                       return;
-               }
+       if ($ip_configuration !~ /static/i && !$server_request_fixed_ip) {
+               notify($ERRORS{'WARNING'}, 0, "management node IP configuration 
is $ip_configuration, static public IP address can only be set if the IP 
configuration is static or if a fixed IP was requested");
+               return;
        }
-       
-       # Get the IP configuration
-       my $interface_name  = $self->get_public_interface_name();
-       if (!$interface_name) {
-               notify($ERRORS{'WARNING'}, 0, "unable to set static public IP 
address, public interface name could not be determined");
+       elsif (!$public_ip_address) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve public IP 
address to assign to $computer_name");
                return;
        }
-       
-       my $computer_public_ip_address  = 
$self->data->get_computer_public_ip_address()             || '<undefined>';
-       my $subnet_mask                 = 
$self->data->get_management_node_public_subnet_mask()     || '<undefined>';
-       my $default_gateway             = 
$self->data->get_management_node_public_default_gateway() || '<undefined>';
-       my @dns_servers                 = 
$self->data->get_management_node_public_dns_servers();
-       
-       if ($server_request_fixed_ip) {
-               $computer_public_ip_address  = $server_request_fixed_ip;
-               $subnet_mask                 = 
$self->data->get_server_request_netmask();
-               $default_gateway             = 
$self->data->get_server_request_router();
-               @dns_servers                 = 
$self->data->get_server_request_dns_servers();
+       elsif (!$subnet_mask) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve public subnet 
mask to assign to $computer_name");
+               return;
+       }
+       elsif (!$default_gateway) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve default 
gateway to assign to $computer_name");
+               return;
        }
        
-       # Assemble a string containing the static IP configuration
-       my $configuration_info_string = <<EOF;
-public IP address: $computer_public_ip_address
-public subnet mask: $subnet_mask
-public default gateway: $default_gateway
-public DNS server(s): @dns_servers
-EOF
-       
+       # Determine the public interface name
+       my $public_interface_name  = $self->get_public_interface_name();
+       if (!$public_interface_name) {
+               notify($ERRORS{'WARNING'}, 0, "unable to set static public IP 
address, public interface name could not be determined");
+               return;
+       }
+
        # Get the current public IP address being used by the computer
        # Use cached data if available (0), ignore errors (1)
        my $current_public_ip_address = $self->get_public_ip_address(0, 1);
-       if ($current_public_ip_address && $current_public_ip_address eq 
$computer_public_ip_address) {
+       if ($current_public_ip_address && $current_public_ip_address eq 
$public_ip_address) {
                notify($ERRORS{'DEBUG'}, 0, "static public IP address does not 
need to be set, $computer_name is already configured to use 
$current_public_ip_address");
        }
        else {
                if ($current_public_ip_address) {
-                       notify($ERRORS{'DEBUG'}, 0, "static public IP address 
needs to be set, public IP address currently being used by $computer_name 
$current_public_ip_address does NOT match correct public IP address: 
$computer_public_ip_address");
+                       notify($ERRORS{'DEBUG'}, 0, "static public IP address 
needs to be set, public IP address currently being used by $computer_name 
$current_public_ip_address does NOT match correct public IP address: 
$public_ip_address");
                }
                else {
                        notify($ERRORS{'DEBUG'}, 0, "static public IP address 
needs to be set, unable to determine public IP address currently in use on 
$computer_name");
                }
                
-               # Make sure required info was retrieved
-               if ("$computer_public_ip_address $subnet_mask $default_gateway" 
=~ /undefined/) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to retrieve 
required network configuration for 
$computer_name:\n$configuration_info_string");
-                       return;
-               }
-               else {
-                       notify($ERRORS{'OK'}, 0, "attempting to set static 
public IP address on $computer_name:\n$configuration_info_string");
-               }
                
                # Try to ping address to make sure it's available
                # FIXME  -- need to add other tests for checking ip_address is 
or is not available.
-               if ((_pingnode($computer_public_ip_address))) {
-                       notify($ERRORS{'WARNING'}, 0, "ip_address 
$computer_public_ip_address is pingable, can not assign to $computer_name ");
+               if (_pingnode($public_ip_address)) {
+                       notify($ERRORS{'CRITICAL'}, 0, "ip_address 
$public_ip_address is pingable, can not assign to $computer_name ");
                        return;
                }
                
-               # Assemble the ifcfg file path
-               my $network_scripts_path = "/etc/sysconfig/network-scripts";
-               my $ifcfg_file_path      = 
"$network_scripts_path/ifcfg-$interface_name";
-               notify($ERRORS{'DEBUG'}, 0, "public interface ifcfg file path: 
$ifcfg_file_path");
+               notify($ERRORS{'DEBUG'}, 0, "attempting to set static public IP 
address on $computer_name:\n" .
+                       "interface: $public_interface_name\n" .
+                       "IP address: $public_ip_address\n" .
+                       "subnet mask: $subnet_mask\n" .
+                       "default gateway: $default_gateway"
+               );
                
-               # Assemble the ifcfg file contents
-               my $ifcfg_contents = <<EOF;
-DEVICE=$interface_name
-BOOTPROTO=static
-IPADDR=$computer_public_ip_address
-NETMASK=$subnet_mask
-GATEWAY=$default_gateway
-STARTMODE=onboot
-ONBOOT=yes
-EOF
-       
-               # Echo the contents to the ifcfg file
-               my $echo_ifcfg_command = "echo \"$ifcfg_contents\" > 
$ifcfg_file_path";
-               my ($echo_ifcfg_exit_status, $echo_ifcfg_output) = 
$self->execute($echo_ifcfg_command);
-               if (!defined($echo_ifcfg_output)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to run command to 
recreate $ifcfg_file_path on $computer_name: '$echo_ifcfg_command'");
-                       return;
-               }
-               elsif ($echo_ifcfg_exit_status || grep(/echo:/i, 
@$echo_ifcfg_output)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to recreate 
$ifcfg_file_path on $computer_name, exit status: $echo_ifcfg_exit_status, 
command: '$echo_ifcfg_command', output:\n" . join("\n", @$echo_ifcfg_output));
+               my $ifcfg_parameters = {
+                       bootproto => 'static',
+                       ipaddr => $public_ip_address,
+                       netmask => $subnet_mask,
+                       gateway => $default_gateway,
+               };
+               
+               if (!$self->generate_ifcfg_file($public_interface_name, 
$ifcfg_parameters)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to set static 
public IP address on $computer_name, ifcfg file could not be created");
                        return;
                }
-               else {
-                       notify($ERRORS{'DEBUG'}, 0, "recreated $ifcfg_file_path 
on $computer_name:\n$ifcfg_contents");
-               }
                
                # Restart the interface
-               if (!$self->restart_network_interface($interface_name)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to restart public 
interface $interface_name on $computer_name");
+               if (!$self->restart_network_interface($public_interface_name)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to restart public 
interface $public_interface_name on $computer_name");
                        return;
                }
-               
-               my $ext_sshd_config_file_path = '/etc/ssh/external_sshd_config';
-               if ($self->file_exists($ext_sshd_config_file_path)) {
-                       # Remove existing ListenAddress lines from 
external_sshd_config
-                       
$self->remove_lines_from_file($ext_sshd_config_file_path, 'ListenAddress') || 
return;
-                       
-                       # Add ListenAddress line to the end of the file
-                       $self->append_text_file($ext_sshd_config_file_path, 
"ListenAddress $computer_public_ip_address\n") || return;
-               }
        }
        
-       # Delete existing default route
-       my $route_del_command = "/sbin/route del default";
-       my ($route_del_exit_status, $route_del_output) = 
$self->execute($route_del_command);
-       if (!defined($route_del_output)) {
-               notify($ERRORS{'WARNING'}, 0, "failed to run command to delete 
the existing default route on $computer_name: '$route_del_command'");
-               return;
-       }
-       elsif (grep(/No such process/i, @$route_del_output)) {
-               notify($ERRORS{'DEBUG'}, 0, "existing default route is not 
set");
-       }
-       elsif ($route_del_exit_status) {
-               notify($ERRORS{'WARNING'}, 0, "failed to delete existing 
default route on $computer_name, exit status: $route_del_exit_status, command: 
'$route_del_command', output:\n" . join("\n", @$route_del_output));
+       # Set default gateway
+       if (!$self->set_default_gateway($default_gateway, 
$public_interface_name)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to set static public IP 
address on $computer_name, default gateway could not be set");
                return;
        }
-       else {
-               notify($ERRORS{'DEBUG'}, 0, "deleted existing default route on 
$computer_name, output:\n" . join("\n", @$route_del_output));
-       }
-       
-       # Set default route
-       my $route_add_command = "/sbin/route add default gw $default_gateway 
metric 0 $interface_name 2>&1 && /sbin/route -n";
-       my ($route_add_exit_status, $route_add_output) = 
$self->execute($route_add_command);
-       if (!defined($route_add_output)) {
-               notify($ERRORS{'WARNING'}, 0, "failed to run command to add 
default route to $default_gateway on public interface $interface_name on 
$computer_name: '$route_add_command'");
-               return;
-       }
-       elsif ($route_add_exit_status) {
-               notify($ERRORS{'WARNING'}, 0, "failed to add default route to 
$default_gateway on public interface $interface_name on $computer_name, exit 
status: $route_add_exit_status, command: '$route_add_command', output:\n" . 
join("\n", @$route_add_output));
-               return;
-       }
-       else {
-               notify($ERRORS{'DEBUG'}, 0, "added default route to 
$default_gateway on public interface $interface_name on $computer_name, 
output:\n" . format_data($route_add_output));
-       }
        
        # Update resolv.conf if DNS server address is configured for the 
management node
-       my $resolv_conf_path = "/etc/resolv.conf";
        if (@dns_servers) {
-               # Get the resolve.conf contents
-               my $cat_resolve_command = "cat $resolv_conf_path";
-               my ($cat_resolve_exit_status, $cat_resolve_output) = 
$self->execute($cat_resolve_command);
-               if (!defined($cat_resolve_output)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to run command to 
retrieve existing $resolv_conf_path contents from $computer_name");
-                       return;
-               }
-               elsif ($cat_resolve_exit_status || grep(/^(bash:|cat:)/, 
@$cat_resolve_output)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to retrieve 
existing $resolv_conf_path contents from $computer_name, exit status: 
$cat_resolve_exit_status, command: '$cat_resolve_command', output:\n" . 
join("\n", @$cat_resolve_output));
-                       return;
-               }
-               else {
-                       notify($ERRORS{'DEBUG'}, 0, "retrieved existing 
$resolv_conf_path contents from $computer_name:\n" . join("\n", 
@$cat_resolve_output));
-               }
-               
-               # Remove lines containing nameserver
-               my @resolv_conf_lines = grep(!/nameserver/i, 
@$cat_resolve_output);
-               
-               # Add a nameserver line for each configured DNS server
-               for my $dns_server_address (@dns_servers) {
-                       push @resolv_conf_lines, "nameserver 
$dns_server_address";
-               }
-               
-               # Remove newlines for consistency
-               map {chomp $_} @resolv_conf_lines;
-               
-               # Assemble the lines into an array
-               my $resolv_conf_contents = join("\n", @resolv_conf_lines);
-               
-               # Echo the updated contents to resolv.conf
-               my $echo_resolve_command = "echo \"$resolv_conf_contents\" > 
$resolv_conf_path 2>&1 && cat $resolv_conf_path";
-               my ($echo_resolve_exit_status, $echo_resolve_output) = 
$self->execute($echo_resolve_command);
-               if (!defined($echo_resolve_output)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to run command to 
update $resolv_conf_path on $computer_name:\n$echo_resolve_command");
+               if (!$self->update_resolv_conf(@dns_servers)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to set static 
public IP address on $computer_name, DNS servers could not be configured");
                        return;
                }
-               elsif ($echo_resolve_exit_status) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to update 
$resolv_conf_path on $computer_name, exit status: 
$echo_resolve_exit_status\ncommand:\n$echo_resolve_command\noutput:\n" . 
join("\n", @$echo_resolve_output));
-                       return;
-               }
-               else {
-                       notify($ERRORS{'DEBUG'}, 0, "updated $resolv_conf_path 
on $computer_name:\n" . join("\n", @$echo_resolve_output));
-               }
-       }
-       else {
-               notify($ERRORS{'DEBUG'}, 0, "$resolv_conf_path not updated  on 
$computer_name because DNS server address is not configured for the management 
node");
        }
        
        # Delete cached network configuration info - forces next call to 
get_network_configuration to retrieve changed network info from computer
        delete $self->{network_configuration};
        
-       notify($ERRORS{'OK'}, 0, "successfully set static public IP address on 
$computer_name");
+       notify($ERRORS{'OK'}, 0, "set static public IP address on 
$computer_name");
        return 1;
 }
 
@@ -1260,10 +1166,13 @@ sub set_default_gateway {
                notify($ERRORS{'WARNING'}, 0, "failed to set default gateway on 
$computer_name to $default_gateway, interface: $interface_name, exit status: 
$exit_status, command:\n$command\noutput:\n" . join("\n", @$output));
                return 0;
        }
-       else {
-               notify($ERRORS{'OK'}, 0, "set default gateway on $computer_name 
to $default_gateway, interface: $interface_name");
-       }
        
+       # Create a route file so default route persists across reboots
+       my $route_file_path = 
"/etc/sysconfig/network-scripts/route-$interface_name";
+       my $route_file_contents = "default via $default_gateway dev 
$interface_name";
+       $self->create_text_file($route_file_path, $route_file_contents);
+       
+       notify($ERRORS{'OK'}, 0, "set default gateway on $computer_name to 
$default_gateway, interface: $interface_name");
        return 1;
 }
 
@@ -2616,12 +2525,39 @@ EOF
  Description : Retrieves the network configuration on the Linux computer and
                constructs a hash. The hash reference returned is formatted as
                follows:
-               |--%{eth0}
-                  |--%{eth0}{default_gateway} '10.10.4.1'
-                  |--%{eth0}{ip_address}
-                     |--{eth0}{ip_address}{10.10.4.3} = '255.255.240.0'
-                  |--{eth0}{name} = 'eth0'
-                  |--{eth0}{physical_address} = '00:50:56:08:00:f8'
+               {
+                 "eth0" => {
+                   "broadcast_address" => "10.25.15.255",
+                   "ip_address" => {
+                     "10.25.10.194" => "255.255.240.0"
+                   },
+                   "name" => "eth0",
+                   "physical_address" => "00:50:56:23:00:bc"
+                 },
+                 "eth1" => {
+                   "name" => "eth1",
+                   "physical_address" => "00:50:56:23:00:bd"
+                 },
+                 "lo" => {
+                   "name" => "lo"
+                 },
+                 "xbr1" => {
+                   "bridge" => {
+                     "bridge_id" => "8000.0050562300bd",
+                     "interfaces" => [
+                       "eth1"
+                     ],
+                     "stp_enabled" => "8000.0050562300bd"
+                   },
+                   "broadcast_address" => "192.168.53.255",
+                   "default_gateway" => "192.168.53.254",
+                   "ip_address" => {
+                     "152.46.18.135" => "255.255.248.0"
+                   },
+                   "name" => "xbr1",
+                   "physical_address" => "00:50:56:23:00:bd"
+                 }
+               }
 
 =cut
 
@@ -2687,9 +2623,9 @@ sub get_network_configuration {
                        
$network_configuration->{$interface_name}{ip_address}{$1} = $2;
                        
$network_configuration->{$interface_name}{broadcast_address} = $3;
                }
-
        }
        
+       
        # Run route
        my $route_command = "/sbin/route -n";
        my ($route_exit_status, $route_output) = $self->execute($route_command);
@@ -2717,6 +2653,34 @@ sub get_network_configuration {
                }
        }
        
+       # Check if bridge is configured
+       my $network_bridge_info = $self->get_network_bridge_info();
+       for my $bridge_name (keys %$network_bridge_info) {
+               # Add bridge info under 'bridge' key for the bridge
+               if (defined($network_configuration->{$bridge_name})) {
+                       $network_configuration->{$bridge_name}{bridge} = 
$network_bridge_info->{$bridge_name};
+               }
+               else {
+                       notify($ERRORS{'WARNING'}, 0, "'$bridge_name' bridge 
was not found in 'ifconfig' output:" .
+                               "ifconfig output:\n" . join("\n", 
@$ifconfig_output) . "\n" .
+                               "network bridge info:\n" . 
format_data($network_bridge_info)
+                       );
+               }
+               
+               # Add name of bridge to 'master' key for the physical interface
+               for my $bridge_interface_name 
(@{$network_bridge_info->{$bridge_name}{interfaces}}) {
+                       if 
(defined($network_configuration->{$bridge_interface_name})) {
+                               
$network_configuration->{$bridge_interface_name}{master} = $bridge_name;
+                       }
+                       else {
+                               notify($ERRORS{'WARNING'}, 0, "'$bridge_name' 
bridge contains '$bridge_interface_name' interface but '$bridge_interface_name' 
was not found in 'ifconfig' output:\n" .
+                                       "ifconfig output:\n" . join("\n", 
@$ifconfig_output) . "\n" .
+                                       "network bridge info:\n" . 
format_data($network_bridge_info)
+                               );
+                       }
+               }
+       }
+       
        $self->{network_configuration} = $network_configuration;
        #can produce large output, if you need to monitor the configuration 
setting uncomment the below output statement
        notify($ERRORS{'DEBUG'}, 0, "retrieved network configuration:\n" . 
format_data($self->{network_configuration}));
@@ -3274,12 +3238,10 @@ sub is_file_on_local_disk {
 #/////////////////////////////////////////////////////////////////////////////
 =head2 enable_dhcp
 
- Parameters  : $interface_name (optional)
+ Parameters  : $interface_name
  Returns     : boolean
- Description : Configures the ifcfg-* file(s) to use DHCP. If an interface name
-               argument is specified, only the ifcfg file for that interface
-               will be configured. If no argument is specified, the files for
-               the public and private interfaces will be configured.
+ Description : Configures the ifcfg-* file for the specified interface to use
+               DHCP.
 
 =cut
 
@@ -3290,7 +3252,7 @@ sub enable_dhcp {
                return;
        }
        
-       my $computer_node_name = $self->data->get_computer_node_name();
+       my $computer_name = $self->data->get_computer_node_name();
        
        my $interface_name = shift;
        if (!$interface_name) {
@@ -3298,27 +3260,21 @@ sub enable_dhcp {
                return;
        }
        
-       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);
-       }
+       # Delete existing static route file for the interface if one exists
+       
$self->delete_file("/etc/sysconfig/network-scripts/route-$interface_name");
        
        my $ifcfg_file_info = $self->get_ifcfg_file_info($interface_name) || {};
        
+       my $calling_subroutine = get_calling_subroutine();
        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};
+               if ($ifcfg_file_info->{bridge}) {
+                       # ifcfg file contains something like: BRIDGE=br1
+                       push @bridge_interface_names, 
$ifcfg_file_info->{bridge};
                }
-               elsif ($ifcfg_file_info->{TYPE} && $ifcfg_file_info->{TYPE} =~ 
/Bridge/i) {
+               elsif ($ifcfg_file_info->{type} && $ifcfg_file_info->{type} =~ 
/Bridge/i) {
+                       # ifcfg file contains something like: TYPE=Bridge
                        # 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();
@@ -3335,30 +3291,73 @@ sub enable_dhcp {
                }
        }
        
-       # 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;
+       return $self->generate_ifcfg_file($interface_name, { 'bootproto' => 
'dhcp' });
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+=head2 generate_ifcfg_file
+
+ Parameters  : $interface_name, $parameters
+ Returns     : boolean
+ Description : Creates an interface configuration file in
+               /etc/sysconfig/network-scripts. The parameters argument contains
+               key value pairs and must contain a 'bootproto' key. The key 
names
+               must be completely lowercase for consistency. The resulting file
+               will contain uppercase parameter names.
+
+=cut
+
+sub generate_ifcfg_file {
+       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, $parameters_argument) = @_;
+       if (!$interface_name) {
+               notify($ERRORS{'WARNING'}, 0, "interface name argument was not 
supplied");
+               return;
+       }
+       elsif (!$parameters_argument) {
+               notify($ERRORS{'WARNING'}, 0, "parameters argument was not 
supplied");
+               return;
+       }
+       elsif (!ref($parameters_argument) || ref($parameters_argument) ne 
'HASH') {
+               notify($ERRORS{'WARNING'}, 0, "parameters argument is not a 
hash reference:\n" . format_data($parameters_argument));
+               return;
+       }
+       elsif (!$parameters_argument->{bootproto}) {
+               notify($ERRORS{'WARNING'}, 0, "parameters argument must contain 
a 'bootproto' key:\n" . format_data($parameters_argument));
+               return;
        }
        
+       my $computer_name = $self->data->get_computer_node_name();
+       
+       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 = "/tmp/$ifcfg_file_name.$timestamp";
+               $self->copy_file($ifcfg_file_path, $ifcfg_backup_file_path);
+       }
+       
+       my $ifcfg_file_info = $self->get_ifcfg_file_info($interface_name) || {};
+       
        # 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',
+               '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;
@@ -3368,15 +3367,32 @@ sub enable_dhcp {
                }
        }
        
+       # Add/overwrite required parameters to file contents
+       my $common_parameters = {
+               'device' => $interface_name,
+               'name' => $interface_name,
+               'onboot' => 'yes',
+       };
+       for my $parameter (keys %$common_parameters) {
+               my $value = $common_parameters->{$parameter};
+               $ifcfg_file_info->{$parameter} = $value;
+       }
+       
+       # Add/overwrite parameters specified by argument to file contents
+       for my $parameter (keys %$parameters_argument) {
+               my $value = $parameters_argument->{$parameter};
+               $ifcfg_file_info->{$parameter} = $value;
+       }
+       
        # 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";
+               $updated_ifcfg_contents .= uc($parameter) . "=$value\n";
        }
        
        # Create the text file
-       notify($ERRORS{'DEBUG'}, 0, "updated ifcfg-$interface_name 
contents:\n$updated_ifcfg_contents");
+       notify($ERRORS{'DEBUG'}, 0, "attempting to generate file on 
$computer_name: $ifcfg_file_path, contents:\n$updated_ifcfg_contents");
        return $self->create_text_file($ifcfg_file_path, 
$updated_ifcfg_contents);
 }
 
@@ -3390,12 +3406,12 @@ sub enable_dhcp {
                
                A hash is constructed such as:
                {
-                 "BOOTPROTO" => "dhcp",
-                 "DEVICE" => "eth0",
-                 "ONBOOT" => "yes"
+                 "bootproto" => "dhcp",
+                 "device" => "eth0",
+                 "onboot" => "yes"
                }
                
-               The hash key names are guaranteed to be uppercase.
+               The hash key names are guaranteed to be lowercase.
 
 =cut
 
@@ -3420,7 +3436,7 @@ sub get_ifcfg_file_info {
                next if $line =~ /^\s*#/;
                my ($property, $value) = $line =~ /^\s*([^=]+)\s*=\s*(.*)\s*$/g;
                if (defined($property)) {
-                       $info->{uc($property)} = $value;
+                       $info->{lc($property)} = $value;
                }
                else {
                        notify($ERRORS{'WARNING'}, 0, "failed to parse line 
from $ifcfg_file_path: '$line'");
@@ -3439,14 +3455,23 @@ sub get_ifcfg_file_info {
  Description : Executes 'brctl show' and parses the output. A hash is
                constructed:
                {
-                 "br1" => {
-                   "bridge_id" => "",
-                   "interfaces" => [
-                     "eth1",
-                     "eth2"
-                   ],
-                   "stp_enabled" => ""
-                 }
+                  "br0" => {
+                    "bridge_id" => "8000.00505623001c",
+                    "bridge_name" => "br0",
+                    "interfaces" => [
+                      "eth0",
+                    ],
+                    "stp_enabled" => "no"
+                  },
+                  "xbr1" => {
+                    "bridge_id" => "8000.00505623001d",
+                    "bridge_name" => "xbr1",
+                    "interfaces" => [
+                      "eth1",
+                      "vnet1"
+                    ],
+                    "stp_enabled" => "no"
+                  }
                }
 
 =cut
@@ -3466,6 +3491,11 @@ sub get_network_bridge_info {
        # br1             8000.000c29494c97       no              eth1
        #                                                         eth2
        
+       # It's possible to have no interfaces listed:
+       # bridge name     bridge id               STP enabled     interfaces
+       # xbr1            8000.000000000000       no
+
+       
        my $command = "brctl show";
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
@@ -3480,26 +3510,52 @@ sub get_network_bridge_info {
        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;
-               }
+               # Ignore blank and heading lines
+               next if ($line !~ /\w/ || $line =~ /(bridge name)/);
+               
+               my ($bridge_name, $bridge_id, $stp_enabled, $interface_name) = 
$line =~ /
+                       ^
+                       ([^\s]+)
+                       \s+
+                       ([^\s]+)
+                       \s+
+                       ([^\s]+)
+                       \s*
+                       ([^\s]*)
+                       $
+               /gx;
                
-               if ($bridge_name) {
+               if (defined($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" .
+               elsif (defined($current_bridge_name)) {
+                       # Bridge name not found in line but current bridge name 
was previously determined
+                       # Check if line only contains an interface name:
+                       ($interface_name) = $line =~ /^\s+([^\s]+)$/gx;
+                       if (!defined($interface_name)) {
+                               notify($ERRORS{'DEBUG'}, 0, "ignoring line, 
neither bridge name nor interface name were not found\n" .
+                                       "line: '$line'\n" .
+                                       "output:\n" . join("\n", @$output)
+                               );
+                               next;
+                       }
+               }
+               else {
+                       notify($ERRORS{'WARNING'}, 0, "ignoring line, it does 
not contain the bridge name and bridge name was not previously determined\n" .
                                "line: '$line'\n" .
                                "output:\n" . join("\n", @$output)
                        );
-                       return;
+                       next;
                }
                
                $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);
+               $network_bridge_info->{$current_bridge_name}{stp_enabled} = 
$stp_enabled if defined($stp_enabled);
+               
+               # Guarantee 'interfaces' key exists
+               if 
(!defined($network_bridge_info->{$current_bridge_name}{interfaces})) {
+                       
$network_bridge_info->{$current_bridge_name}{interfaces} = [];
+               }
+               push 
@{$network_bridge_info->{$current_bridge_name}{interfaces}}, $interface_name if 
$interface_name;
        }
        
        notify($ERRORS{'OK'}, 0, "retrieved network bridge configuration from 
$computer_name:" . format_data($network_bridge_info));
@@ -7162,7 +7218,7 @@ sub remove_matching_fstab_lines {
 
 =head2 update_resolv_conf
 
- Parameters  : none
+ Parameters  : @public_dns_servers (optional)
  Returns     : boolean
  Description : Updates /etc/resolv.conf on the computer. Existing nameserver
                lines are removed and new nameserver lines are added based on 
the
@@ -7179,14 +7235,14 @@ sub update_resolv_conf {
        
        my $computer_name = $self->data->get_computer_short_name();
        my $public_ip_configuration = 
$self->data->get_management_node_public_ip_configuration();
-       my @public_dns_servers = 
$self->data->get_management_node_public_dns_servers();
+       my @public_dns_servers = shift || 
$self->data->get_management_node_public_dns_servers();
        
        if ($public_ip_configuration !~ /static/i) {    
                notify($ERRORS{'WARNING'}, 0, "unable to update resolv.conf on 
$computer_name, management node's IP configuration is set to 
$public_ip_configuration");
                return;
        }
        elsif (!@public_dns_servers) {
-               notify($ERRORS{'WARNING'}, 0, "unable to update resolv.conf on 
$computer_name, management node's public DNS server is not configured");
+               notify($ERRORS{'WARNING'}, 0, "unable to update resolv.conf on 
$computer_name, DNS server argument was not provided and management node's 
public DNS server is not configured");
                return;
        }
        
@@ -7213,7 +7269,12 @@ sub update_resolv_conf {
        }
        
        my $resolv_conf_contents_new = join("\n", @resolv_conf_lines_new);
-       return $self->create_text_file($resolv_conf_path, 
$resolv_conf_contents_new);
+       if ($self->create_text_file($resolv_conf_path, 
$resolv_conf_contents_new)) {
+               notify($ERRORS{'DEBUG'}, 0, "updated $resolv_conf_path on 
$computer_name:\n$resolv_conf_contents_new");
+       }
+       else {
+               return 0;
+       }
 }
 
 ##/////////////////////////////////////////////////////////////////////////////


Reply via email to