class Puppet::Util::Windows::Daemon
The Daemon
class, based on the chef/win32-service implementation
Constants
- CONTINUE_PENDING
Service
has 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
Service
is paused- PAUSE_PENDING
Service
has received a signal to pause but is not yet paused- RUNNING
Service
is running- START_PENDING
Service
has received a start signal but is not yet running- STOPPED
Service
is not running- STOP_PENDING
Service
has 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 212 def self.mainloop 213 self.new.mainloop 214 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 220 def mainloop 221 @@waiting_control_code = IDLE_CONTROL_CODE 222 @@dwServiceState = 0 223 224 # Redirect STDIN, STDOUT and STDERR to the NUL device if they're still 225 # associated with a tty. This helps newbs avoid Errno::EBADF errors. 226 STDIN.reopen('NUL') if STDIN.isatty 227 STDOUT.reopen('NUL') if STDOUT.isatty 228 STDERR.reopen('NUL') if STDERR.isatty 229 230 # Calling init here so that init failures never even tries to start the 231 # service. Of course that means that init methods must be very quick 232 # because the SCM will be receiving no START_PENDING messages while 233 # init's running. 234 # 235 # TODO: Fix? 236 service_init() if respond_to?('service_init') 237 238 # Create the event to signal the service to start. 239 @@hStartEvent = CreateEventW(nil, 1, 0, nil) 240 241 if @@hStartEvent == 0 242 raise SystemCallError.new('CreateEvent', FFI.errno) 243 end 244 245 # Create the event to signal the service to stop. 246 @@hStopEvent = CreateEventW(nil, 1, 0, nil) 247 248 if @@hStopEvent == 0 249 raise SystemCallError.new('CreateEvent', FFI.errno) 250 end 251 252 # Create the event to signal the service that stop has completed 253 @@hStopCompletedEvent = CreateEventW(nil, 1, 0, nil) 254 255 if @@hStopCompletedEvent == 0 256 raise SystemCallError.new('CreateEvent', FFI.errno) 257 end 258 259 hThread = CreateThread(nil, 0, ThreadProc, Service_Main, 0, nil) 260 261 if hThread == 0 262 raise SystemCallError.new('CreateThread', FFI.errno) 263 end 264 265 events = FFI::MemoryPointer.new(:pointer, 2) 266 events.put_pointer(0, FFI::Pointer.new(hThread)) 267 events.put_pointer(FFI::Pointer.size, FFI::Pointer.new(@@hStartEvent)) 268 269 while ((index = WaitForMultipleObjects(2, events, 0, 1000)) == WAIT_TIMEOUT) do 270 end 271 272 if index == WAIT_FAILED 273 raise SystemCallError.new('WaitForMultipleObjects', FFI.errno) 274 end 275 276 # The thread exited, so the show is off. 277 if index == WAIT_OBJECT_0 278 raise "Service_Main thread exited abnormally" 279 end 280 281 thr = Thread.new do 282 begin 283 while(WaitForSingleObject(@@hStopEvent, 1000) == WAIT_TIMEOUT) 284 # Check to see if anything interesting has been signaled 285 case @@waiting_control_code 286 when SERVICE_CONTROL_PAUSE 287 service_pause() if respond_to?('service_pause') 288 when SERVICE_CONTROL_CONTINUE 289 service_resume() if respond_to?('service_resume') 290 when SERVICE_CONTROL_INTERROGATE 291 service_interrogate() if respond_to?('service_interrogate') 292 when SERVICE_CONTROL_SHUTDOWN 293 service_shutdown() if respond_to?('service_shutdown') 294 when SERVICE_CONTROL_PARAMCHANGE 295 service_paramchange() if respond_to?('service_paramchange') 296 when SERVICE_CONTROL_NETBINDADD 297 service_netbindadd() if respond_to?('service_netbindadd') 298 when SERVICE_CONTROL_NETBINDREMOVE 299 service_netbindremove() if respond_to?('service_netbindremove') 300 when SERVICE_CONTROL_NETBINDENABLE 301 service_netbindenable() if respond_to?('service_netbindenable') 302 when SERVICE_CONTROL_NETBINDDISABLE 303 service_netbinddisable() if respond_to?('service_netbinddisable') 304 end 305 @@waiting_control_code = IDLE_CONTROL_CODE 306 end 307 308 service_stop() if respond_to?('service_stop') 309 ensure 310 SetEvent(@@hStopCompletedEvent) 311 end 312 end 313 314 if respond_to?('service_main') 315 service_main(*@@Argv) 316 end 317 318 thr.join 319 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 356 def running? 357 [SERVICE_RUNNING, SERVICE_PAUSED, 0].include?(@@dwServiceState) 358 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 337 def state 338 @@dwServiceState 339 end