puppet 6.0.2-x64-mingw32 → 6.0.3-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +11 -11
- data/lib/puppet/application.rb +5 -0
- data/lib/puppet/application/apply.rb +1 -0
- data/lib/puppet/application/script.rb +1 -1
- data/lib/puppet/application/ssl.rb +119 -49
- data/lib/puppet/defaults.rb +9 -27
- data/lib/puppet/face/node/clean.rb +0 -1
- data/lib/puppet/feature/base.rb +1 -1
- data/lib/puppet/file_serving/fileset.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +4 -2
- data/lib/puppet/provider/package/windows.rb +2 -2
- data/lib/puppet/provider/package/windows/exe_package.rb +3 -10
- data/lib/puppet/provider/service/windows.rb +11 -3
- data/lib/puppet/provider/user/useradd.rb +2 -10
- data/lib/puppet/resource/catalog.rb +1 -5
- data/lib/puppet/ssl/host.rb +7 -9
- data/lib/puppet/transaction/persistence.rb +1 -1
- data/lib/puppet/type/package.rb +1 -1
- data/lib/puppet/type/user.rb +4 -1
- data/lib/puppet/util.rb +7 -3
- data/lib/puppet/util/execution.rb +1 -0
- data/lib/puppet/util/logging.rb +3 -2
- data/lib/puppet/util/windows/process.rb +6 -2
- data/lib/puppet/util/windows/security.rb +14 -0
- data/lib/puppet/util/windows/service.rb +217 -74
- data/lib/puppet/util/windows/user.rb +3 -5
- data/lib/puppet/version.rb +1 -1
- data/locales/ja/puppet.po +505 -276
- data/locales/puppet.pot +250 -111
- data/man/man5/puppet.conf.5 +8 -1
- data/man/man8/puppet-ssl.8 +22 -2
- data/man/man8/puppet.8 +1 -1
- data/spec/integration/parser/collection_spec.rb +4 -8
- data/spec/integration/type/file_spec.rb +6 -6
- data/spec/integration/util/windows/security_spec.rb +10 -7
- data/spec/integration/util/windows/user_spec.rb +37 -17
- data/spec/lib/puppet/test_ca.rb +1 -1
- data/spec/unit/agent_spec.rb +2 -2
- data/spec/unit/application/apply_spec.rb +41 -2
- data/spec/unit/application/face_base_spec.rb +1 -1
- data/spec/unit/application/ssl_spec.rb +160 -110
- data/spec/unit/application_spec.rb +29 -11
- data/spec/unit/configurer/downloader_spec.rb +1 -1
- data/spec/unit/configurer_spec.rb +5 -5
- data/spec/unit/face/node_spec.rb +1 -3
- data/spec/unit/file_serving/fileset_spec.rb +11 -11
- data/spec/unit/network/http/connection_spec.rb +2 -2
- data/spec/unit/pops/validator/validator_spec.rb +24 -10
- data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
- data/spec/unit/provider/package/windows_spec.rb +4 -4
- data/spec/unit/provider/service/windows_spec.rb +21 -3
- data/spec/unit/provider/user/useradd_spec.rb +2 -2
- data/spec/unit/resource/catalog_spec.rb +2 -2
- data/spec/unit/ssl/host_spec.rb +1 -1
- data/spec/unit/transaction/persistence_spec.rb +4 -4
- data/spec/unit/util/execution_spec.rb +19 -1
- data/spec/unit/util/logging_spec.rb +58 -0
- data/spec/unit/util/windows/service_spec.rb +344 -191
- metadata +2 -2
| @@ -59,7 +59,6 @@ Puppet::Face.define(:node, '0.0.1') do | |
| 59 59 | 
             
              # clean signed cert for +host+
         | 
| 60 60 | 
             
              def clean_cert(node)
         | 
| 61 61 | 
             
                if Puppet.features.puppetserver_ca?
         | 
| 62 | 
            -
                  require 'puppetserver/ca/action/clean'
         | 
| 63 62 | 
             
                  Puppetserver::Ca::Action::Clean.new(LoggerIO.new).run({ 'certnames' => [node] })
         | 
| 64 63 | 
             
                else
         | 
| 65 64 | 
             
                  Puppet.info _("Not managing %{node} certs as this host is not a CA") % { node: node }
         | 
    
        data/lib/puppet/feature/base.rb
    CHANGED
    
    
| @@ -559,6 +559,8 @@ class Checker4_0 < Evaluator::LiteralEvaluator | |
| 559 559 | 
             
                return if namespace_for_file(file) == NO_NAMESPACE
         | 
| 560 560 |  | 
| 561 561 | 
             
                body = prog.body
         | 
| 562 | 
            +
                return if prog.body.is_a?(Model::Nop) #Ignore empty or comment-only files
         | 
| 563 | 
            +
             | 
| 562 564 | 
             
                if(body.is_a?(Model::BlockExpression))
         | 
| 563 565 | 
             
                  body.statements.each { |s| acceptor.accept(Issues::ILLEGAL_TOP_CONSTRUCT_LOCATION, s) unless valid_top_construct?(s) }
         | 
| 564 566 | 
             
                else
         | 
| @@ -623,9 +625,9 @@ class Checker4_0 < Evaluator::LiteralEvaluator | |
| 623 625 |  | 
| 624 626 | 
             
              def is_parent_dir_of(parent_dir, child_dir)
         | 
| 625 627 | 
             
                parent_dir_path = Pathname.new(parent_dir)
         | 
| 626 | 
            -
                clean_parent = parent_dir_path.cleanpath
         | 
| 628 | 
            +
                clean_parent = parent_dir_path.cleanpath.to_s + File::SEPARATOR
         | 
