summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/service/daemontools.rb
blob: 934e96aea02b3481c7f7985384b2aa9293ce6342 (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 defined?(@defpath) and @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"
            next
        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 defined?(@servicedir) and @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