Module: Puppet::Util::Windows::Service
- Extended by:
- FFI::Library, String
- Defined in:
- lib/puppet/util/windows/service.rb
Overview
This module is designed to provide an API between the windows system and puppet for service management.
for an overview of the service state transitions see: docs.microsoft.com/en-us/windows/desktop/Services/service-status-transitions
Defined Under Namespace
Classes: ENUM_SERVICE_STATUS_PROCESSW, QUERY_SERVICE_CONFIGW, SERVICE_STATUS, SERVICE_STATUS_PROCESS
Constant Summary collapse
- FILE =
Puppet::Util::Windows::File
- DEFAULT_TIMEOUT =
integer value of the floor for timeouts when waiting for service pending states. puppet will wait the length of dwWaitHint if it is longer than this value, but no shorter
30- SERVICE_CONTROL_STOP =
Service control codes docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-controlserviceexw
0x00000001- SERVICE_CONTROL_PAUSE =
0x00000002- SERVICE_CONTROL_CONTINUE =
0x00000003- SERVICE_CONTROL_INTERROGATE =
0x00000004- SERVICE_CONTROL_SHUTDOWN =
0x00000005- SERVICE_CONTROL_PARAMCHANGE =
0x00000006- SERVICE_CONTROL_NETBINDADD =
0x00000007- SERVICE_CONTROL_NETBINDREMOVE =
0x00000008- SERVICE_CONTROL_NETBINDENABLE =
0x00000009- SERVICE_CONTROL_NETBINDDISABLE =
0x0000000A
- SERVICE_CONTROL_DEVICEEVENT =
0x0000000B
- SERVICE_CONTROL_HARDWAREPROFILECHANGE =
0x0000000C
- SERVICE_CONTROL_POWEREVENT =
0x0000000D
- SERVICE_CONTROL_SESSIONCHANGE =
0x0000000E
- SERVICE_CONTROL_PRESHUTDOWN =
0x0000000F
- SERVICE_CONTROL_TIMECHANGE =
0x00000010- SERVICE_CONTROL_TRIGGEREVENT =
0x00000020- SERVICE_AUTO_START =
Service start type codes docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-changeserviceconfigw
0x00000002- SERVICE_BOOT_START =
0x00000000- SERVICE_DEMAND_START =
0x00000003- SERVICE_DISABLED =
0x00000004- SERVICE_SYSTEM_START =
0x00000001- SERVICE_START_TYPES =
{ SERVICE_AUTO_START => :SERVICE_AUTO_START, SERVICE_BOOT_START => :SERVICE_BOOT_START, SERVICE_DEMAND_START => :SERVICE_DEMAND_START, SERVICE_DISABLED => :SERVICE_DISABLED, SERVICE_SYSTEM_START => :SERVICE_SYSTEM_START, }
- SERVICE_FILE_SYSTEM_DRIVER =
0x00000002- SERVICE_KERNEL_DRIVER =
0x00000001- SERVICE_WIN32_OWN_PROCESS =
0x00000010- SERVICE_WIN32_SHARE_PROCESS =
0x00000020- SERVICE_USER_OWN_PROCESS =
0x00000050- SERVICE_USER_SHARE_PROCESS =
0x00000060- SERVICE_INTERACTIVE_PROCESS =
Available only if service is also SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS
0x00000100- ALL_SERVICE_TYPES =
SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER | SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
- SERVICE_CONTINUE_PENDING =
0x00000005- SERVICE_PAUSE_PENDING =
0x00000006- SERVICE_PAUSED =
0x00000007- SERVICE_RUNNING =
0x00000004- SERVICE_START_PENDING =
0x00000002- SERVICE_STOP_PENDING =
0x00000003- SERVICE_STOPPED =
0x00000001- SERVICE_STATES =
{ SERVICE_CONTINUE_PENDING => :SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING => :SERVICE_PAUSE_PENDING, SERVICE_PAUSED => :SERVICE_PAUSED, SERVICE_RUNNING => :SERVICE_RUNNING, SERVICE_START_PENDING => :SERVICE_START_PENDING, SERVICE_STOP_PENDING => :SERVICE_STOP_PENDING, SERVICE_STOPPED => :SERVICE_STOPPED, }
- SERVICE_ACCEPT_STOP =
Service accepts control codes docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_status_process
0x00000001- SERVICE_ACCEPT_PAUSE_CONTINUE =
0x00000002- SERVICE_ACCEPT_SHUTDOWN =
0x00000004- SERVICE_ACCEPT_PARAMCHANGE =
0x00000008- SERVICE_ACCEPT_NETBINDCHANGE =
0x00000010- SERVICE_ACCEPT_HARDWAREPROFILECHANGE =
0x00000020- SERVICE_ACCEPT_POWEREVENT =
0x00000040- SERVICE_ACCEPT_SESSIONCHANGE =
0x00000080- SERVICE_ACCEPT_PRESHUTDOWN =
0x00000100- SERVICE_ACCEPT_TIMECHANGE =
0x00000200- SERVICE_ACCEPT_TRIGGEREVENT =
0x00000400- SERVICE_ACCEPT_USER_LOGOFF =
0x00000800- SC_MANAGER_CREATE_SERVICE =
Service manager access codes docs.microsoft.com/en-us/windows/desktop/Services/service-security-and-access-rights
0x00000002- SC_MANAGER_CONNECT =
0x00000001- SC_MANAGER_ENUMERATE_SERVICE =
0x00000004- SC_MANAGER_LOCK =
0x00000008- SC_MANAGER_MODIFY_BOOT_CONFIG =
0x00000020- SC_MANAGER_QUERY_LOCK_STATUS =
0x00000010- SC_MANAGER_ALL_ACCESS =
FILE::STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_MODIFY_BOOT_CONFIG | SC_MANAGER_QUERY_LOCK_STATUS
- SERVICE_CHANGE_CONFIG =
Service access codes docs.microsoft.com/en-us/windows/desktop/Services/service-security-and-access-rights
0x0002- SERVICE_ENUMERATE_DEPENDENTS =
0x0008- SERVICE_INTERROGATE =
0x0080- SERVICE_PAUSE_CONTINUE =
0x0040- SERVICE_QUERY_STATUS =
0x0004- SERVICE_QUERY_CONFIG =
0x0001- SERVICE_START =
0x0010- SERVICE_STOP =
0x0020- SERVICE_USER_DEFINED_CONTROL =
0x0100- SERVICE_ALL_ACCESS =
FILE::STANDARD_RIGHTS_REQUIRED | SERVICE_CHANGE_CONFIG | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE | SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_START | SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL
- SERVICE_NO_CHANGE =
Service config codes From the windows 10 SDK: // // Value to indicate no change to an optional parameter // #define SERVICE_NO_CHANGE 0xffffffff
0xffffffff- SERVICE_ACTIVE =
0x00000001- SERVICE_INACTIVE =
0x00000002- SERVICE_STATE_ALL =
SERVICE_ACTIVE | SERVICE_INACTIVE
- SERVICENAME_MAX =
256- SC_STATUS_TYPE =
docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryservicestatusex BOOL QueryServiceStatusEx(
SC_HANDLE hService, SC_STATUS_TYPE InfoLevel, LPBYTE lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded);
enum( :SC_STATUS_PROCESS_INFO, 0, )
- SC_ENUM_TYPE =
docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexw BOOL EnumServicesStatusExW(
SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType, DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName);
enum( :SC_ENUM_PROCESS_INFO, 0, )
Class Method Summary collapse
-
.milliseconds_to_seconds(wait_hint) ⇒ Integer
private
process the wait hint listed by a service to something usable by ruby sleep.
-
.open_scm(scm_access, &block) ⇒ Object
private
Opens a handle to the service control manager.
-
.open_service(service_name, scm_access, service_access) {|service| ... } ⇒ Object
private
Opens a connection to the SCManager on windows then uses that handle to create a handle to a specific service in windows corresponding to service_name.
-
.query_config(service) ⇒ QUERY_SERVICE_CONFIGW struct
private
perform QueryServiceConfigW on a windows service and return the result.
-
.query_status(service) ⇒ SERVICE_STATUS_PROCESS struct
private
perform QueryServiceStatusEx on a windows service and return the result.
-
.service_start_type(service_name) ⇒ QUERY_SERVICE_CONFIGW.struct
Query the configuration of a service using QueryServiceConfigW.
-
.service_state(service_name) ⇒ string
Query the state of a service using QueryServiceStatusEx.
-
.services ⇒ Hash
enumerate over all services in all states and return them as a hash.
-
.set_startup_mode(service_name, startup_type) ⇒ Object
Change the startup mode of a windows service.
-
.start(service_name) ⇒ Object
Start a windows service, assume that the service is already in the stopped state.
-
.stop(service_name) ⇒ Object
Use ControlService to send a stop signal to a windows service.
-
.wait_for_pending_transition(service, pending_state, final_state) ⇒ bool
private
waits for a windows service to report final_state if it is in pending_state.
-
.wait_hint_to_wait_time(wait_hint) ⇒ Integer
private
create a usable wait time to wait between querying the service.
Methods included from FFI::Library
Methods included from String
Class Method Details
.milliseconds_to_seconds(wait_hint) ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
process the wait hint listed by a service to something usable by ruby sleep
628 629 630 |
# File 'lib/puppet/util/windows/service.rb', line 628 def milliseconds_to_seconds(wait_hint) wait_hint / 1000; end |
.open_scm(scm_access, &block) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Opens a handle to the service control manager
476 477 478 479 480 481 482 |
# File 'lib/puppet/util/windows/service.rb', line 476 def open_scm(scm_access, &block) scm = OpenSCManagerW(FFI::Pointer::NULL, FFI::Pointer::NULL, scm_access) raise Puppet::Util::Windows::Error.new(_("Failed to open a handle to the service control manager")) if scm == FFI::Pointer::NULL_HANDLE yield scm ensure CloseServiceHandle(scm) end |
.open_service(service_name, scm_access, service_access) {|service| ... } ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Opens a connection to the SCManager on windows then uses that handle to create a handle to a specific service in windows corresponding to service_name
this function takes a block that executes within the context of the open service handler, and will close the service and SCManager handles once the block finishes
459 460 461 462 463 464 465 466 467 468 |
# File 'lib/puppet/util/windows/service.rb', line 459 def open_service(service_name, scm_access, service_access, &block) service = FFI::Pointer::NULL_HANDLE open_scm(scm_access) do |scm| service = OpenServiceW(scm, wide_string(service_name), service_access) raise Puppet::Util::Windows::Error.new(_("Failed to open a handle to the service")) if service == FFI::Pointer::NULL_HANDLE yield service end ensure CloseServiceHandle(service) end |
.query_config(service) ⇒ QUERY_SERVICE_CONFIGW struct
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
perform QueryServiceConfigW on a windows service and return the result
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
# File 'lib/puppet/util/windows/service.rb', line 534 def query_config(service) config = nil size_required = nil # Fetch the bytes of memory required to be allocated # for QueryServiceConfigW to return succesfully. This # is done by sending NULL and 0 for the pointer and size # respectively, letting the command fail, then reading the # value of pcbBytesNeeded FFI::MemoryPointer.new(:lpword) do |bytes_pointer| # return value will be false from this call, since it's designed # to fail. Just ignore it QueryServiceConfigW(service, FFI::Pointer::NULL, 0, bytes_pointer) size_required = bytes_pointer.read_dword FFI::MemoryPointer.new(size_required) do |ssp_ptr| config = QUERY_SERVICE_CONFIGW.new(ssp_ptr) success = QueryServiceConfigW( service, ssp_ptr, size_required, bytes_pointer ) if success == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Service query failed")) end end end config end |
.query_status(service) ⇒ SERVICE_STATUS_PROCESS struct
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
perform QueryServiceStatusEx on a windows service and return the result
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
# File 'lib/puppet/util/windows/service.rb', line 491 def query_status(service) size_required = nil status = nil # Fetch the bytes of memory required to be allocated # for QueryServiceConfigW to return succesfully. This # is done by sending NULL and 0 for the pointer and size # respectively, letting the command fail, then reading the # value of pcbBytesNeeded FFI::MemoryPointer.new(:lpword) do |bytes_pointer| # return value will be false from this call, since it's designed # to fail. Just ignore it QueryServiceStatusEx( service, :SC_STATUS_PROCESS_INFO, FFI::Pointer::NULL, 0, bytes_pointer ) size_required = bytes_pointer.read_dword FFI::MemoryPointer.new(size_required) do |ssp_ptr| status = SERVICE_STATUS_PROCESS.new(ssp_ptr) success = QueryServiceStatusEx( service, :SC_STATUS_PROCESS_INFO, ssp_ptr, size_required, bytes_pointer ) if success == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Service query failed")) end end end status end |
.service_start_type(service_name) ⇒ QUERY_SERVICE_CONFIGW.struct
Query the configuration of a service using QueryServiceConfigW
314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/puppet/util/windows/service.rb', line 314 def service_start_type(service_name) config = nil open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_CONFIG) do |service| config = query_config(service) end start_type = SERVICE_START_TYPES[config[:dwStartType]] if start_type.nil? raise Puppet::Error.new(_("Unknown start type '%{start_type}' for '%{service_name}'") % { start_type: config[:dwStartType].to_s, service_name: service_name}) end start_type end |
.service_state(service_name) ⇒ string
Query the state of a service using QueryServiceStatusEx
297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/puppet/util/windows/service.rb', line 297 def service_state(service_name) status = nil open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_STATUS) do |service| status = query_status(service) end state = SERVICE_STATES[status[:dwCurrentState]] if state.nil? raise Puppet::Error.new(_("Unknown Service state '%{current_state}' for '%{service_name}'") % { current_state: status[:dwCurrentState].to_s, service_name: service_name}) end state end |
.services ⇒ Hash
enumerate over all services in all states and return them as a hash
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/puppet/util/windows/service.rb', line 371 def services services = {} open_scm(SC_MANAGER_ENUMERATE_SERVICE) do |scm| size_required = 0 services_returned = 0 FFI::MemoryPointer.new(:dword) do |bytes_pointer| FFI::MemoryPointer.new(:dword) do |svcs_ret_ptr| FFI::MemoryPointer.new(:dword) do |resume_ptr| resume_ptr.write_dword(0) # Fetch the bytes of memory required to be allocated # for QueryServiceConfigW to return succesfully. This # is done by sending NULL and 0 for the pointer and size # respectively, letting the command fail, then reading the # value of pcbBytesNeeded # # return value will be false from this call, since it's designed # to fail. Just ignore it EnumServicesStatusExW( scm, :SC_ENUM_PROCESS_INFO, ALL_SERVICE_TYPES, SERVICE_STATE_ALL, FFI::Pointer::NULL, 0, bytes_pointer, svcs_ret_ptr, resume_ptr, FFI::Pointer::NULL ) size_required = bytes_pointer.read_dword FFI::MemoryPointer.new(size_required) do |buffer_ptr| resume_ptr.write_dword(0) svcs_ret_ptr.write_dword(0) success = EnumServicesStatusExW( scm, :SC_ENUM_PROCESS_INFO, ALL_SERVICE_TYPES, SERVICE_STATE_ALL, buffer_ptr, buffer_ptr.size, bytes_pointer, svcs_ret_ptr, resume_ptr, FFI::Pointer::NULL ) if success == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Failed to fetch services")) end # Now that the buffer is populated with services # we pull the data from memory using pointer arithmetic: # the number of services returned by the function is # available to be read from svcs_ret_ptr, and we iterate # that many times moving the cursor pointer the length of # ENUM_SERVICE_STATUS_PROCESSW.size. This should iterate # over the buffer and extract each struct. services_returned = svcs_ret_ptr.read_dword cursor_ptr = FFI::Pointer.new(ENUM_SERVICE_STATUS_PROCESSW, buffer_ptr) 0.upto(services_returned - 1) do |index| service = ENUM_SERVICE_STATUS_PROCESSW.new(cursor_ptr[index]) services[service[:lpServiceName].read_arbitrary_wide_string_up_to(SERVICENAME_MAX)] = { :display_name => service[:lpDisplayName].read_arbitrary_wide_string_up_to(SERVICENAME_MAX), :service_status_process => service[:ServiceStatusProcess] } end end # buffer_ptr end # resume_ptr end # scvs_ret_ptr end # bytes_ptr end # open_scm services end |
.set_startup_mode(service_name, startup_type) ⇒ Object
Change the startup mode of a windows service
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/puppet/util/windows/service.rb', line 333 def set_startup_mode(service_name, startup_type) startup_code = SERVICE_START_TYPES.key(startup_type) if startup_code.nil? raise Puppet::Error.new(_("Unknown start type %{start_type}") % {startup_type: startup_type.to_s}) end open_service(service_name, SC_MANAGER_CONNECT, SERVICE_CHANGE_CONFIG) do |service| # Currently the only thing puppet's API can really manage # in this list is dwStartType (the third param). Thus no # generic function was written to make use of all the params # since the API as-is couldn't use them anyway success = ChangeServiceConfigW( service, SERVICE_NO_CHANGE, # dwServiceType startup_code, # dwStartType SERVICE_NO_CHANGE, # dwErrorControl FFI::Pointer::NULL, # lpBinaryPathName FFI::Pointer::NULL, # lpLoadOrderGroup FFI::Pointer::NULL, # lpdwTagId FFI::Pointer::NULL, # lpDependencies FFI::Pointer::NULL, # lpServiceStartName FFI::Pointer::NULL, # lpPassword FFI::Pointer::NULL # lpDisplayName ) if success == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Failed to update service configuration")) end end end |
.start(service_name) ⇒ Object
Start a windows service, assume that the service is already in the stopped state
255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/puppet/util/windows/service.rb', line 255 def start(service_name) open_service(service_name, SC_MANAGER_CONNECT, SERVICE_START | SERVICE_QUERY_STATUS) do |service| # don't attempt to fail here if the service isn't stopped because windows error codes # are likely more informative than ours and a failed call to StartServiceW will produce # those errors wait_for_pending_transition(service, SERVICE_STOP_PENDING, SERVICE_STOPPED) if StartServiceW(service, 0, FFI::Pointer::NULL) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Failed to start the service")) end unless wait_for_pending_transition(service, SERVICE_START_PENDING, SERVICE_RUNNING) raise Puppet::Error.new(_("Failed to start the service, after calling StartService the service is not in SERVICE_START_PENDING or SERVICE_RUNNING")) end end end |
.stop(service_name) ⇒ Object
Use ControlService to send a stop signal to a windows service
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/puppet/util/windows/service.rb', line 274 def stop(service_name) open_service(service_name, SC_MANAGER_CONNECT, SERVICE_STOP | SERVICE_QUERY_STATUS) do |service| FFI::MemoryPointer.new(SERVICE_STATUS.size) do |status_ptr| status = SERVICE_STATUS.new(status_ptr) # don't attempt to fail here if the service isn't started because windows error codes # are likely more informative than ours and a failed call to ControlService will produce # those errors wait_for_pending_transition(service, SERVICE_START_PENDING, SERVICE_RUNNING) if ControlService(service, SERVICE_CONTROL_STOP, status) == FFI::WIN32_FALSE raise Puppet::Util::Windows::Error.new(_("Failed to send stop control to service, current state is %{current_state}. Failed with") % { current_state: status[:dwCurrentState].to_s }) end unless wait_for_pending_transition(service, SERVICE_STOP_PENDING, SERVICE_STOPPED) raise Puppet::Error.new(_("Failed to stop the service, after calling ControlService the service is not in SERVICE_STOP_PENDING or SERVICE_STOPPED")) end end end end |
.wait_for_pending_transition(service, pending_state, final_state) ⇒ bool
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
waits for a windows service to report final_state if it is in pending_state
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/puppet/util/windows/service.rb', line 573 def wait_for_pending_transition(service, pending_state, final_state) elapsed_time = 0 last_checkpoint = -1 loop do status = query_status(service) state = status[:dwCurrentState] return true if state == final_state unless state == pending_state return false end # When the service is in the pending state we need to do the following: # 1. check if any progress has been made since dwWaitHint using dwCheckPoint, # and fail if no progress was made # 2. if progress has been made, increment elapsed_time and set last_checkpoint # 3. sleep, then loop again if there was progress. time_to_wait = wait_hint_to_wait_time(status[:dwWaitHint]) if status[:dwCheckPoint] > last_checkpoint elapsed_time = 0 else timeout = milliseconds_to_seconds(status[:dwWaitHint]); timeout = DEFAULT_TIMEOUT if timeout < DEFAULT_TIMEOUT if elapsed_time >= (timeout) raise Puppet::Error.new(_("No progress made on service operation and dwWaitHint exceeded")) end end last_checkpoint = status[:dwCheckPoint] sleep(time_to_wait) elapsed_time += time_to_wait end end |
.wait_hint_to_wait_time(wait_hint) ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
create a usable wait time to wait between querying the service.
611 612 613 614 615 616 617 618 |
# File 'lib/puppet/util/windows/service.rb', line 611 def wait_hint_to_wait_time(wait_hint) # Wait 1/10th the wait_hint, but no less than 1 and # no more than 10 seconds wait_time = milliseconds_to_seconds(wait_hint) / 10; wait_time = 1 if wait_time < 1 wait_time = 10 if wait_time > 10 wait_time end |