sub set_static_public_address()

in managementnode/lib/VCL/Module/OS/Linux/Ubuntu.pm [370:551]


sub set_static_public_address {
	my $self = shift;
	if (ref($self) !~ /ubuntu/i) {
		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
		return 0;
	}
	
	my $computer_name           = $self->data->get_computer_short_name();
	my $public_ip_configuration = $self->data->get_management_node_public_ip_configuration();
	my $public_ip_address       = $self->data->get_computer_public_ip_address();
	my $public_subnet_mask      = $self->data->get_management_node_public_subnet_mask();
	my @public_dns_servers      = $self->data->get_management_node_public_dns_servers();
	
	my $public_default_gateway  = $self->get_correct_default_gateway();
	
	my $server_request_fixed_ip = $self->data->get_server_request_fixed_ip();
	if ($server_request_fixed_ip) {
		$public_ip_address = $server_request_fixed_ip;
		$public_subnet_mask     = $self->data->get_server_request_netmask();
		$public_default_gateway = $self->data->get_server_request_router();
		@public_dns_servers     = $self->data->get_server_request_dns_servers();
		
		if (!$public_subnet_mask) {
			notify($ERRORS{'WARNING'}, 0, "unable to set static public IP address to $public_ip_address on $computer_name, server request fixed IP is set but server request subnet mask could not be retrieved");
			return;
		}
		elsif (!@public_dns_servers) {
			notify($ERRORS{'WARNING'}, 0, "unable to set static public IP address to $public_ip_address on $computer_name, server request fixed IP is set but server request DNS servers could not be retrieved");
			return;
		}
	}
	else {
		if ($public_ip_configuration !~ /static/i) {	
			notify($ERRORS{'WARNING'}, 0, "unable to set static public IP address to $public_ip_address on $computer_name, management node's IP configuration is set to $public_ip_configuration");
			return;
		}
	}
	
	# Get 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 to $public_ip_address on $computer_name, failed to determine public interface name");
		return;
	}
	
	# Stop the interface in case it is already assigned the static IP otherwise ping will respond
	$self->stop_network_interface($public_interface_name);
	
	# Attempt to ping the public IP address to make sure it's available
	if (_pingnode($public_ip_address)) {
		notify($ERRORS{'CRITICAL'}, 0, "failed to set static public IP address to $public_ip_address on $computer_name, IP address is pingable");
		return;
	}
	
	# Get the current interfaces file contents
	my $interfaces_file_path = '/etc/network/interfaces';
	my @interfaces_lines_original = $self->get_file_contents($interfaces_file_path);
	if (!@interfaces_lines_original) {
		notify($ERRORS{'WARNING'}, 0, "failed to set static public IP address to $public_ip_address on $computer_name, $interfaces_file_path contents could not be retrieved");
		return;
	}
	my $interfaces_contents_original = join("\n", @interfaces_lines_original);
	notify($ERRORS{'DEBUG'}, 0, "retreived contents of '$interfaces_file_path' from $computer_name:\n$interfaces_contents_original");
	
	# Make a backup of the file
	my $timestamp = POSIX::strftime("%Y-%m-%d_%H-%M-%S", localtime);
	$self->copy_file($interfaces_file_path, "$interfaces_file_path.$timestamp");
	
	# Examples:
	# auto eth0
	# iface eth0 inet dhcp
	
	# auto br1
	# iface br1 inet dhcp
	#    bridge_ports eth1
	#    bridge_stp off
	#    bridge_fd 0
	
	# iface eth1 inet static
	#    address 192.168.1.1
	#    netmask 255.255.255.0
	
	my @stanza_types = (
		'iface',
		'mapping',
		'auto',
		'allow-',
		'source',
	);
	
	my @interfaces_lines_new;
	my $in_public_iface_stanza = 0;
	
	my @lines_to_add = (
		"   address $public_ip_address",
		"   netmask $public_subnet_mask",
		"   gateway $public_default_gateway",
	);
	
	for my $line (@interfaces_lines_original) {
		
		if ($line =~ /^\s*iface\s+$public_interface_name\s+(\w+)/) {
			my $address_family = $1;
			$in_public_iface_stanza = 1;
			notify($ERRORS{'DEBUG'}, 0, "found beginning of public iface stanza: $line");
			push @interfaces_lines_new, "iface $public_interface_name $address_family static";
			
			# Add static IP information
			push @interfaces_lines_new, @lines_to_add;
			notify($ERRORS{'DEBUG'}, 0, "adding lines:\n" . join("\n", @lines_to_add));
		}
		elsif ($in_public_iface_stanza) {
			my ($stanza_type) = grep { $line =~ /^\s*$_/ } @stanza_types;
			if ($stanza_type) {
				$in_public_iface_stanza = 0;
				notify($ERRORS{'DEBUG'}, 0, "found end of public iface stanza, line begins new stanza: $line");
				
				# Add line which begins next stanza
				push @interfaces_lines_new, $line;
			}
			else {
				notify($ERRORS{'DEBUG'}, 0, "line in public iface stanza: $line");
				
				# Check if line should be added or ignored
				if ($line =~ /^\s*(bridge|bond|vlan)/) {
					my $match = $1;
					notify($ERRORS{'DEBUG'}, 0, "including '$match' line from public iface stanza: $line");
					push @interfaces_lines_new, $line;
				}
				else {
					notify($ERRORS{'DEBUG'}, 0, "not including line from public iface stanza: $line");
				}
			}
		}
		else {
			notify($ERRORS{'DEBUG'}, 0, "line is not part of public iface stanza: $line");
			push @interfaces_lines_new, $line;
		}
	}
	my $interfaces_contents_new = join("\n", @interfaces_lines_new);
	
	
	# Check if the interfaces content changed, update file if necessary
	if ($interfaces_contents_new eq $interfaces_contents_original) {
		notify($ERRORS{'OK'}, 0, "update of $interfaces_file_path on $computer_name not necessary, $interfaces_file_path not changed:\n$interfaces_contents_new");
	}
	elsif ($self->create_text_file($interfaces_file_path, $interfaces_contents_new)) {
		notify($ERRORS{'OK'}, 0, "updated $interfaces_file_path to set static public IP address to $public_ip_address on $computer_name\n" .
			"original:\n$interfaces_contents_original\n" .
			"---\n" .
			"new:\n$interfaces_contents_new"
		);
	}
	else {
		notify($ERRORS{'WARNING'}, 0, "failed to update $interfaces_file_path to set static public IP address to $public_ip_address on $computer_name");
		return;
	}
	
	# Restart the public interface
	if (!$self->restart_network_interface($public_interface_name)) {
		notify($ERRORS{'WARNING'}, 0, "failed to set static public IP address to $public_ip_address on $computer_name, failed to restart public interface $public_interface_name");
		return;
	}
	
	# Set the default gateway
	if (!$self->set_static_default_gateway()) {
		notify($ERRORS{'WARNING'}, 0, "failed to set static public IP address to $public_ip_address on $computer_name, failed to set the default gateway");
		return;
	}
	
	# Update resolv.conf
	if (!$self->update_resolv_conf()) {
		notify($ERRORS{'WARNING'}, 0, "failed to set static public IP address to $public_ip_address on $computer_name, failed to update resolv.conf");
		return;
	}
	
	# 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{'DEBUG'}, 0, "set static public IP address to $public_ip_address on $computer_name");
	return 1;
}