summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/service/daemontools.rb
blob: 52d8c6b6c26282de241746b37dc9546def8ee4b6 (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
# 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"

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

    class << self
        attr_writer :defpath
        
        # this is necessary to autodetect a valid resource
        # default path, since there is no standard for such directory.
        def defpath
            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 %s does not exist" % path
            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 restartcmd
        [ command(:svc), "-t", self.service]
    end

    # The start command does nothing, service are automatically started
    # when enabled by svscan. But, forces an enable if necessary
    def start
        # to start make sure the sevice is enabled
        self.enable
        # start is then automatic
    end

    def status
        begin
            output = svstat self.service
            return :running if output =~ /\bup\b/
        rescue Puppet::ExecutionFailure => detail
            raise Puppet::Error.new( "Could not get status for service %s: %s" % [ resource.ref, detail] )
        end
        return :stopped
    end

    # unfortunately it is not possible
    # to stop without disabling the service
    def stop
        self.disable
    end

    # disable by stopping the service
    # and removing the symlink so that svscan
    # doesn't restart our service behind our back
    def disable
        # should stop the service
        # stop the log subservice if any
        log = File.join(self.service, "log")
        texecute("stop log", [ command(:svc) , '-dx', log] ) if FileTest.directory?(log)
        
        # stop the main resource
        texecute("stop", [command(:svc), '-dx', self.service] )

        # unlink the daemon symlink to disable it
        File.unlink(self.service) if FileTest.symlink?(self.service)
    end

    def enabled?
        FileTest.symlink?(self.service)
    end

    def enable
        File.symlink(self.daemon, self.service) if ! FileTest.symlink?(self.service)
    end
end