On Fri, 27 Feb 2015 11:20:30 +0200 Apollon Oikonomopoulos <apoi...@debian.org> 
wrote:
> The attached patch on top of 3.7.2-2 (hopefully) addresses all of 
> these issues (and drops support for pre-2.88 sysv-rc if you don't 
> mind). I have not tested it on a sysvinit Jessie system though, so if 
> anyone could do this it would be appreciated!

I also tested it on a sysv-rc Jessie system. This is an updated version 
of the patch, marking the systemctl command as optional. Without this, 
sysv-rc Jessie systems would have the Debian provider blacklisted 
because of the missing systemctl command.

Interdiff:

--- b/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -15,7 +15,7 @@
   # http://projects.reductivelabs.com/issues/2538
   # is resolved.
   commands :invoke_rc => "/usr/sbin/invoke-rc.d"
-  commands :systemctl => "/bin/systemctl"
+  optional_commands :systemctl => "/bin/systemctl"
 
   # This isn't being used directly, it's just here to ensure
   # that the /usr/sbin/service binary is available.

Cheers,
Apollon
From a9b76dbfba96f537227c445297d3ccd115de46ca Mon Sep 17 00:00:00 2001
From: Apollon Oikonomopoulos <apoi...@debian.org>
Date: Fri, 27 Feb 2015 10:55:34 +0200
Subject: [PATCH] Fix service listing and enable/disable in Debian
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add two support methods to detect when we're running systemd as PID 1
and if a service has only an initscript.

Use these to implement the following functionality:

 • Under systemd, use systemctl enable/disable for all services. This
   works correctly for all types of services.

 • Under systemd, use systemctl is-enabled only for services that have a
   systemd unit file and fall back to invoke-rc.d for sysv services.

Also, fix self.instances to augment the list of systemd-enabled services
with the sysv services.

Finally drop pre-2.88 sysv-rc support and use `update-rc.d enable' for
all services when running under sysv-rc, preserving order changes.
---
 lib/puppet/provider/service/debian.rb | 94 ++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 23 deletions(-)

diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 9f7a2f5..7a26409 100644
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -15,6 +15,7 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
   # http://projects.reductivelabs.com/issues/2538
   # is resolved.
   commands :invoke_rc => "/usr/sbin/invoke-rc.d"
+  optional_commands :systemctl => "/bin/systemctl"
 
   # This isn't being used directly, it's just here to ensure
   # that the /usr/sbin/service binary is available.
@@ -23,38 +24,82 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
 
   defaultfor :operatingsystem => :debian
 
+  def self.runs_on_systemd?
+    Dir.exists? "/run/systemd/system"
+  end
+
+  def is_sysv_unit?
+    # The sysv generator sets the SourcePath attribute to the name of the
+    # initscript. Use this to detect whether a unit is backed by an initscript
+    # or not.
+    source = systemctl(:show, "-pSourcePath", @resource[:name])
+    source.start_with? "SourcePath=/etc/init.d/"
+  end
+
+  def self.instances
+    # We need to merge services with systemd unit files with those only having
+    # an initscript. Note that we could use `systemctl --all` to get sysv
+    # services as well, however it would only output *enabled* services.
+    i = {}
+    if self.runs_on_systemd?
+      begin
+        output = systemctl('list-unit-files', '--type', 'service', '--full', '--all',  '--no-pager')
+        output.scan(/^(\S+)\.service\s+(disabled|enabled)\s*$/i).each do |m|
+          i[m[0]] = new(:name => m[0])
+        end
+      rescue Puppet::ExecutionFailure
+      end
+    end
+    get_services(defpath).each do |sysv|
+      unless i.has_key?(sysv.name)
+        i[sysv.name] = sysv
+      end
+    end
+    return i.values
+  end
+
   # Remove the symlinks
   def disable
-    if `dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?`.to_i == 0
-      update_rc @resource[:name], "disable"
+    if self.class.runs_on_systemd?
+      systemctl(:disable, @resource[:name])
     else
-      update_rc "-f", @resource[:name], "remove"
-      update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
+      update_rc @resource[:name], "disable"
     end
   end
 
   def enabled?
-    # TODO: Replace system call when Puppet::Util::Execution.execute gives us a way
-    # to determine exit status.  http://projects.reductivelabs.com/issues/2538
-    system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start")
-
-    # 104 is the exit status when you query start an enabled service.
-    # 106 is the exit status when the policy layer supplies a fallback action
-    # See x-man-page://invoke-rc.d
-    if [104, 106].include?($CHILD_STATUS.exitstatus)
-      return :true
-    elsif [105].include?($CHILD_STATUS.exitstatus)
-      # 105 is unknown, which generally means the iniscript does not support query
-      # The debian policy states that the initscript should support methods of query
-      # For those that do not, peform the checks manually
-      # http://www.debian.org/doc/debian-policy/ch-opersys.html
-      if get_start_link_count >= 4
+    # Initscript-backed services have no enabled status in systemd, so we
+    # need to query them using invoke-rc.d.
+    if self.class.runs_on_systemd? and not is_sysv_unit?
+      begin
+        systemctl("is-enabled", @resource[:name])
         return :true
-      else
+      rescue Puppet::ExecutionFailure
         return :false
       end
     else
-      return :false
+      # TODO: Replace system call when Puppet::Util::Execution.execute gives us a way
+      # to determine exit status.  http://projects.reductivelabs.com/issues/2538
+      system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start")
+
+      # 104 is the exit status when you query start an enabled service.
+      # 106 is the exit status when the policy layer supplies a fallback action
+      # See x-man-page://invoke-rc.d
+      if [104, 106].include?($CHILD_STATUS.exitstatus)
+        return :true
+      elsif [105].include?($CHILD_STATUS.exitstatus)
+        # 105 is unknown, which generally means the iniscript does not support query
+        # The debian policy states that the initscript should support methods of query
+        # For those that do not, peform the checks manually
+        # http://www.debian.org/doc/debian-policy/ch-opersys.html
+        if get_start_link_count >= 4
+          return :true
+        else
+          return :false
+        end
+      else
+        return :false
+      end
     end
   end
 
@@ -63,8 +108,11 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
   end
 
   def enable
-    update_rc "-f", @resource[:name], "remove"
-    update_rc @resource[:name], "defaults"
+    if self.class.runs_on_systemd?
+      systemctl(:enable, @resource[:name])
+    else
+      update_rc @resource[:name], "enable"
+    end
   end
 
   # The start, stop, restart and status command use service
-- 
2.1.4

Attachment: signature.asc
Description: Digital signature

Reply via email to