From b979de76b67cd80d87e032dbbcb49ac5022d9240 Mon Sep 17 00:00:00 2001
From: immarvin <yangsbj@cn.ibm.com>
Date: Sun, 8 Jun 2014 05:42:23 -0700
Subject: [PATCH] add generic subroutine and functions for service management

---
 perl-xCAT/xCAT/Utils.pm     | 463 +++++++++++++++++++++++++++++++++++-
 xCAT/postscripts/xcatlib.sh | 204 ++++++++++++++++
 2 files changed, 665 insertions(+), 2 deletions(-)

diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm
index f9f454b10..4264e7e74 100644
--- a/perl-xCAT/xCAT/Utils.pm
+++ b/perl-xCAT/xCAT/Utils.pm
@@ -16,7 +16,6 @@ if ($^O =~ /^aix/i) {
 use lib "$::XCATROOT/lib/perl";
 # do not put a use or require for  xCAT::Table here. Add to each new routine
 # needing it to avoid reprocessing of user tables ( ExtTab.pm) for each command call 
-#  
 use POSIX qw(ceil);
 use File::Path;
 use Socket;
@@ -3426,10 +3425,11 @@ sub version_cmp {
       string of the bin file name
     Returns:
       string of the full path name of the binary executable file
+      string of the bin file name in the argument if failed
     Globals:
         none
     Error:
-      string of the bin file name in the argument
+        none
     Example:
          my $CHKCONFIG = xCAT::Utils->fullpathbin("chkconfig");
     Comments:
@@ -3517,4 +3517,463 @@ sub gettimezone
 }
 
 
+#--------------------------------------------------------------------------------
+
+=head3   servicemap 
+    returns the name of service unit(for systemd) or service daemon(for SYSVinit). 
+    Arguments:
+      $svcname: the name of the service
+      $svcmgrtype: the service manager type:
+                   0: SYSVinit
+                   1: systemd 
+    Returns:
+      the name of service unit or service daemon
+      undef on fail
+    Globals:
+        none
+    Error:
+      None 
+    Example:
+         my $svc = xCAT::Utils->servicemap($svcname,1);
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub servicemap{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+  }
+  
+  my $svcmgrtype=shift;
+
+
+  #hash structure: 
+  #"service name $svcname" =>{
+  #"service manager name(SYSVinit/systemd) $svcmgrtype" 
+  #=> ["list of possible service file names for the specified $svcname under the specified $svcmgrtype "]
+  # }
+  my %svchash=(
+     "dhcp" => {
+                 0=>["dhcpd","isc-dhcp-server"],
+                 1=>["dhcpd.service"],
+               },
+     "nfs" =>  {
+                 0=>["nfsserver","nfs","nfs-kernel-server"],
+                 1=>["nfs-server.service"],
+               },
+     "named" =>  {
+                 0=>["named","bind9"],
+                 1=>["named.service"],
+               },
+     "syslog" =>  {
+                 0=>["syslog","syslogd","rsyslog"],
+                 1=>["rsyslog.service"],
+               },
+     "firewall" =>  {
+                 0=>["iptables","firewalld","SuSEfirewall2_setup"],
+                 1=>["firewalld.service"],
+               },
+     "http" =>  {
+                 0=>["apache2","httpd"],
+                 1=>["httpd.service"],
+               },
+  );
+
+  my $path=undef;
+  my $retdefault=$svcname;
+  if($svcmgrtype == 0){
+     $path="/etc/init.d/";
+  }elsif ($svcmgrtype == 1){
+     $path="/usr/lib/systemd/system/";
+     $retdefault=$svcname.".service";
+  }
+
+  
+  my $ret=undef;
+  if($svchash{$svcname} and $svchash{$svcname}{$svcmgrtype}){
+    foreach my $file (@{$svchash{$svcname}{$svcmgrtype}}){
+       if(-e $path.$file ){
+             $ret=$file;
+             last;
+          }
+    }      
+  }else{
+    if(-e $path.$retdefault){
+        $ret=$retdefault;
+    } 
+ }
+
+ return $ret;  
+
+}
+
+
+#--------------------------------------------------------------------------------
+
+=head3  startservice  
+    start a service
+    Arguments:
+      service name
+    Returns:
+      0 on success
+      nonzero otherwise
+    Globals:
+        none
+    Error:
+        none
+    Example:
+        xCAT::Utils->startservice("nfs");
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub startservice{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+  }
+
+  my $cmd="";
+  my $svcunit=undef;
+  my $svcd=undef;
+
+  $svcunit=servicemap($svcname,1);
+  $svcd=servicemap($svcname,0);
+  if($svcunit)
+  {
+      $cmd="systemctl start $svcunit";
+  }
+  elsif( $svcd )
+  {
+      $cmd="service $svcd start";
+  }
+  print "$cmd\n"; 
+  if( $cmd eq "" )
+  {
+     return -1;
+  }
+ 
+  xCAT::Utils->runcmd($cmd, -1);
+  return $::RUNCMD_RC;
+}
+
+
+#--------------------------------------------------------------------------------
+
+=head3  stopservice  
+    stop a service
+    Arguments:
+      service name
+    Returns:
+      0 on success
+      nonzero otherwise
+    Globals:
+        none
+    Error:
+        none
+    Example:
+        xCAT::Utils->stopservice("nfs");
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub stopservice{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+  }
+
+  my $cmd="";
+  my $svcunit=undef;
+  my $svcd=undef;
+
+  $svcunit=servicemap($svcname,1);
+  $svcd=servicemap($svcname,0);
+  if($svcunit)
+  {
+      $cmd="systemctl stop $svcunit";
+  }
+  elsif( $svcd )
+  {
+      $cmd="service $svcd stop";
+  }
+  print "$cmd\n"; 
+  if( $cmd eq "" )
+  {
+     return -1;
+  }
+ 
+  xCAT::Utils->runcmd($cmd, -1);
+  return $::RUNCMD_RC;
+}
+
+
+#--------------------------------------------------------------------------------
+
+=head3  restartservice  
+    restart a service
+    Arguments:
+      service name
+    Returns:
+      0 on success
+      nonzero otherwise
+    Globals:
+        none
+    Error:
+        none
+    Example:
+        xCAT::Utils->restartservice("nfs");
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub restartservice{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+  }
+
+  my $cmd="";
+  my $svcunit=undef;
+  my $svcd=undef;
+
+  $svcunit=servicemap($svcname,1);
+  $svcd=servicemap($svcname,0);
+  if($svcunit)
+  {
+      $cmd="systemctl restart $svcunit";
+  }
+  elsif( $svcd )
+  {
+      $cmd="service $svcd restart";
+  }
+  print "$cmd\n"; 
+  if( $cmd eq "" )
+  {
+     return -1;
+  }
+ 
+  xCAT::Utils->runcmd($cmd, -1);
+  return $::RUNCMD_RC;
+}
+
+#--------------------------------------------------------------------------------
+
+=head3   checkservicestatus 
+    returns theservice status. 
+    Arguments:
+      $svcname: the name of the service
+      $outputoption[optional]:
+                   the output option
+                   1: return a hashref with the keys:"retcode","retmsg"
+           otherwise: return retcode only
+    Returns:
+      undef on fail
+      a hashref if $outputoption is 1,the hash structure is:
+                  {"retcode"=>(status code, 0 for running/active,1 for stopped/inactive,2 for failed)
+                   "retmsg" =>(status string, running/active/stopped/inactive/failed)
+                  }
+      the status code otherwise
+
+    Globals:
+        none
+    Error:
+      None 
+    Example:
+         my $ret = xCAT::Utils-checkservicestatus($svcname,1);
+         my $retcode = xCAT::Utils-checkservicestatus($svcname);
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub checkservicestatus{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+  }
+
+  my $outputoption=shift;
+
+  my $cmd="";
+  my $svcunit=undef;
+  my $svcd=undef;
+  my %ret;
+
+  $svcunit=servicemap($svcname,1);
+  $svcd=servicemap($svcname,0);
+  my $output=undef;
+
+  if($svcunit)
+  {
+      #for systemd, parse the output since it is formatted
+      $cmd="systemctl show --property=ActiveState $svcunit|awk -F '=' '{print \$2}'";
+      $output=xCAT::Utils->runcmd($cmd, -1);
+      if($output =~ /^active$/i){
+         $ret{retcode}=0;
+         print "xxx$output\n";
+      }elsif($output =~ /^failed$/i){
+         $ret{retcode}=2;
+       
+      }elsif($output =~ /^inactive$/i){
+         $ret{retcode}=1;
+      }
+  }
+  elsif( $svcd )
+  {
+      #for SYSVinit, check the return value since the "service" command output is confused
+      $cmd="service $svcd status";
+      $output=xCAT::Utils->runcmd($cmd, -1);
+      $ret{retcode}=$::RUNCMD_RC; 
+#      if($output =~ /stopped|not running/i){
+#        $ret{retcode}=1;
+#      }elsif($output =~ /running/i){
+#        $ret{retcode}=0;
+#      }
+  }
+  if($output)
+  {
+     $ret{retmsg}=$output;
+  }
+  
+
+  if(defined $outputoption and $outputoption == 1 ){
+     return \%ret;
+  }elsif(exists $ret{retcode}){
+     return $ret{retcode};
+  }
+
+   return undef;
+
+}
+
+
+#--------------------------------------------------------------------------------
+
+=head3  enableservice 
+   enable a service to start it on the system bootup
+    Arguments:
+      service name
+    Returns:
+      0 on success
+      nonzero otherwise
+    Globals:
+        none
+    Error:
+        none
+    Example:
+        xCAT::Utils->enableservice("nfs");
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub enableservice{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+
+  }
+  my $cmd="";
+  my $svcunit=undef;
+  my $svcd=undef;
+
+  $svcunit=servicemap($svcname,1);
+  $svcd=servicemap($svcname,0);
+  if($svcunit)
+  {
+      $cmd="systemctl enable $svcunit";
+  }
+  elsif( $svcd )
+  {
+      my $CHKCONFIG = xCAT::Utils->fullpathbin("chkconfig");
+      if($CHKCONFIG ne "chkconfig"){
+          $cmd="$CHKCONFIG $svcd on";
+      }else{
+        $CHKCONFIG = xCAT::Utils->fullpathbin("update-rc.d");
+        if($CHKCONFIG ne "update-rc.d"){
+            $cmd="$CHKCONFIG $svcd defaults";
+        }
+      }
+  }
+  print "$cmd\n";
+  if( $cmd eq "" )
+  {
+     return -1;
+  }
+
+  xCAT::Utils->runcmd($cmd, -1);
+  return $::RUNCMD_RC;
+}
+
+
+#--------------------------------------------------------------------------------
+
+=head3  disableservice  
+    disable a service to prevent it from starting on system bootup
+    Arguments:
+      service name
+    Returns:
+      0 on success
+      nonzero otherwise
+    Globals:
+        none
+    Error:
+        none
+    Example:
+        xCAT::Utils->disableservice("nfs");
+    Comments:
+        none
+=cut
+
+#--------------------------------------------------------------------------------
+sub disableservice{
+  my $svcname=shift;
+  if( $svcname =~ /xCAT::Utils/)
+  {
+     $svcname=shift;
+
+  }
+  my $cmd="";
+  my $svcunit=undef;
+  my $svcd=undef;
+
+  $svcunit=servicemap($svcname,1);
+  $svcd=servicemap($svcname,0);
+  if($svcunit)
+  {
+      $cmd="systemctl disable $svcunit";
+  }
+  elsif( $svcd )
+  {
+      my $CHKCONFIG = xCAT::Utils->fullpathbin("chkconfig");
+      if($CHKCONFIG ne "chkconfig"){
+          $cmd="$CHKCONFIG $svcd off";
+      }else{
+        $CHKCONFIG = xCAT::Utils->fullpathbin("update-rc.d");
+        if($CHKCONFIG ne "update-rc.d"){
+            $cmd="$CHKCONFIG -f $svcd remove";
+        }
+      }
+  }
+  print "$cmd\n";
+  if( $cmd eq "" )
+  {
+     return -1;
+  }
+
+  xCAT::Utils->runcmd($cmd, -1);
+  return $::RUNCMD_RC;
+}
 1;