| 627 629 |  | 
| 628 | 
            -
                return child_dir.to_s.start_with?(clean_parent | 
| 630 | 
            +
                return child_dir.to_s.start_with?(clean_parent)
         | 
| 629 631 | 
             
              end
         | 
| 630 632 |  | 
| 631 633 | 
             
              def dir_to_names(relative_path)
         | 
| @@ -63,14 +63,14 @@ Puppet::Type.type(:package).provide(:windows, :parent => Puppet::Provider::Packa | |
| 63 63 | 
             
                installer = Puppet::Provider::Package::Windows::Package.installer_class(resource)
         | 
| 64 64 |  | 
| 65 65 | 
             
                command = [installer.install_command(resource), install_options].flatten.compact.join(' ')
         | 
| 66 | 
            -
                output = execute(command, :failonfail => false, :combine => true)
         | 
| 66 | 
            +
                output = execute(command, :failonfail => false, :combine => true, :cwd => File.dirname(resource[:source]), :suppress_window => true)
         | 
| 67 67 |  | 
| 68 68 | 
             
                check_result(output.exitstatus)
         | 
| 69 69 | 
             
              end
         | 
| 70 70 |  | 
| 71 71 | 
             
              def uninstall
         | 
| 72 72 | 
             
                command = [package.uninstall_command, uninstall_options].flatten.compact.join(' ')
         | 
| 73 | 
            -
                output = execute(command, :failonfail => false, :combine => true)
         | 
| 73 | 
            +
                output = execute(command, :failonfail => false, :combine => true, :suppress_window => true)
         | 
| 74 74 |  | 
| 75 75 | 
             
                check_result(output.exitstatus)
         | 
| 76 76 | 
             
              end
         | 
| @@ -42,17 +42,10 @@ class Puppet::Provider::Package::Windows | |
| 42 42 | 
             
                end
         | 
| 43 43 |  | 
| 44 44 | 
             
                def self.install_command(resource)
         | 
| 45 | 
            -
                   | 
| 45 | 
            +
                  munge(resource[:source])
         | 
| 46 46 | 
             
                end
         | 
| 47 47 |  | 
| 48 48 | 
             
                def uninstall_command
         | 
| 49 | 
            -
                  # 1. Launch using cmd /c start because if the executable is a console
         | 
| 50 | 
            -
                  #    application Windows will automatically display its console window
         | 
| 51 | 
            -
                  # 2. Specify a quoted title, otherwise if uninstall_string is quoted,
         | 
| 52 | 
            -
                  #    start will interpret that to be the title, and get confused
         | 
| 53 | 
            -
                  # 3. Specify /w (wait) to wait for uninstall to finish
         | 
| 54 | 
            -
                  command = ['cmd.exe', '/c', 'start', '"puppet-uninstall"', '/w']
         | 
| 55 | 
            -
             | 
| 56 49 | 
             
                  # Only quote bare uninstall strings, e.g.
         | 
| 57 50 | 
             
                  #   C:\Program Files (x86)\Notepad++\uninstall.exe
         | 
| 58 51 | 
             
                  # Don't quote uninstall strings that are already quoted, e.g.
         | 
| @@ -60,9 +53,9 @@ class Puppet::Provider::Package::Windows | |
| 60 53 | 
             
                  # Don't quote uninstall strings that contain arguments:
         | 
| 61 54 | 
             
                  #   "C:\Program Files (x86)\Git\unins000.exe" /SILENT
         | 
| 62 55 | 
             
                  if uninstall_string =~ /\A[^"]*.exe\Z/i
         | 
| 63 | 
            -
                    command  | 
| 56 | 
            +
                    command = "\"#{uninstall_string}\""
         | 
| 64 57 | 
             
                  else
         | 
| 65 | 
            -
                    command  | 
| 58 | 
            +
                    command = uninstall_string
         | 
| 66 59 | 
             
                  end
         | 
| 67 60 |  | 
| 68 61 | 
             
                  command
         | 
| @@ -56,6 +56,13 @@ Puppet::Type.type(:service).provide :windows, :parent => :service do | |
| 56 56 | 
             
              end
         | 
| 57 57 |  | 
| 58 58 | 
             
              def start
         | 
| 59 | 
            +
                if status == :paused
         | 
| 60 | 
            +
                  Puppet::Util::Windows::Service.resume(@resource[:name])
         | 
| 61 | 
            +
                  return
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                # status == :stopped here
         | 
| 65 | 
            +
             | 
| 59 66 | 
             
                if enabled? == :false
         | 
| 60 67 | 
             
                  # If disabled and not managing enable, respect disabled and fail.
         | 
| 61 68 | 
             
                  if @resource[:enable].nil?
         | 
| @@ -81,10 +88,11 @@ Puppet::Type.type(:service).provide :windows, :parent => :service do | |
| 81 88 | 
             
                current_state = Puppet::Util::Windows::Service.service_state(@resource[:name])
         | 
| 82 89 | 
             
                state = case current_state
         | 
| 83 90 | 
             
                  when :SERVICE_STOPPED,
         | 
| 84 | 
            -
                       : | 
| 85 | 
            -
                       :SERVICE_STOP_PENDING,
         | 
| 86 | 
            -
                       :SERVICE_PAUSE_PENDING
         | 
| 91 | 
            +
                       :SERVICE_STOP_PENDING
         | 
| 87 92 | 
             
                    :stopped
         | 
| 93 | 
            +
                  when :SERVICE_PAUSED,
         | 
| 94 | 
            +
                       :SERVICE_PAUSE_PENDING
         | 
| 95 | 
            +
                    :paused
         | 
| 88 96 | 
             
                  when :SERVICE_RUNNING,
         | 
| 89 97 | 
             
                       :SERVICE_CONTINUE_PENDING,
         | 
| 90 98 | 
             
                       :SERVICE_START_PENDING
         | 
| @@ -134,15 +134,6 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ | |
| 134 134 | 
             
                cmd
         | 
| 135 135 | 
             
              end
         | 
| 136 136 |  | 
| 137 | 
            -
              def check_manage_expiry
         | 
| 138 | 
            -
                cmd = []
         | 
| 139 | 
            -
                if @resource[:expiry] and not @resource.forcelocal?
         | 
| 140 | 
            -
                  cmd << "-e #{@resource[:expiry]}"
         | 
| 141 | 
            -
                end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                cmd
         | 
| 144 | 
            -
              end
         | 
| 145 | 
            -
             | 
| 146 137 | 
             
              def check_system_users
         | 
| 147 138 | 
             
                if self.class.system_users? and resource.system?
         | 
| 148 139 | 
             
                  ["-r"]
         | 
| @@ -188,7 +179,8 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ | |
| 188 179 |  | 
| 189 180 | 
             
              def modifycmd(param, value)
         | 
| 190 181 | 
             
                if @resource.forcelocal?
         | 
| 191 | 
            -
                   | 
| 182 | 
            +
                  case param
         | 
| 183 | 
            +
                  when :groups, :expiry
         | 
| 192 184 | 
             
                    cmd = [command(:modify)]
         | 
| 193 185 | 
             
                  else
         | 
| 194 186 | 
             
                    cmd = [command(property_manages_password_age?(param) ? :localpassword : :localmodify)]
         | 
| @@ -558,11 +558,7 @@ class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph | |
| 558 558 | 
             
                Puppet::FileSystem.open(resourcefile.value, resourcefile.mode.to_i(8), "w:UTF-8") do |f|
         | 
| 559 559 | 
             
                  to_print = resources.map do |resource|
         | 
| 560 560 | 
             
                    next unless resource.managed?
         | 
| 561 | 
            -
                     | 
| 562 | 
            -
                      "#{resource.type}[#{resource[resource.name_var]}]"
         | 
| 563 | 
            -
                    else
         | 
| 564 | 
            -
                      "#{resource.ref.downcase}"
         | 
| 565 | 
            -
                    end
         | 
| 561 | 
            +
                    "#{resource.ref.downcase}"
         | 
| 566 562 | 
             
                  end.compact
         | 
| 567 563 | 
             
                  f.puts to_print.join("\n")
         | 
| 568 564 | 
             
                end
         | 
    
        data/lib/puppet/ssl/host.rb
    CHANGED
    
    | @@ -154,15 +154,14 @@ class Puppet::SSL::Host | |
| 154 154 | 
             
                raise Puppet::Error, _("No certificate to validate.") unless cert
         | 
| 155 155 | 
             
                raise Puppet::Error, _("No private key with which to validate certificate with fingerprint: %{fingerprint}") % { fingerprint: cert.fingerprint } unless key
         | 
| 156 156 | 
             
                unless cert.content.check_private_key(key.content)
         | 
| 157 | 
            -
                  raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: cert.fingerprint, cert_name: Puppet[:certname] | 
| 157 | 
            +
                  raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: cert.fingerprint, cert_name: Puppet[:certname] }
         | 
| 158 158 | 
             
            The certificate retrieved from the master does not match the agent's private key. Did you forget to run as root?
         | 
| 159 159 | 
             
            Certificate fingerprint: %{fingerprint}
         | 
| 160 160 | 
             
            To fix this, remove the certificate from both the master and the agent and then start a puppet run, which will automatically regenerate a certificate.
         | 
| 161 161 | 
             
            On the master:
         | 
| 162 162 | 
             
              puppetserver ca clean --certname %{cert_name}
         | 
| 163 163 | 
             
            On the agent:
         | 
| 164 | 
            -
               | 
| 165 | 
            -
              1b. On Windows: del "%{cert_dir}\\%{cert_name}.pem" /f
         | 
| 164 | 
            +
              1. puppet ssl clean
         | 
| 166 165 | 
             
              2. puppet agent -t
         | 
| 167 166 | 
             
            ERROR_STRING
         | 
| 168 167 | 
             
                end
         | 
| @@ -237,15 +236,14 @@ ERROR_STRING | |
| 237 236 |  | 
| 238 237 | 
             
              def validate_local_csr_with_key(csr, key)
         | 
| 239 238 | 
             
                if key.content.public_key.to_s != csr.content.public_key.to_s
         | 
| 240 | 
            -
                  raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: csr.fingerprint, csr_public_key: csr.content.public_key.to_text, agent_public_key: key.content.public_key.to_text | 
| 239 | 
            +
                  raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: csr.fingerprint, csr_public_key: csr.content.public_key.to_text, agent_public_key: key.content.public_key.to_text }
         | 
| 241 240 | 
             
            The local CSR does not match the agent's public key.
         | 
| 242 241 | 
             
            CSR fingerprint: %{fingerprint}
         | 
| 243 242 | 
             
            CSR public key: %{csr_public_key}
         | 
| 244 243 | 
             
            Agent public key: %{agent_public_key}
         | 
| 245 244 | 
             
            To fix this, remove the CSR from the agent and then start a puppet run, which will automatically regenerate a CSR.
         | 
| 246 245 | 
             
            On the agent:
         | 
| 247 | 
            -
               | 
| 248 | 
            -
              1b. On Windows: del "%{cert_dir}\\%{cert_name}.pem" /f
         | 
| 246 | 
            +
              1. puppet ssl clean
         | 
| 249 247 | 
             
              2. puppet agent -t
         | 
| 250 248 | 
             
            ERROR_STRING
         | 
| 251 249 | 
             
                end
         | 
| @@ -254,7 +252,7 @@ ERROR_STRING | |
| 254 252 |  | 
| 255 253 | 
             
              def validate_csr_with_key(csr, key)
         | 
| 256 254 | 
             
                if key.content.public_key.to_s != csr.content.public_key.to_s
         | 
| 257 | 
            -
                  raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: csr.fingerprint, csr_public_key: csr.content.public_key.to_text, agent_public_key: key.content.public_key.to_text, cert_name: Puppet[:certname] | 
| 255 | 
            +
                  raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: csr.fingerprint, csr_public_key: csr.content.public_key.to_text, agent_public_key: key.content.public_key.to_text, cert_name: Puppet[:certname] }
         | 
