class Puppet::Util::Windows::Daemon
The Daemon class, based on the chef/win32-service implementation
Constants
- CONTINUE_PENDING
Servicehas received a signal to resume but is not yet running- CONTROL_CONTINUE
Notifies service that it should resume
- CONTROL_INTERROGATE
Notifies service that it should return its current status information
- CONTROL_NETBINDADD
Notifies a service that there is a new component for binding
- CONTROL_NETBINDDISABLE
Notifies a service that a component for binding has been disabled
- CONTROL_NETBINDENABLE
Notifies a service that a component for binding has been enabled
- CONTROL_NETBINDREMOVE
Notifies a service that a component for binding has been removed
- CONTROL_PARAMCHANGE
Notifies a service that its parameters have changed
- CONTROL_PAUSE
Notifies service that it should pause
- CONTROL_STOP
Notifies service that it should stop
- ERROR_CALL_NOT_IMPLEMENTED
- IDLE
- IDLE_CONTROL_CODE
Misc
- NO_ERROR
- PAUSED
Serviceis paused- PAUSE_PENDING
Servicehas received a signal to pause but is not yet paused- RUNNING
Serviceis running- START_PENDING
Servicehas received a start signal but is not yet running- STOPPED
Serviceis not running- STOP_PENDING
Servicehas received a stop signal but is not yet stopped- Service_Ctrl_ex
Handles control signals from the service control manager.
- Service_Main
Called by the service control manager after the call to StartServiceCtrlDispatcher.
- SetTheServiceStatus
Wraps SetServiceStatus.
- ThreadProc
- WAIT_FAILED
- WAIT_OBJECT_0
- WAIT_TIMEOUT
Public Class Methods
This is a shortcut for Daemon.new + Daemon#mainloop.
# File lib/puppet/util/windows/daemon.rb 213 def self.mainloop 214 self.new.mainloop 215 end
Public Instance Methods
This is the method that actually puts your code into a loop and allows it to run as a service. The code that is actually run while in the mainloop is what you defined in your own Daemon#service_main method.
# File lib/puppet/util/windows/daemon.rb 221 def mainloop 222 @@waiting_control_code = IDLE_CONTROL_CODE 223 @@dwServiceState = 0 224 225 # Redirect STDIN, STDOUT and STDERR to the NUL device if they're still 226 # associated with a tty. This helps newbs avoid Errno::EBADF errors. 227 STDIN.reopen('NUL') if STDIN.isatty 228 STDOUT.reopen('NUL') if STDOUT.isatty 229 STDERR.reopen('NUL') if STDERR.isatty 230 231 # Calling init here so that init failures never even tries to start the 232 # service. Of course that means that init methods must be very quick 233 # because the SCM will be receiving no START_PENDING messages while 234 # init's running. 235 # 236 # TODO: Fix? 237 service_init() if respond_to?('service_init') 238 239 # Create the event to signal the service to start. 240 @@hStartEvent = CreateEventW(nil, 1, 0, nil) 241 242 if @@hStartEvent == 0 243 raise SystemCallError.new('CreateEvent', FFI.errno) 244 end 245 246 # Create the event to signal the service to stop. 247 @@hStopEvent = CreateEventW(nil, 1, 0, nil) 248 249 if @@hStopEvent == 0 250 raise SystemCallError.new('CreateEvent', FFI.errno) 251 end 252 253 # Create the event to signal the service that stop has completed 254 @@hStopCompletedEvent = CreateEventW(nil, 1, 0, nil) 255 256 if @@hStopCompletedEvent == 0 257 raise SystemCallError.new('CreateEvent', FFI.errno) 258 end 259 260 hThread = CreateThread(nil, 0, ThreadProc, Service_Main, 0, nil) 261 262 if hThread == 0 263 raise SystemCallError.new('CreateThread', FFI.errno) 264 end 265 266 events = FFI::MemoryPointer.new(:pointer, 2) 267 events.put_pointer(0, FFI::Pointer.new(hThread)) 268 events.put_pointer(FFI::Pointer.size, FFI::Pointer.new(@@hStartEvent)) 269 270 while ((index = WaitForMultipleObjects(2, events, 0, 1000)) == WAIT_TIMEOUT) do 271 end 272 273 if index == WAIT_FAILED 274 raise SystemCallError.new('WaitForMultipleObjects', FFI.errno) 275 end 276 277 # The thread exited, so the show is off. 278 if index == WAIT_OBJECT_0 279 raise "Service_Main thread exited abnormally" 280 end 281 282 thr = Thread.new do 283 begin 284 while(WaitForSingleObject(@@hStopEvent, 1000) == WAIT_TIMEOUT) 285 # Check to see if anything interesting has been signaled 286 case @@waiting_control_code 287 when SERVICE_CONTROL_PAUSE 288 service_pause() if respond_to?('service_pause') 289 when SERVICE_CONTROL_CONTINUE 290 service_resume() if respond_to?('service_resume') 291 when SERVICE_CONTROL_INTERROGATE 292 service_interrogate() if respond_to?('service_interrogate') 293 when SERVICE_CONTROL_SHUTDOWN 294 service_shutdown() if respond_to?('service_shutdown') 295 when SERVICE_CONTROL_PARAMCHANGE 296 service_paramchange() if respond_to?('service_paramchange') 297 when SERVICE_CONTROL_NETBINDADD 298 service_netbindadd() if respond_to?('service_netbindadd') 299 when SERVICE_CONTROL_NETBINDREMOVE 300 service_netbindremove() if respond_to?('service_netbindremove') 301 when SERVICE_CONTROL_NETBINDENABLE 302 service_netbindenable() if respond_to?('service_netbindenable') 303 when SERVICE_CONTROL_NETBINDDISABLE 304 service_netbinddisable() if respond_to?('service_netbinddisable') 305 end 306 @@waiting_control_code = IDLE_CONTROL_CODE 307 end 308 309 service_stop() if respond_to?('service_stop') 310 ensure 311 SetEvent(@@hStopCompletedEvent) 312 end 313 end 314 315 if respond_to?('service_main') 316 service_main(*@@Argv) 317 end 318 319 thr.join 320 end
Returns whether or not the service is in a running state, i.e. the service status is either RUNNING, PAUSED or IDLE.
This is typically used within your service_main method to setup the main loop. For example:
class MyDaemon < Daemon def service_main while running? # Your main loop here end end end
# File lib/puppet/util/windows/daemon.rb 357 def running? 358 [SERVICE_RUNNING, SERVICE_PAUSED, 0].include?(@@dwServiceState) 359 end
Returns the state of the service (as an constant integer) which can be any of the service status constants, e.g. RUNNING, PAUSED, etc.
This method is typically used within your service_main method to setup the loop. For example:
class MyDaemon < Daemon def service_main while state == RUNNING || state == PAUSED || state == IDLE # Your main loop here end end end
See the Daemon#running? method for an abstraction of the above code.
# File lib/puppet/util/windows/daemon.rb 338 def state 339 @@dwServiceState 340 end