diff --git a/xCAT/postscripts/xcatlib.sh b/xCAT/postscripts/xcatlib.sh
index ee532258d..6bac5d0d5 100644
--- a/xCAT/postscripts/xcatlib.sh
+++ b/xCAT/postscripts/xcatlib.sh
@@ -266,3 +266,207 @@ function v6calcnet(){
     str_v6net=`echo $str_v6net | sed 's/.$//'`
     echo "$str_v6net"
 }
+
+
+function servicemap {
+   local svcname=$1
+   local svcmgrtype=$2
+   local svclistname=   
+
+   INIT_dhcp="dhcpd isc-dhcp-server";
+   SYSTEMD_dhcp="dhcpd.service";
+
+   INIT_nfs="nfsserver nfs nfs-kernel-server";
+   SYSTEMD_nfs="nfs-server.service";
+
+   INIT_named="named bind9";
+   SYSTEMD_named="named.service";
+
+   INIT_syslog="syslog syslogd rsyslog";
+   SYSTEMD_syslog="rsyslog.service";
+ 
+   INIT_firewall="iptables firewalld SuSEfirewall2_setup";
+   SYSTEMD_firewall="firewalld.service";
+
+   INIT_http="apache2 httpd";
+   SYSTEMD_http="httpd.service";
+
+   local path=
+   local retdefault=$svcname
+   local svcvar=${svcname//[-.]/_}
+   if [ "$svcmgrtype" = "0"  ];then
+      svclistname=INIT_$svcvar
+      path="/etc/init.d/"
+   elif [ "$svcmgrtype" = "1"  ];then
+      svclistname=SYSTEMD_$svcvar
+      retdefault=$svcname.service
+      path="/usr/lib/systemd/system/"
+   fi
+   
+
+   local svclist=$(eval echo \$$svclistname)      
+
+   if [ -z "$svclist" ];then
+      svclist="$retdefault"
+   fi
+
+   for name in `echo $svclist`
+   do
+      if [ -e "$path$name"  ];then
+         echo $name
+         break
+      fi
+   done
+   
+}
+
+function startservice {
+   local svcname=$1
+   local cmd=
+   local svcunit=`servicemap $svcname 1`
+   local svcd=`servicemap $svcname 0`
+  
+   if [ -n "$svcunit"  ];then
+      cmd="systemctl start $svcunit"
+   elif [ -n "$svcd"  ];then
+      cmd="service $svcd start";
+   fi
+
+   if [ -z "$cmd"  ];then
+      return 127
+   fi
+   
+   eval $cmd
+}
+
+
+
+function stopservice {
+   local svcname=$1
+   local cmd=
+   local svcunit=`servicemap $svcname 1`
+   local svcd=`servicemap $svcname 0`
+  
+   if [ -n "$svcunit"  ];then
+      cmd="systemctl stop $svcunit"
+   elif [ -n "$svcd"  ];then
+      cmd="service $svcd stop";
+   fi
+
+   if [ -z "$cmd"  ];then
+      return 127
+   fi
+   
+   eval $cmd
+}
+
+
+function restartservice {
+   local svcname=$1
+   local cmd=
+   local svcunit=`servicemap $svcname 1`
+   local svcd=`servicemap $svcname 0`
+  
+   if [ -n "$svcunit"  ];then
+      cmd="systemctl restart $svcunit"
+   elif [ -n "$svcd"  ];then
+      cmd="service $svcd restart";
+   fi
+
+   if [ -z "$cmd"  ];then
+      return 127
+   fi
+   
+   eval $cmd
+}
+
+
+function checkservicestatus {
+   local svcname=$1
+
+   local svcunit=`servicemap $svcname 1`
+   local svcd=`servicemap $svcname 0`
+ 
+   local output= 
+   local retcode=3  
+
+   if [ -n "$svcunit"  ];then
+      output=$(systemctl show --property=ActiveState $svcunit|awk -F '=' '{print $2}')
+      if echo $output|grep -E -i "^active$";then
+         retcode=0
+      elif echo $output|grep -E -i "^inactive$";then
+         retcode=1
+      elif echo $output|grep -E -i "^failed$";then
+         retcode=2
+      fi
+   elif [ -n "$svcd"  ];then
+      output=$(service $svcd status)
+      retcode=$?
+      echo $output 
+#      if echo $output|grep -E -i "(stopped|not running)";then
+#         retcode=1
+#      elif echo $output|grep -E -i "running";then
+#         retcode=0
+#      fi
+   else
+      retcode=127
+   fi
+   
+   return $retcode
+    
+}
+
+function enableservice {
+   local svcname=$1
+   local cmd=
+   local svcunit=`servicemap $svcname 1`
+   local svcd=`servicemap $svcname 0`
+  
+   if [ -n "$svcunit"  ];then
+      cmd="systemctl enable  $svcunit"
+   elif [ -n "$svcd"  ];then
+     command -v chkconfig >/dev/null 2>&1
+     if [ $? -eq 0 ];then
+        cmd="chkconfig $svcd on";
+     else
+        command -v update-rc.d >/dev/null 2>&1
+        if [ $? -eq 0 ];then
+           cmd="update-rc.d $svcd defaults"
+        fi  
+     fi
+   fi
+
+   if [ -z "$cmd"  ];then
+      return 127
+   fi
+   
+   eval $cmd
+}
+
+
+function disableservice {
+   local svcname=$1
+   local cmd=
+   local svcunit=`servicemap $svcname 1`
+   local svcd=`servicemap $svcname 0`
+  
+   if [ -n "$svcunit"  ];then
+      cmd="systemctl disable  $svcunit"
+   elif [ -n "$svcd"  ];then
+     command -v chkconfig >/dev/null 2>&1
+     if [ $? -eq 0 ];then
+        cmd="chkconfig $svcd off";
+     else
+        command -v update-rc.d >/dev/null 2>&1
+        if [ $? -eq 0 ];then
+           cmd="update-rc.d -f $svcd remove"
+        fi  
+     fi
+   fi
+
+   if [ -z "$cmd"  ];then
+      return 127
+   fi
+   
+   eval $cmd
+}