summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/service/daemontools.rb
blob: f5a073329561c2f48ff5187f51c8e85c08c5e1e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# Daemontools service management
#
# author Brice Figureau <brice-puppet@daysofwonder.com>
Puppet::Type.type(:service).provide :daemontools, :parent => :base do
  desc "Daemontools service management.

  This provider manages daemons running supervised by D.J.Bernstein daemontools.
  It tries to detect the service directory, with by order of preference:

  * /service
  * /etc/service
  * /var/lib/svscan

  The daemon directory should be placed in a directory that can be
  by default in:

  * /var/lib/service
  * /etc

  or this can be overriden in the service resource parameters::

      service { \"myservice\":
        provider => \"daemontools\",
        path => \"/path/to/daemons\",
      }

  This provider supports out of the box:

  * start/stop (mapped to enable/disable)
  * enable/disable
  * restart
  * status

  If a service has `ensure => \"running\"`, it will link /path/to/daemon to
  /path/to/service, which will automatically enable the service.

  If a service has `ensure => \"stopped\"`, it will only down the service, not
  remove the /path/to/service link.

  "

  commands :svc  => "/usr/bin/svc", :svstat => "/usr/bin/svstat"

  class << self
    attr_writer :defpath

    # Determine the daemon path.
    def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
      unless @defpath
        ["/var/lib/service", "/etc"].each do |path|
          if FileTest.exist?(path)
            @defpath = path
            break
          end
        end
        raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
      end
      @defpath
    end
  end

  attr_writer :servicedir

  # returns all providers for all existing services in @defpath
  # ie enabled or not
  def self.instances
    path = self.defpath
    unless FileTest.directory?(path)
      Puppet.notice "Service path #{path} does not exist"
      return
    end

    # reject entries that aren't either a directory
    # or don't contain a run file
    Dir.entries(path).reject { |e|
      fullpath = File.join(path, e)
      e =~ /^\./ or ! FileTest.directory?(fullpath) or ! FileTest.exist?(File.join(fullpath,"run"))
    }.collect do |name|
      new(:name => name, :path => path)
    end
  end

  # returns the daemon dir on this node
  def self.daemondir
    self.defpath
  end

  # find the service dir on this node
  def servicedir
    unless @servicedir
      ["/service", "/etc/service","/var/lib/svscan"].each do |path|
        if FileTest.exist?(path)
          @servicedir = path
          break
        end
      end
      raise "Could not find service directory" unless @servicedir
    end
    @servicedir
  end

  # returns the full path of this service when enabled
  # (ie in the service directory)
  def service
    File.join(self.servicedir, resource[:name])
  end

  # returns the full path to the current daemon directory
  # note that this path can be overriden in the resource
  # definition
  def daemon
    File.join(resource[:path], resource[:name])
  end

  def status
    begin
      output = svstat self.service
      if output =~ /:\s+up \(/
        return :running
      end
    rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
    end
    :stopped
  end

  def setupservice
      if resource[:manifest]
        Puppet.notice "Configuring #{resource[:name]}"
        command = [ resource[:manifest], resource[:name] ]
        #texecute("setupservice", command)
        rv = system("#{command}")
      end
  rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
  end

  def enabled?
    case self.status
    when :running
      # obviously if the daemon is running then it is enabled
      return :true
    else
      # the service is enabled if it is linked
      return FileTest.symlink?(self.service) ? :true : :false
    end
  end

  def enable
      if ! FileTest.directory?(self.daemon)
        Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
        self.setupservice
      end
      if self.daemon
        if ! FileTest.symlink?(self.service)
          Puppet.notice "Enabling #{self.service}: linking #{self.daemon} -> #{self.service}"
          File.symlink(self.daemon, self.service)
        end
      end
  rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error.new( "No daemon directory found for #{self.service}")
  end

  def disable
    begin
      if ! FileTest.directory?(self.daemon)
        Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
        self.setupservice
      end
      if self.daemon
        if FileTest.symlink?(self.service)
          Puppet.notice "Disabling #{self.service}: removing link #{self.daemon} -> #{self.service}"
          File.unlink(self.service)
        end
      end
    rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error.new( "No daemon directory found for #{self.service}")
    end
    self.stop
  end

  def restart
    svc "-t", self.service
  end

  def start
    enable unless enabled? == :true
    svc "-u", self.service
  end

  def stop
    svc "-d", self.service
  end
end