| 258 256 | 
             
            The CSR retrieved from the master does not match the agent's public key.
         | 
| 259 257 | 
             
            CSR fingerprint: %{fingerprint}
         | 
| 260 258 | 
             
            CSR public key: %{csr_public_key}
         | 
| @@ -263,8 +261,7 @@ To fix this, remove the CSR from both the master and the agent and then start a | |
| 263 261 | 
             
            On the master:
         | 
| 264 262 | 
             
              puppetserver ca clean --certname %{cert_name}
         | 
| 265 263 | 
             
            On the agent:
         | 
| 266 | 
            -
               | 
| 267 | 
            -
              1b. On Windows: del "%{cert_dir}\\%{cert_name}.pem" /f
         | 
| 264 | 
            +
              1. puppet ssl clean
         | 
| 268 265 | 
             
              2. puppet agent -t
         | 
| 269 266 | 
             
            ERROR_STRING
         | 
| 270 267 | 
             
                end
         | 
| @@ -576,6 +573,7 @@ ERROR_STRING | |
| 576 573 | 
             
                  end
         | 
| 577 574 | 
             
                end
         | 
| 578 575 | 
             
              end
         | 
| 576 | 
            +
              public :download_certificate_from_ca
         | 
| 579 577 |  | 
| 580 578 | 
             
              # Returns the file path for the named certificate, based on this host's
         | 
| 581 579 | 
             
              # configuration.
         | 
| @@ -64,7 +64,7 @@ class Puppet::Transaction::Persistence | |
| 64 64 | 
             
                  begin
         | 
| 65 65 | 
             
                    result = Puppet::Util::Yaml.safe_load_file(filename, [Symbol])
         | 
| 66 66 | 
             
                  rescue Puppet::Util::Yaml::YamlLoadError => detail
         | 
