Author: arkurth
Date: Fri Sep  9 17:36:38 2016
New Revision: 1760092

URL: http://svn.apache.org/viewvc?rev=1760092&view=rev
Log:
VCL-989
Updated systemd.pm to handle Ubuntu 15.04+'s usage of ssh as a service name 
instead of sshd.

Added code to delete_service to attempt to delete both ext_ssh and ext_sshd.

Added _get_service_unit_file_path subroutine which retrieves the name of the 
unit file used by a service. This is called from add_ext_sshd_service instead 
of assuming the file is named sshd.service.

Modified regular expressions in add_ext_sshd_service which manipulate 
ext_sshd.service.  They now:
* Remove any $ variables from the ExecStart line containing "OPT" including 
$OPTIONS and $SSHD_OPTS
* Remove any explicit -f <sshd_config path> sections from ExecStart line
* Remove all Alias= lines

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

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm?rev=1760092&r1=1760091&r2=1760092&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm Fri Sep  9 
17:36:38 2016
@@ -299,7 +299,7 @@ sub enable_service {
                return;
        }
        elsif ($exit_status ne 0 || grep(/(failed)/i, @$output)) {
-               notify($ERRORS{'WARNING'}, 0, "failed to enable '$service_name' 
service on $computer_node_name, exit status: $exit_status, output:\n" . 
join("\n", @$output));
+               notify($ERRORS{'WARNING'}, 0, "failed to enable '$service_name' 
service on $computer_node_name, exit status: $exit_status, 
command:\n$command\noutput:\n" . join("\n", @$output));
                return;
        }
        else {
@@ -375,24 +375,32 @@ sub delete_service {
                return 0;
        }
        
-       my $service_name = shift;
-       if (!$service_name) {
+       my $service_name_argument = shift;
+       if (!$service_name_argument) {
                notify($ERRORS{'WARNING'}, 0, "service name argument was not 
supplied");
                return;
        }
        
        my $computer_node_name = $self->data->get_computer_node_name();
        
-       # Disable the service before deleting it
-       if ($self->service_exists($service_name)) {
-               $self->stop_service($service_name) || return;
-               $self->disable_service($service_name) || return;
-       }
-       
-       # Delete the service configuration file
-       my $service_file_path = "/lib/systemd/system/$service_name.service";
-       if (!$self->os->delete_file($service_file_path)) {
-               return;
+       # Attempt to delete both ext_sshd and ext_ssh if the argument is 
+       my @service_names = ($service_name_argument);
+       if ($service_name_argument =~ /ext_ssh/) {
+               @service_names = ('ext_sshd', 'ext_ssh');
+       }
+       
+       for my $service_name (@service_names) {
+               # Disable the service before deleting it
+               if ($self->service_exists($service_name)) {
+                       $self->stop_service($service_name) || return;
+                       $self->disable_service($service_name) || return;
+               }
+               
+               # Delete the service configuration file
+               my $service_file_path = 
"/lib/systemd/system/$service_name.service";
+               if (!$self->os->delete_file($service_file_path)) {
+                       return;
+               }
        }
        
        $self->_daemon_reload();
@@ -570,7 +578,15 @@ sub add_ext_sshd_service {
        
        my $computer_node_name = $self->data->get_computer_node_name();
        
-       my $sshd_service_file_path     = '/lib/systemd/system/sshd.service';
+       # Get the unit file path for the sshd service
+       # Do not automatically assume it is /lib/systemd/system/sshd.service
+       # https://issues.apache.org/jira/browse/VCL-989
+       my $sshd_service_file_path = $self->_get_service_unit_file_path('sshd');
+       if (!$sshd_service_file_path) {
+               $sshd_service_file_path = '/lib/systemd/system/sshd.service';
+       }
+       
+       # Hard-code the ext_sshd file path (intentional)
        my $ext_sshd_service_file_path = '/lib/systemd/system/ext_sshd.service';
        
        # Get the contents of the sshd service configuration file already on 
the computer
@@ -581,22 +597,36 @@ sub add_ext_sshd_service {
        }
        
        my $ext_sshd_service_file_contents = join("\n", 
@sshd_service_file_contents);
-       
+
        # Replace: OpenSSH --> External OpenSSH
        $ext_sshd_service_file_contents =~ s|(OpenSSH)|external $1|g;
        
        # Replace: sshd --> ext_sshd, exceptions:
        # /bin/sshd
        # /sshd_config
-       $ext_sshd_service_file_contents =~ 
s|(?<!bin/)sshd(?!_config)|ext_sshd|g;
+       $ext_sshd_service_file_contents =~ 
s|(?<!bin/)sshd(?!_config\|-keygen)|ext_sshd|g;
        
-       # Replace: $OPTIONS --> -f /etc/ssh/external_sshd_config
-       $ext_sshd_service_file_contents =~ s|(ExecStart=.+)\s+\$OPTIONS|$1 -f 
/etc/ssh/external_sshd_config|g;
+       # Remove ExecStart options variables
+       # ExecStart=/usr/sbin/sshd -D $OPTIONS
+       # ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
+       $ext_sshd_service_file_contents =~ 
s/^\s*(ExecStart=.+\S)\s+\$\S*OPT\S*(.*)$/$1$2/gm;
+       
+       # Remove explicit -f arguments
+       $ext_sshd_service_file_contents =~ 
s/^\s*(ExecStart=.+\S)\s+-f\s+\S+(.*)$/$1$2/gm;
+       
+       # Add -f argument
+       $ext_sshd_service_file_contents =~ s|^\s*(ExecStart=.+\S)\s*$|$1 -f 
/etc/ssh/external_sshd_config|gm;
        
        # Set EnvironmentFile to /dev/null, service won't start if the file 
doesn't exist
        $ext_sshd_service_file_contents =~ 
s|(EnvironmentFile)=.*|$1=/dev/null|g;
        
-       $ext_sshd_service_file_contents .= "\n";
+       # Remove Alias= line which may exist in ssh_config:
+       # Alias=ext_sshd.service
+       # Otherwise, this may occur when attempting to enable the service if 
the service is named the same as the alias:
+       # Failed to execute operation: Too many levels of symbolic links
+       $ext_sshd_service_file_contents =~ s/^\s*Alias=.*//gm;
+       
+       notify($ERRORS{'DEBUG'}, 0, 
"$ext_sshd_service_file_path:\n$ext_sshd_service_file_contents");
        
        if (!$self->os->create_text_file($ext_sshd_service_file_path, 
$ext_sshd_service_file_contents)) {
                notify($ERRORS{'WARNING'}, 0, "failed to create ext_sshd 
service file on $computer_node_name: $ext_sshd_service_file_path");
@@ -651,6 +681,64 @@ sub _daemon_reload {
 }
 
 #/////////////////////////////////////////////////////////////////////////////
+
+=head2 _get_service_unit_file_path
+
+ Parameters  : $service_name
+ Returns     : string
+ Description : Determines the unit file for the service specified by the
+               argument. This is needed because the file name is not always
+               $service_name.service. This is the case when a service has alias
+               names configured such as the ssh and sshd services on Ubuntu 16.
+               The file path for the sshd service is ssh.service.
+
+=cut
+
+sub _get_service_unit_file_path {
+       my $self = shift;
+       if (ref($self) !~ /VCL::/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return 0;
+       }
+       
+       my $service_name = shift;
+       if (!$service_name) {
+               notify($ERRORS{'WARNING'}, 0, "service name argument was not 
supplied");
+               return;
+       }
+       
+       my $computer_node_name = $self->data->get_computer_node_name();
+       
+       my $command = "systemctl show $service_name.service 
--property=FragmentPath";
+       my ($exit_status, $output) = $self->os->execute($command, 0);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve unit file 
path for $service_name service on $computer_node_name: $command");
+               return;
+       }
+       elsif ($exit_status ne 0 || grep(/(failed)/i, @$output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve unit file 
path for $service_name service on $computer_node_name, exit status: 
$exit_status, output:\n" . join("\n", @$output));
+               return;
+       }
+       
+       # Expected output:
+       # FragmentPath=/lib/systemd/system/ssh.service
+       my ($file_path_line) = grep(/FragmentPath=/, @$output);
+       if (!$file_path_line) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve unit file 
path for $service_name service on $computer_node_name, output does not contain 
a 'FragmentPath=' line, output:\n" . join("\n", @$output));
+               return;
+       }
+       
+       my ($file_path) = $file_path_line =~ /FragmentPath=(.+)\s*$/g;
+       if (!$file_path) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve unit file 
path for $service_name service on $computer_node_name, failed to parse 
'FragmentPath=' line, output:\n" . join("\n", @$output));
+               return;
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved unit file path for $service_name 
service on $computer_node_name: $file_path");
+       return $file_path
+}
+
+#/////////////////////////////////////////////////////////////////////////////
 
 1;
 __END__


Reply via email to