| 67 | 
            -
                    Puppet.log_exception(detail, _("Transaction store file %{filename} is corrupt (%{detail}); replacing") % { filename: filename, detail: detail } | 
| 67 | 
            +
                    Puppet.log_exception(detail, _("Transaction store file %{filename} is corrupt (%{detail}); replacing") % { filename: filename, detail: detail })
         | 
| 68 68 |  | 
| 69 69 | 
             
                    begin
         | 
| 70 70 | 
             
                      File.rename(filename, filename + ".bad")
         | 
    
        data/lib/puppet/type/package.rb
    CHANGED
    
    
    
        data/lib/puppet/type/user.rb
    CHANGED
    
    | @@ -409,7 +409,10 @@ module Puppet | |
| 409 409 | 
             
                    resource at the same time. For instance, Puppet creates a home directory for a managed
         | 
| 410 410 | 
             
                    user if `ensure => present` and the user does not exist at the time of the Puppet run.
         | 
| 411 411 | 
             
                    If the home directory is then deleted manually, Puppet will not recreate it on the next
         | 
| 412 | 
            -
                    run. | 
| 412 | 
            +
                    run.
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                    Note that on Windows, this manages creation/deletion of the user profile instead of the
         | 
| 415 | 
            +
                    home directory. The user profile is stored in the `C:\Users\<username>` directory."
         | 
| 413 416 |  | 
| 414 417 | 
             
                  defaultto false
         | 
| 415 418 |  | 
    
        data/lib/puppet/util.rb
    CHANGED
    
    | @@ -478,9 +478,13 @@ module Util | |
| 478 478 |  | 
| 479 479 | 
             
              def safe_posix_fork(stdin=$stdin, stdout=$stdout, stderr=$stderr, &block)
         | 
| 480 480 | 
             
                child_pid = Kernel.fork do
         | 
| 481 | 
            -
                   | 
| 482 | 
            -
                   | 
| 483 | 
            -
                   | 
| 481 | 
            +
                  STDIN.reopen(stdin)
         | 
| 482 | 
            +
                  STDOUT.reopen(stdout)
         | 
| 483 | 
            +
                  STDERR.reopen(stderr)
         | 
| 484 | 
            +
             | 
| 485 | 
            +
                  $stdin = STDIN
         | 
| 486 | 
            +
                  $stdout = STDOUT
         | 
| 487 | 
            +
                  $stderr = STDERR
         | 
| 484 488 |  | 
| 485 489 | 
             
                  begin
         | 
| 486 490 | 
             
                    Dir.foreach('/proc/self/fd') do |f|
         | 
    
        data/lib/puppet/util/logging.rb
    CHANGED
    
    | @@ -49,12 +49,13 @@ module Logging | |
| 49 49 | 
             
              #    to take advantage of the backtrace logging.
         | 
| 50 50 | 
             
              def log_exception(exception, message = :default, options = {})
         | 
| 51 51 | 
             
                trace = Puppet[:trace] || options[:trace]
         | 
| 52 | 
            +
                level = options[:level] || :err
         | 
| 52 53 | 
             
                if message == :default && exception.is_a?(Puppet::ParseErrorWithIssue)
         | 
| 53 54 | 
             
                  # Retain all detailed info and keep plain message and stacktrace separate
         | 
| 54 55 | 
             
                  backtrace = []
         | 
| 55 56 | 
             
                  build_exception_trace(backtrace, exception, trace)
         | 
| 56 57 | 
             
                  Puppet::Util::Log.create({
         | 
| 57 | 
            -
                      :level =>  | 
| 58 | 
            +
                      :level => level,
         | 
| 58 59 | 
             
                      :source => log_source,
         | 
| 59 60 | 
             
                      :message => exception.basic_message,
         | 
| 60 61 | 
             
                      :issue_code => exception.issue_code,
         | 
| @@ -66,7 +67,7 @@ module Logging | |
| 66 67 | 
             
                      :node => exception.node
         | 
| 67 68 | 
             
                    }.merge(log_metadata))
         | 
| 68 69 | 
             
                else
         | 
| 69 | 
            -
                   | 
| 70 | 
            +
                  send_log(level, format_exception(exception, message, trace))
         | 
| 70 71 | 
             
                end
         | 
| 71 72 | 
             
              end
         | 
| 72 73 |  | 
| @@ -8,6 +8,8 @@ module Puppet::Util::Windows::Process | |
| 8 8 |  | 
| 9 9 | 
             
              WAIT_TIMEOUT = 0x102
         | 
| 10 10 | 
             
              WAIT_INTERVAL = 200
         | 
| 11 | 
            +
              # https://docs.microsoft.com/en-us/windows/desktop/ProcThread/process-creation-flags
         | 
| 12 | 
            +
              CREATE_NO_WINDOW = 0x08000000
         | 
| 11 13 |  | 
| 12 14 | 
             
              def execute(command, arguments, stdin, stdout, stderr)
         | 
| 13 15 | 
             
                create_args = {
         | 
| @@ -17,9 +19,11 @@ module Puppet::Util::Windows::Process | |
| 17 19 | 
             
                    :stdout => stdout,
         | 
| 18 20 | 
             
                    :stderr => stderr
         | 
| 19 21 | 
             
                  },
         | 
| 20 | 
            -
                  :close_handles => false
         | 
| 22 | 
            +
                  :close_handles => false,
         | 
| 21 23 | 
             
                }
         | 
| 22 | 
            -
             | 
| 24 | 
            +
                if arguments[:suppress_window]
         | 
| 25 | 
            +
                  create_args[:creation_flags] = CREATE_NO_WINDOW
         | 
| 26 | 
            +
                end
         | 
| 23 27 | 
             
                cwd = arguments[:cwd]
         | 
| 24 28 | 
             
                if cwd
         | 
| 25 29 | 
             
                  Dir.chdir(cwd) { Process.create(create_args) }
         | 
| @@ -324,6 +324,20 @@ module Puppet::Util::Windows::Security | |
| 324 324 | 
             
                  # we don't check S_ISYSTEM_MISSING bit, but automatically carry over existing SYSTEM perms
         | 
| 325 325 | 
             
                  # by default set SYSTEM perms to full
         | 
| 326 326 | 
             
                  system_allow = FILE::FILE_ALL_ACCESS
         | 
| 327 | 
            +
                else
         | 
| 328 | 
            +
                  # It is possible to set SYSTEM with a mode other than Full Control (7) however this makes no sense and in practical terms
         | 
| 329 | 
            +
                  # should not be done.  We can trap these instances and correct them before being applied.
         | 
| 330 | 
            +
                  if (sd.owner == well_known_system_sid) && (owner_allow != FILE::FILE_ALL_ACCESS)
         | 
| 331 | 
            +
                    #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
         | 
| 332 | 
            +
                    Puppet.debug _("An attempt to set mode %{mode} on item %{path} would result in the owner, SYSTEM, to have less than Full Control rights. This attempt has been corrected to Full Control") % { mode: mode.to_s(8), path: path }
         | 
| 333 | 
            +
                    owner_allow = FILE::FILE_ALL_ACCESS
         | 
| 334 | 
            +
                  end
         | 
| 335 | 
            +
             | 
| 336 | 
            +
                  if (sd.group == well_known_system_sid) && (group_allow != FILE::FILE_ALL_ACCESS)
         | 
| 337 | 
            +
                    #TRANSLATORS 'SYSTEM' is a Windows name and should not be translated
         | 
| 338 | 
            +
                    Puppet.debug _("An attempt to set mode %{mode} on item %{path} would result in the group, SYSTEM, to have less than Full Control rights. This attempt has been corrected to Full Control") % { mode: mode.to_s(8), path: path }
         | 
| 339 | 
            +
                    group_allow = FILE::FILE_ALL_ACCESS
         | 
| 340 | 
            +
                  end
         | 
| 327 341 | 
             
                end
         | 
| 328 342 |  | 
| 329 343 | 
             
                # even though FILE_DELETE_CHILD only applies to directories, it can be set on files
         | 
| @@ -40,6 +40,26 @@ module Puppet::Util::Windows | |
| 40 40 | 
             
                SERVICE_CONTROL_PRESHUTDOWN           = 0x0000000F
         | 
| 41 41 | 
             
                SERVICE_CONTROL_TIMECHANGE            = 0x00000010
         | 
| 42 42 | 
             
                SERVICE_CONTROL_TRIGGEREVENT          = 0x00000020
         | 
| 43 | 
            +
                SERVICE_CONTROL_SIGNALS               = {
         | 
| 44 | 
            +
                  SERVICE_CONTROL_STOP                  => :SERVICE_CONTROL_STOP,
         | 
| 45 | 
            +
                  SERVICE_CONTROL_PAUSE                 => :SERVICE_CONTROL_PAUSE,
         | 
| 46 | 
            +
                  SERVICE_CONTROL_CONTINUE              => :SERVICE_CONTROL_CONTINUE,
         | 
| 47 | 
            +
                  SERVICE_CONTROL_INTERROGATE           => :SERVICE_CONTROL_INTERROGATE,
         | 
| 48 | 
            +
                  SERVICE_CONTROL_SHUTDOWN              => :SERVICE_CONTROL_SHUTDOWN,
         | 
| 49 | 
            +
                  SERVICE_CONTROL_PARAMCHANGE           => :SERVICE_CONTROL_PARAMCHANGE,
         | 
| 50 | 
            +
                  SERVICE_CONTROL_NETBINDADD            => :SERVICE_CONTROL_NETBINDADD,
         | 
| 51 | 
            +
                  SERVICE_CONTROL_NETBINDREMOVE         => :SERVICE_CONTROL_NETBINDREMOVE,
         | 
| 52 | 
            +
                  SERVICE_CONTROL_NETBINDENABLE         => :SERVICE_CONTROL_NETBINDENABLE,
         | 
| 53 | 
            +
                  SERVICE_CONTROL_NETBINDDISABLE        => :SERVICE_CONTROL_NETBINDDISABLE,
         | 
| 54 | 
            +
                  SERVICE_CONTROL_DEVICEEVENT           => :SERVICE_CONTROL_DEVICEEVENT,
         | 
| 55 | 
            +
                  SERVICE_CONTROL_HARDWAREPROFILECHANGE => :SERVICE_CONTROL_HARDWAREPROFILECHANGE,
         | 
| 56 | 
            +
                  SERVICE_CONTROL_POWEREVENT            => :SERVICE_CONTROL_POWEREVENT,
         | 
| 57 | 
            +
                  SERVICE_CONTROL_SESSIONCHANGE         => :SERVICE_CONTROL_SESSIONCHANGE,
         | 
| 58 | 
            +
                  SERVICE_CONTROL_PRESHUTDOWN           => :SERVICE_CONTROL_PRESHUTDOWN,
         | 
| 59 | 
            +
                  SERVICE_CONTROL_TIMECHANGE            => :SERVICE_CONTROL_TIMECHANGE,
         | 
| 60 | 
            +
                  SERVICE_CONTROL_TRIGGEREVENT          => :SERVICE_CONTROL_TRIGGEREVENT
         | 
| 61 | 
            +
                }
         | 
| 62 | 
            +
             | 
| 43 63 |  | 
| 44 64 | 
             
                # Service start type codes
         | 
| 45 65 | 
             
                # https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-changeserviceconfigw
         | 
| @@ -81,7 +101,14 @@ module Puppet::Util::Windows | |
| 81 101 | 
             
                SERVICE_START_PENDING    = 0x00000002
         | 
| 82 102 | 
             
                SERVICE_STOP_PENDING     = 0x00000003
         | 
| 83 103 | 
             
                SERVICE_STOPPED          = 0x00000001
         | 
| 84 | 
            -
                 | 
| 104 | 
            +
                UNSAFE_PENDING_STATES    = [SERVICE_START_PENDING, SERVICE_STOP_PENDING]
         | 
| 105 | 
            +
                FINAL_STATES             = {
         | 
| 106 | 
            +
                  SERVICE_CONTINUE_PENDING => SERVICE_RUNNING,
         | 
| 107 | 
            +
                  SERVICE_PAUSE_PENDING    => SERVICE_PAUSED,
         | 
| 108 | 
            +
                  SERVICE_START_PENDING    => SERVICE_RUNNING,
         | 
| 109 | 
            +
                  SERVICE_STOP_PENDING     => SERVICE_STOPPED
         | 
| 110 | 
            +
                }
         | 
| 111 | 
            +
                SERVICE_STATES           = {
         | 
| 85 112 | 
             
                  SERVICE_CONTINUE_PENDING => :SERVICE_CONTINUE_PENDING,
         | 
| 86 113 | 
             
                  SERVICE_PAUSE_PENDING => :SERVICE_PAUSE_PENDING,
         | 
| 87 114 | 
             
                  SERVICE_PAUSED => :SERVICE_PAUSED,
         | 
| @@ -266,37 +293,68 @@ module Puppet::Util::Windows | |
| 266 293 | 
             
                end
         | 
| 267 294 | 
             
                module_function :exists?
         | 
| 268 295 |  | 
| 269 | 
            -
                # Start a windows service | 
| 296 | 
            +
                # Start a windows service
         | 
| 270 297 | 
             
                #
         | 
| 271 298 | 
             
                # @param [:string] service_name name of the service to start
         | 
| 272 299 | 
             
                def start(service_name)
         | 
| 273 | 
            -
                   | 
| 274 | 
            -
             | 
| 275 | 
            -
             | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 300 | 
            +
                  Puppet.debug _("Starting the %{service_name} service") % { service_name: service_name }
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                  valid_initial_states = [
         | 
| 303 | 
            +
                    SERVICE_STOP_PENDING,
         | 
| 304 | 
            +
                    SERVICE_STOPPED,
         | 
| 305 | 
            +
                    SERVICE_START_PENDING
         | 
| 306 | 
            +
                  ]
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                  transition_service_state(service_name, valid_initial_states, SERVICE_RUNNING) do |service|
         | 
| 309 | 
            +
                    if StartServiceW(service, 0, FFI::Pointer::NULL) == FFI::WIN32_FALSE
         | 
| 310 | 
            +
                      raise Puppet::Util::Windows::Error, _("Failed to start the service")
         | 
| 278 311 | 
             
                    end
         | 
| 279 312 | 
             
                  end
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                  Puppet.debug _("Successfully started the %{service_name} service") % { service_name: service_name }
         | 
| 280 315 | 
             
                end
         | 
| 281 316 | 
             
                module_function :start
         | 
| 282 317 |  | 
| 283 | 
            -
                #  | 
| 318 | 
            +
                # Stop a windows service
         | 
| 284 319 | 
             
                #
         | 
| 285 320 | 
             
                # @param [:string] service_name name of the service to stop
         | 
| 286 321 | 
             
                def stop(service_name)
         | 
| 287 | 
            -
                   | 
| 288 | 
            -
             | 
| 289 | 
            -
             | 
| 290 | 
            -
             | 
| 291 | 
            -
             | 
| 292 | 
            -
             | 
| 293 | 
            -
                        end
         | 
| 294 | 
            -
                      end
         | 
| 295 | 
            -
                    end
         | 
| 322 | 
            +
                  Puppet.debug _("Stopping the %{service_name} service") % { service_name: service_name }
         | 
| 323 | 
            +
             | 
| 324 | 
            +
                  valid_initial_states = SERVICE_STATES.keys - [SERVICE_STOPPED]
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                  transition_service_state(service_name, valid_initial_states, SERVICE_STOPPED) do |service|
         | 
| 327 | 
            +
                    send_service_control_signal(service, SERVICE_CONTROL_STOP)
         | 
| 296 328 | 
             
                  end
         | 
| 329 | 
            +
             | 
| 330 | 
            +
                  Puppet.debug _("Successfully stopped the %{service_name} service") % { service_name: service_name }
         | 
| 297 331 | 
             
                end
         | 
| 298 332 | 
             
                module_function :stop
         | 
| 299 333 |  | 
| 334 | 
            +
                # Resume a paused windows service
         | 
| 335 | 
            +
                #
         | 
| 336 | 
            +
                # @param [:string] service_name name of the service to resume
         | 
| 337 | 
            +
                def resume(service_name)
         | 
| 338 | 
            +
                  Puppet.debug _("Resuming the %{service_name} service") % { service_name: service_name }
         | 
| 339 | 
            +
             | 
| 340 | 
            +
                  valid_initial_states = [
         | 
| 341 | 
            +
                    SERVICE_PAUSE_PENDING,
         | 
| 342 | 
            +
                    SERVICE_PAUSED,
         | 
| 343 | 
            +
                    SERVICE_CONTINUE_PENDING
         | 
| 344 | 
            +
                  ]
         | 
| 345 | 
            +
             | 
| 346 | 
            +
                  transition_service_state(service_name, valid_initial_states, SERVICE_RUNNING) do |service|
         | 
| 347 | 
            +
                    # The SERVICE_CONTROL_CONTINUE signal can only be sent when
         | 
| 348 | 
            +
                    # the service is in the SERVICE_PAUSED state
         | 
| 349 | 
            +
                    wait_on_pending_state(service, SERVICE_PAUSE_PENDING)
         | 
| 350 | 
            +
             | 
| 351 | 
            +
                    send_service_control_signal(service, SERVICE_CONTROL_CONTINUE)
         | 
| 352 | 
            +
                  end
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                  Puppet.debug _("Successfully resumed the %{service_name} service") % { service_name: service_name }
         | 
| 355 | 
            +
                end
         | 
| 356 | 
            +
                module_function :resume
         | 
| 357 | 
            +
             | 
| 300 358 | 
             
                # Query the state of a service using QueryServiceStatusEx
         | 
| 301 359 | 
             
                #
         | 
| 302 360 | 
             
                # @param [:string] service_name name of the service to query
         | 
| @@ -495,24 +553,74 @@ module Puppet::Util::Windows | |
| 495 553 | 
             
                  private :open_scm
         | 
| 496 554 |  | 
| 497 555 | 
             
                  # @api private
         | 
| 498 | 
            -
                  #  | 
| 499 | 
            -
                  #  | 
| 556 | 
            +
                  # Transition the service to the specified state. The block should perform
         | 
| 557 | 
            +
                  # the actual transition.
         | 
| 500 558 | 
             
                  #
         | 
| 501 | 
            -
                  # @param [ | 
| 502 | 
            -
                  # @param [ | 
| 503 | 
            -
                  # | 
| 504 | 
            -
                   | 
| 505 | 
            -
             | 
| 506 | 
            -
             | 
| 507 | 
            -
             | 
| 508 | 
            -
             | 
| 509 | 
            -
             | 
| 510 | 
            -
             | 
| 511 | 
            -
             | 
| 512 | 
            -
             | 
| 513 | 
            -
             | 
| 514 | 
            -
             | 
| 515 | 
            -
             | 
| 559 | 
            +
                  # @param [String] service_name the name of the service to transition
         | 
| 560 | 
            +
                  # @param [[Integer]] valid_initial_states an array of valid states that the service can transition from
         | 
| 561 | 
            +
                  # @param [:Integer] final_state the state that the service will transition to
         | 
| 562 | 
            +
                  def transition_service_state(service_name, valid_initial_states, final_state, &block)
         | 
| 563 | 
            +
                    service_access = SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS
         | 
| 564 | 
            +
                    open_service(service_name, SC_MANAGER_CONNECT, service_access) do |service|
         | 
| 565 | 
            +
                      status = query_status(service)
         | 
| 566 | 
            +
                      initial_state = status[:dwCurrentState]
         | 
| 567 | 
            +
             | 
| 568 | 
            +
                      # If the service is already in the final_state, then
         | 
| 569 | 
            +
                      # no further work needs to be done
         | 
| 570 | 
            +
                      if initial_state == final_state 
         | 
| 571 | 
            +
                        Puppet.debug _("The service is already in the %{final_state} state. No further work needs to be done.") % { final_state: SERVICE_STATES[final_state] }
         | 
| 572 | 
            +
             | 
| 573 | 
            +
                        next
         | 
| 574 | 
            +
                      end
         | 
| 575 | 
            +
             | 
| 576 | 
            +
                      # Check that initial_state corresponds to a valid
         | 
| 577 | 
            +
                      # initial state
         | 
| 578 | 
            +
                      unless valid_initial_states.include?(initial_state)
         | 
| 579 | 
            +
                        valid_initial_states_str = valid_initial_states.map do |state|
         | 
| 580 | 
            +
                          SERVICE_STATES[state]
         | 
| 581 | 
            +
                        end.join(", ")
         | 
| 582 | 
            +
             | 
| 583 | 
            +
                        raise Puppet::Error, _("The service must be in one of the %{valid_initial_states} states to perform this transition. It is currently in the %{current_state} state.") % { valid_initial_states: valid_initial_states_str, current_state: SERVICE_STATES[initial_state] }
         | 
| 584 | 
            +
                      end
         | 
| 585 | 
            +
             | 
| 586 | 
            +
                      # Check if there's a pending transition to the final_state. If so, then wait for
         | 
| 587 | 
            +
                      # that transition to finish.
         | 
| 588 | 
            +
                      possible_pending_states = FINAL_STATES.keys.select do |pending_state|
         | 
| 589 | 
            +
                        # SERVICE_RUNNING has two pending states, SERVICE_START_PENDING and
         | 
| 590 | 
            +
                        # SERVICE_CONTINUE_PENDING. That is why we need the #select here
         | 
| 591 | 
            +
                        FINAL_STATES[pending_state] == final_state
         | 
| 592 | 
            +
                      end
         | 
| 593 | 
            +
                      if possible_pending_states.include?(initial_state)
         | 
| 594 | 
            +
                        Puppet.debug _("There is already a pending transition to the %{final_state} state for the %{service_name} service.")  % { final_state: SERVICE_STATES[final_state], service_name: service_name }
         | 
| 595 | 
            +
                        wait_on_pending_state(service, initial_state)
         | 
| 596 | 
            +
             | 
| 597 | 
            +
                        next
         | 
| 598 | 
            +
                      end
         | 
| 599 | 
            +
             | 
| 600 | 
            +
                      # If we are in an unsafe pending state like SERVICE_START_PENDING
         | 
| 601 | 
            +
                      # or SERVICE_STOP_PENDING, then we want to wait for that pending
         | 
| 602 | 
            +
                      # transition to finish before transitioning the service state.
         | 
| 603 | 
            +
                      # The reason we do this is because SERVICE_START_PENDING is when
         | 
| 604 | 
            +
                      # the service thread is being created and initialized, while
         | 
| 605 | 
            +
                      # SERVICE_STOP_PENDING is when the service thread is being cleaned
         | 
| 606 | 
            +
                      # up and destroyed. Thus there is a chance that when the service is
         | 
| 607 | 
            +
                      # in either of these states, its service thread may not yet be ready
         | 
| 608 | 
            +
                      # to perform the state transition (it may not even exist).
         | 
| 609 | 
            +
                      if UNSAFE_PENDING_STATES.include?(initial_state)
         | 
| 610 | 
            +
                        Puppet.debug _("The service is in the %{pending_state} state, which is an unsafe pending state.") % { pending_state: SERVICE_STATES[initial_state] }
         | 
| 611 | 
            +
                        wait_on_pending_state(service, initial_state)
         | 
| 612 | 
            +
                        initial_state = FINAL_STATES[initial_state]
         | 
| 613 | 
            +
                      end
         | 
| 614 | 
            +
             | 
| 615 | 
            +
                      Puppet.debug _("Transitioning the %{service_name} service from %{initial_state} to %{final_state}") % { service_name: service_name, initial_state: SERVICE_STATES[initial_state], final_state: SERVICE_STATES[final_state] }
         | 
| 616 | 
            +
             | 
| 617 | 
            +
                      yield service
         | 
| 618 | 
            +
             | 
| 619 | 
            +
                      Puppet.debug _("Waiting for the transition to finish")
         | 
| 620 | 
            +
                      wait_on_state_transition(service, initial_state, final_state)
         | 
| 621 | 
            +
                    end
         | 
| 622 | 
            +
                  rescue => detail
         | 
| 623 | 
            +
                    raise Puppet::Error, _("Failed to transition the %{service_name} service to the %{final_state} state. Detail: %{detail}") % { service_name: service_name, final_state: SERVICE_STATES[final_state], detail: detail }, detail.backtrace
         | 
| 516 624 | 
             
                  end
         | 
| 517 625 | 
             
                  private :transition_service_state
         | 
| 518 626 |  | 
| @@ -596,75 +704,110 @@ module Puppet::Util::Windows | |
| 596 704 | 
             
                  private :query_config
         | 
| 597 705 |  | 
| 598 706 | 
             
                  # @api private
         | 
| 599 | 
            -
                  #  | 
| 707 | 
            +
                  # Sends a service control signal to a service
         | 
| 708 | 
            +
                  #
         | 
| 709 | 
            +
                  # @param [:handle] service handle to the service
         | 
| 710 | 
            +
                  # @param [Integer] signal the service control signal to send
         | 
| 711 | 
            +
                  def send_service_control_signal(service, signal)
         | 
| 712 | 
            +
                    FFI::MemoryPointer.new(SERVICE_STATUS.size) do |status_ptr|
         | 
| 713 | 
            +
                      status = SERVICE_STATUS.new(status_ptr)
         | 
| 714 | 
            +
                      if ControlService(service, signal, status) == FFI::WIN32_FALSE
         | 
| 715 | 
            +
                        raise Puppet::Util::Windows::Error, _("Failed to send the %{control_signal} signal to the service. Its current state is %{current_state}. Failed with") % { control_signal: SERVICE_CONTROL_SIGNALS[signal], current_state: SERVICE_STATES[status[:dwCurrentState]] }
         | 
| 716 | 
            +
                      end
         | 
| 717 | 
            +
                    end
         | 
| 718 | 
            +
                  end
         | 
| 719 | 
            +
             | 
| 720 | 
            +
                  # @api private
         | 
| 721 | 
            +
                  # Waits for a service to transition from one state to
         | 
| 722 | 
            +
                  # another state.
         | 
| 600 723 | 
             
                  #
         | 
| 601 724 | 
             
                  # @param [:handle] service handle to the service to wait on
         | 
| 602 | 
            -
                  # @param [ | 
| 603 | 
            -
                  # @ | 
| 604 | 
            -
                   | 
| 605 | 
            -
             | 
| 725 | 
            +
                  # @param [Integer] initial_state the state that the service is transitioning from.
         | 
| 726 | 
            +
                  # @param [Integer] final_state the state that the service is transitioning to
         | 
| 727 | 
            +
                  def wait_on_state_transition(service, initial_state, final_state)
         | 
| 728 | 
            +
                    # Get the pending state for this transition. Note that SERVICE_RUNNING
         | 
| 729 | 
            +
                    # has two possible pending states, which is why we need this logic.
         | 
| 730 | 
            +
                    if final_state != SERVICE_RUNNING
         | 
| 731 | 
            +
                      pending_state = FINAL_STATES.key(final_state)
         | 
| 732 | 
            +
                    elsif initial_state == SERVICE_STOPPED
         | 
| 733 | 
            +
                      # SERVICE_STOPPED => SERVICE_RUNNING
         | 
| 734 | 
            +
                      pending_state = SERVICE_START_PENDING
         | 
| 735 | 
            +
                    else
         | 
| 736 | 
            +
                      # SERVICE_PAUSED => SERVICE_RUNNING
         | 
| 737 | 
            +
                      pending_state = SERVICE_CONTINUE_PENDING
         | 
| 738 | 
            +
                    end
         | 
| 739 | 
            +
             | 
| 740 | 
            +
                    # Wait for the transition to finish
         | 
| 741 | 
            +
                    state = nil
         | 
| 606 742 | 
             
                    elapsed_time = 0
         | 
| 607 743 | 
             
                    while elapsed_time <= DEFAULT_TIMEOUT
         | 
| 608 744 | 
             
                      status = query_status(service)
         | 
| 609 745 | 
             
                      state = status[:dwCurrentState]
         | 
| 610 | 
            -
             | 
| 611 | 
            -
             | 
| 746 | 
            +
             | 
| 747 | 
            +
                      return if state == final_state
         | 
| 748 | 
            +
                      if state == pending_state
         | 
| 749 | 
            +
                        Puppet.debug _("The service transitioned to the %{pending_state} state.") % { pending_state: SERVICE_STATES[pending_state] }
         | 
| 750 | 
            +
                        wait_on_pending_state(service, pending_state)
         | 
| 751 | 
            +
                        return
         | 
| 612 752 | 
             
                      end
         | 
| 753 | 
            +
             | 
| 613 754 | 
             
                      sleep(1)
         | 
| 614 755 | 
             
                      elapsed_time += 1
         | 
| 615 756 | 
             
                    end
         | 
| 616 | 
            -
             | 
| 757 | 
            +
             | 
| 758 | 
            +
                    # Timed out while waiting for the transition to finish. Raise an error
         | 
| 759 | 
            +
                    raise Puppet::Error, _("Timed out while waiting for the service to transition from %{initial_state} to %{final_state} OR from %{initial_state} to %{pending_state} to %{final_state}. The service's current state is %{current_state}.") % { initial_state: SERVICE_STATES[initial_state], final_state: SERVICE_STATES[final_state], pending_state: SERVICE_STATES[pending_state], current_state: SERVICE_STATES[state] }
         | 
| 617 760 | 
             
                  end
         | 
| 618 | 
            -
                  private : | 
| 761 | 
            +
                  private :wait_on_state_transition
         | 
| 619 762 |  | 
| 620 763 | 
             
                  # @api private
         | 
| 621 | 
            -
                  #  | 
| 622 | 
            -
                  #  | 
| 764 | 
            +
                  # Waits for a service to finish transitioning from
         | 
| 765 | 
            +
                  # a pending state. The service must be in the pending state
         | 
| 766 | 
            +
                  # before invoking this routine.
         | 
| 623 767 | 
             
                  #
         | 
| 624 768 | 
             
                  # @param [:handle] service handle to the service to wait on
         | 
| 625 | 
            -
                  # @param [Integer]  | 
| 626 | 
            -
                   | 
| 627 | 
            -
             | 
| 628 | 
            -
             | 
| 629 | 
            -
             | 
| 769 | 
            +
                  # @param [Integer] pending_state the pending state
         | 
| 770 | 
            +
                  def wait_on_pending_state(service, pending_state)
         | 
| 771 | 
            +
                    final_state = FINAL_STATES[pending_state]
         | 
| 772 | 
            +
             | 
| 773 | 
            +
                    Puppet.debug _("Waiting for the pending transition to the %{final_state} state to finish.") % { final_state: SERVICE_STATES[final_state] }
         | 
| 774 | 
            +
             | 
| 630 775 | 
             
                    elapsed_time = 0
         | 
| 631 776 | 
             
                    last_checkpoint = -1
         | 
| 632 777 | 
             
                    loop do
         | 
| 633 778 | 
             
                      status = query_status(service)
         | 
| 634 779 | 
             
                      state = status[:dwCurrentState]
         | 
| 635 | 
            -
             | 
| 780 | 
            +
             | 
| 781 | 
            +
                      # Check if our service has finished transitioning to
         | 
| 782 | 
            +
                      # the final_state OR if an unexpected transition
         | 
| 783 | 
            +
                      # has occurred
         | 
| 784 | 
            +
                      return if state == final_state
         | 
| 636 785 | 
             
                      unless state == pending_state
         | 
| 637 | 
            -
                         | 
| 638 | 
            -
                          raise Puppet::Error.new(_("Service was not in pending state: %{pending_state}, current state is %{current_state}") % { pending_state: SERVICE_STATES[pending_state], current_state: SERVICE_STATES[state] })
         | 
| 639 | 
            -
                        else
         | 
| 640 | 
            -
                          return false
         | 
| 641 | 
            -
                        end
         | 
| 786 | 
            +
                        raise Puppet::Error, _("Unexpected transition to the %{current_state} state while waiting for the pending transition from %{pending_state} to %{final_state} to finish.") % { current_state: SERVICE_STATES[state], pending_state: SERVICE_STATES[pending_state], final_state: SERVICE_STATES[final_state] }
         | 
| 642 787 | 
             
                      end
         | 
| 643 | 
            -
             | 
| 644 | 
            -
                      #  | 
| 645 | 
            -
                      # | 
| 646 | 
            -
                      #  | 
| 647 | 
            -
                      # 3. sleep, then loop again if there was progress.
         | 
| 648 | 
            -
                      time_to_wait = wait_hint_to_wait_time(status[:dwWaitHint])
         | 
| 788 | 
            +
             | 
| 789 | 
            +
                      # Check if any progress has been made since our last sleep
         | 
| 790 | 
            +
                      # using the dwCheckPoint. If no progress has been made then
         | 
| 791 | 
            +
                      # check if we've timed out, and raise an error if so
         | 
| 649 792 | 
             
                      if status[:dwCheckPoint] > last_checkpoint
         | 
| 650 793 | 
             
                        elapsed_time = 0
         | 
| 794 | 
            +
                        last_checkpoint = status[:dwCheckPoint]
         | 
| 651 795 | 
             
                      else
         | 
| 652 | 
            -
                         | 
| 653 | 
            -
                        timeout = DEFAULT_TIMEOUT  | 
| 654 | 
            -
             | 
| 655 | 
            -
             | 
| 656 | 
            -
             | 
| 657 | 
            -
                          else
         | 
| 658 | 
            -
                            return false
         | 
| 659 | 
            -
                          end
         | 
| 796 | 
            +
                        wait_hint = milliseconds_to_seconds(status[:dwWaitHint])
         | 
| 797 | 
            +
                        timeout = wait_hint < DEFAULT_TIMEOUT ? DEFAULT_TIMEOUT : wait_hint 
         | 
| 798 | 
            +
             | 
| 799 | 
            +
                        if elapsed_time >= timeout
         | 
| 800 | 
            +
                          raise Puppet::Error, _("Timed out while waiting for the pending transition from %{pending_state} to %{final_state} to finish. The current state is %{current_state}.") % { pending_state: SERVICE_STATES[pending_state], final_state: SERVICE_STATES[final_state], current_state: SERVICE_STATES[state] }
         | 
| 660 801 | 
             
                        end
         | 
| 661 802 | 
             
                      end
         | 
| 662 | 
            -
             | 
| 663 | 
            -
                       | 
| 664 | 
            -
                       | 
| 803 | 
            +
             | 
| 804 | 
            +
                      # Wait a bit before rechecking the service's state
         | 
| 805 | 
            +
                      wait_time = wait_hint_to_wait_time(status[:dwWaitHint])
         | 
| 806 | 
            +
                      sleep(wait_time)
         | 
| 807 | 
            +
                      elapsed_time += wait_time
         | 
| 665 808 | 
             
                    end
         | 
| 666 809 | 
             
                  end
         | 
| 667 | 
            -
                  private : | 
| 810 | 
            +
                  private :wait_on_pending_state
         | 
| 668 811 |  | 
| 669 812 | 
             
                  # @api private
         | 
| 670 813 | 
             
                  #
         |