puppet 6.10.0 → 6.10.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +1 -1
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +18 -18
  5. data/ext/project_data.yaml +2 -2
  6. data/lib/puppet/module_tool/applications/installer.rb +5 -1
  7. data/lib/puppet/module_tool/tar/mini.rb +11 -1
  8. data/lib/puppet/network/uri.rb +18 -0
  9. data/lib/puppet/node/environment.rb +5 -15
  10. data/lib/puppet/pops/validation.rb +11 -19
  11. data/lib/puppet/provider/service/windows.rb +8 -0
  12. data/lib/puppet/type/notify.rb +3 -2
  13. data/lib/puppet/type/service.rb +7 -2
  14. data/lib/puppet/util/windows/service.rb +149 -4
  15. data/lib/puppet/version.rb +1 -1
  16. data/locales/puppet.pot +81 -69
  17. data/man/man5/puppet.conf.5 +2 -2
  18. data/man/man8/puppet-agent.8 +1 -1
  19. data/man/man8/puppet-apply.8 +1 -1
  20. data/man/man8/puppet-catalog.8 +1 -1
  21. data/man/man8/puppet-config.8 +1 -1
  22. data/man/man8/puppet-describe.8 +1 -1
  23. data/man/man8/puppet-device.8 +1 -1
  24. data/man/man8/puppet-doc.8 +1 -1
  25. data/man/man8/puppet-epp.8 +1 -1
  26. data/man/man8/puppet-facts.8 +1 -1
  27. data/man/man8/puppet-filebucket.8 +1 -1
  28. data/man/man8/puppet-generate.8 +1 -1
  29. data/man/man8/puppet-help.8 +1 -1
  30. data/man/man8/puppet-key.8 +1 -1
  31. data/man/man8/puppet-lookup.8 +1 -1
  32. data/man/man8/puppet-man.8 +1 -1
  33. data/man/man8/puppet-module.8 +1 -1
  34. data/man/man8/puppet-node.8 +1 -1
  35. data/man/man8/puppet-parser.8 +1 -1
  36. data/man/man8/puppet-plugin.8 +1 -1
  37. data/man/man8/puppet-report.8 +1 -1
  38. data/man/man8/puppet-resource.8 +1 -1
  39. data/man/man8/puppet-script.8 +1 -1
  40. data/man/man8/puppet-ssl.8 +1 -1
  41. data/man/man8/puppet-status.8 +1 -1
  42. data/man/man8/puppet.8 +2 -2
  43. data/spec/integration/type/notify_spec.rb +46 -0
  44. data/spec/unit/module_tool/tar/mini_spec.rb +1 -1
  45. data/spec/unit/network/http/api/indirected_routes_spec.rb +25 -10
  46. data/spec/unit/network/uri_spec.rb +47 -0
  47. data/spec/unit/provider/service/windows_spec.rb +20 -0
  48. data/spec/unit/type/file/source_spec.rb +4 -4
  49. data/spec/unit/type/schedule_spec.rb +3 -1
  50. data/spec/unit/type/service_spec.rb +16 -0
  51. data/spec/unit/util/windows/service_spec.rb +9 -0
  52. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59f14a1638260b64116990632bc1e2e9f3bc9c9f67d6ac8e6d000364754eec95
4
- data.tar.gz: 5653930e2713ccbfd33e67ae9d9e01694852cb98625a4411dfb43bdafaf5addd
3
+ metadata.gz: 428bcd2ac83546e3a664b136e4cc2c0009da9ed3d2f3e34106ab34e72059622f
4
+ data.tar.gz: 8a65ce1247102bee99541b5aad563819ea627ef9ff980f38c34821175c908d5b
5
5
  SHA512:
6
- metadata.gz: 3e897cb8963e9c4b71cfb3c781f77d99f43bd46ddfb34e29fb9924a53076ec3374b79063ff9cc62ba2c7d5caac172cbaffd6a9fd8d459b68632f00b439954e96
7
- data.tar.gz: d7aef922b4b92835a505bf5d62b787c28e8054d752e3148cdf3b7fdd5956f5b38961798e61338c4585a0c39a5c70264af414c55e6e5ed848e91a6dfd345a693c
6
+ metadata.gz: 572d25a4582ec7e5e89e930f6a420fc42938b901d737b9b797adbb9a21196f1286557c4ba55ee067089cf678392a1d7a6e4bdc96a6affa312fde56400dd16f7c
7
+ data.tar.gz: 25ab2853f59cad59e23f277ee7a99cddd9336ee70d27be1ebe40c96b94446937fca34e97754a7d5c7f86bcc831b83a0876851b2a930a267793350ec3f0dd608b
@@ -114,7 +114,7 @@ respectively.
114
114
 
115
115
  ## Submitting Changes
116
116
 
117
- * Sign the [Contributor License Agreement](http://links.puppet.com/cla).
117
+ * Sign the [Contributor License Agreement](https://cla.puppet.com).
118
118
  * Push your changes to a topic branch in your fork of the repository.
119
119
  * Submit a pull request to the repository in the puppetlabs organization.
120
120
  * Update your Jira ticket to mark that you have submitted code and are ready
data/Gemfile CHANGED
@@ -24,7 +24,7 @@ group(:features) do
24
24
  gem 'hocon', '~> 1.0', require: false
25
25
  # requires native libshadow headers/libs
26
26
  #gem 'ruby-shadow', '~> 2.5', require: false, platforms: [:ruby]
27
- gem 'minitar', '~> 0.6', require: false
27
+ gem 'minitar', '~> 0.9', require: false
28
28
  gem 'msgpack', '~> 1.2', require: false
29
29
  gem 'rdoc', '~> 6.0', require: false, platforms: [:ruby]
30
30
  # requires native augeas headers/libs
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- puppet (6.10.0)
4
+ puppet (6.10.1)
5
5
  CFPropertyList (~> 2.2)
6
6
  concurrent-ruby (~> 1.0)
7
7
  facter (>= 2.4.0, < 4)
@@ -50,14 +50,14 @@ GEM
50
50
  method_source (0.9.2)
51
51
  minitar (0.9)
52
52
  msgpack (1.3.1)
53
- multi_json (1.13.1)
53
+ multi_json (1.14.0)
54
54
  mustache (1.1.0)
55
55
  optimist (3.0.0)
56
- packaging (0.99.42)
56
+ packaging (0.99.45)
57
57
  artifactory (~> 2)
58
- rake (~> 12.3)
59
- parallel (1.17.0)
60
- parser (2.6.4.1)
58
+ rake (>= 12.3)
59
+ parallel (1.18.0)
60
+ parser (2.6.5.0)
61
61
  ast (~> 2.4.0)
62
62
  powerpack (0.1.2)
63
63
  pry (0.12.2)
@@ -78,22 +78,22 @@ GEM
78
78
  hpricot (>= 0.8.2)
79
79
  mustache (>= 0.7.0)
80
80
  rdiscount (>= 1.5.8)
81
- rspec (3.8.0)
82
- rspec-core (~> 3.8.0)
83
- rspec-expectations (~> 3.8.0)
84
- rspec-mocks (~> 3.8.0)
85
- rspec-core (3.8.2)
86
- rspec-support (~> 3.8.0)
87
- rspec-expectations (3.8.4)
81
+ rspec (3.9.0)
82
+ rspec-core (~> 3.9.0)
83
+ rspec-expectations (~> 3.9.0)
84
+ rspec-mocks (~> 3.9.0)
85
+ rspec-core (3.9.0)
86
+ rspec-support (~> 3.9.0)
87
+ rspec-expectations (3.9.0)
88
88
  diff-lcs (>= 1.2.0, < 2.0)
89
- rspec-support (~> 3.8.0)
89
+ rspec-support (~> 3.9.0)
90
90
  rspec-its (1.3.0)
91
91
  rspec-core (>= 3.0.0)
92
92
  rspec-expectations (>= 3.0.0)
93
- rspec-mocks (3.8.1)
93
+ rspec-mocks (3.9.0)
94
94
  diff-lcs (>= 1.2.0, < 2.0)
95
- rspec-support (~> 3.8.0)
96
- rspec-support (3.8.2)
95
+ rspec-support (~> 3.9.0)
96
+ rspec-support (3.9.0)
97
97
  rubocop (0.49.1)
98
98
  parallel (~> 1.10)
99
99
  parser (>= 2.3.3.1, < 3.0)
@@ -126,7 +126,7 @@ DEPENDENCIES
126
126
  hocon (~> 1.0)
127
127
  json-schema (~> 2.0)
128
128
  memory_profiler
129
- minitar (~> 0.6)
129
+ minitar (~> 0.9)
130
130
  msgpack (~> 1.2)
131
131
  packaging (~> 0.99)
132
132
  pry
@@ -45,7 +45,7 @@ gem_platform_dependencies:
45
45
  # Use of win32-security is deprecated
46
46
  win32-security: '= 0.2.5'
47
47
  win32-service: '= 0.8.8'
48
- minitar: '~> 0.6.1'
48
+ minitar: '~> 0.9'
49
49
  x64-mingw32:
50
50
  gem_runtime_dependencies:
51
51
  ffi: '~> 1.9.25'
@@ -55,7 +55,7 @@ gem_platform_dependencies:
55
55
  # Use of win32-security is deprecated
56
56
  win32-security: '= 0.2.5'
57
57
  win32-service: '= 0.8.8'
58
- minitar: '~> 0.6.1'
58
+ minitar: '~> 0.9'
59
59
  bundle_platforms:
60
60
  universal-darwin: all
61
61
  x86-mingw32: mingw
@@ -9,6 +9,7 @@ require 'puppet/module_tool/shared_behaviors'
9
9
  require 'puppet/module_tool/install_directory'
10
10
  require 'puppet/module_tool/local_tarball'
11
11
  require 'puppet/module_tool/installed_modules'
12
+ require 'puppet/network/uri'
12
13
 
13
14
  module Puppet::ModuleTool
14
15
  module Applications
@@ -16,6 +17,7 @@ module Puppet::ModuleTool
16
17
 
17
18
  include Puppet::ModuleTool::Errors
18
19
  include Puppet::Forge::Errors
20
+ include Puppet::Network::Uri
19
21
 
20
22
  def initialize(name, install_dir, options = {})
21
23
  super(options)
@@ -79,7 +81,9 @@ module Puppet::ModuleTool
79
81
  results[:install_dir] = @install_dir.target
80
82
 
81
83
  unless @local_tarball && @ignore_dependencies
82
- Puppet.notice _("Downloading from %{host} ...") % { host: module_repository.host }
84
+ Puppet.notice _("Downloading from %{host} ...") % {
85
+ host: mask_credentials(module_repository.host)
86
+ }
83
87
  end
84
88
 
85
89
  if @ignore_dependencies
@@ -1,7 +1,17 @@
1
1
  class Puppet::ModuleTool::Tar::Mini
2
2
  def unpack(sourcefile, destdir, _)
3
3
  Zlib::GzipReader.open(sourcefile) do |reader|
4
- Archive::Tar::Minitar.unpack(reader, destdir, find_valid_files(reader)) do |action, name, stats|
4
+ # puppet doesn't have a hard dependency on minitar, so we
5
+ # can't be certain which version is installed. If it's 0.9
6
+ # or above then we can prevent minitar from fsync'ing each
7
+ # extracted file and directory, otherwise fallback to the
8
+ # old behavior
9
+ args = [reader, destdir, find_valid_files(reader)]
10
+ spec = Gem::Specification.find_by_name('minitar')
11
+ if spec && spec.version >= Gem::Version.new('0.9')
12
+ args << {:fsync => false}
13
+ end
14
+ Archive::Tar::Minitar.unpack(*args) do |action, name, stats|
5
15
  case action
6
16
  when :dir
7
17
  validate_entry(destdir, name)
@@ -0,0 +1,18 @@
1
+ # This module holds funtions for network URI's
2
+ module Puppet::Network::Uri
3
+ # Mask credentials in given URI or address as string. Resulting string will
4
+ # contain '***' in place of password. It will only be replaced if actual
5
+ # password is given.
6
+ #
7
+ # @param uri [URI|String] an uri or address to be masked
8
+ # @return [String] a masked url
9
+ def mask_credentials(uri)
10
+ if uri.is_a? URI
11
+ uri = uri.dup
12
+ else
13
+ uri = URI.parse(uri)
14
+ end
15
+ uri.password = '***' unless uri.password.nil?
16
+ uri.to_s
17
+ end
18
+ end
@@ -25,11 +25,6 @@ class Puppet::Node::Environment
25
25
  NO_MANIFEST = :no_manifest
26
26
 
27
27
  # The create() factory method should be used instead.
28
- #
29
- # @api private
30
- def self.new(*args)
31
- create(*args)
32
- end
33
28
  private_class_method :new
34
29
 
35
30
  # Create a new environment with the given name
@@ -44,13 +39,7 @@ class Puppet::Node::Environment
44
39
  #
45
40
  # @api public
46
41
  def self.create(name, modulepath, manifest = NO_MANIFEST, config_version = nil)
47
- obj = self.allocate
48
- obj.send(:initialize,
49
- name.intern,
50
- expand_dirs(extralibs() + modulepath),
51
- manifest == NO_MANIFEST ? manifest : Puppet::FileSystem.expand_path(manifest),
52
- config_version)
53
- obj
42
+ new(name, modulepath, manifest, config_version)
54
43
  end
55
44
 
56
45
  # A remote subclass to make it easier to trace instances when debugging.
@@ -81,9 +70,10 @@ class Puppet::Node::Environment
81
70
  #
82
71
  # @param name [Symbol] The environment name
83
72
  def initialize(name, modulepath, manifest, config_version)
84
- @name = name
85
- @modulepath = modulepath
86
- @manifest = manifest
73
+ @name = name.intern
74
+ @modulepath = self.class.expand_dirs(self.class.extralibs() + modulepath)
75
+ @manifest = manifest == NO_MANIFEST ? manifest : Puppet::FileSystem.expand_path(manifest)
76
+
87
77
  @config_version = config_version
88
78
  end
89
79
 
@@ -91,7 +91,7 @@ module Validation
91
91
  # @api public
92
92
  #
93
93
  class SeverityProducer
94
- @@severity_hash = {:ignore => true, :warning => true, :error => true, :deprecation => true }
94
+ SEVERITIES = { ignore: true, warning: true, error: true, deprecation: true }.freeze
95
95
 
96
96
  # Creates a new instance where all issues are diagnosed as :error unless overridden.
97
97
  # @param [Symbol] specifies default severity if :error is not wanted as the default
@@ -128,7 +128,7 @@ module Validation
128
128
  unless issue.is_a? Issues::Issue
129
129
  raise Puppet::DevError.new(_("Attempt to set validation severity for something that is not an Issue. (Got %{issue})") % { issue: issue.class })
130
130
  end
131
- unless @@severity_hash[level]
131
+ unless SEVERITIES[level]
132
132
  raise Puppet::DevError.new(_("Illegal severity level: %{level} for '%{issue_code}'") % { issue_code: issue.issue_code, level: level })
133
133
  end
134
134
  unless issue.demotable? || level == :error
@@ -412,9 +412,9 @@ module Validation
412
412
  # @param diagnostic [Diagnostic, Acceptor] diagnostic(s) that should be accepted
413
413
  def accept(diagnostic)
414
414
  if diagnostic.is_a?(Acceptor)
415
- diagnostic.diagnostics.each {|d| self.send(d.severity, d)}
415
+ diagnostic.diagnostics.each {|d| _accept(d)}
416
416
  else
417
- self.send(diagnostic.severity, diagnostic)
417
+ _accept(diagnostic)
418
418
  end
419
419
  end
420
420
 
@@ -445,22 +445,14 @@ module Validation
445
445
 
446
446
  private
447
447
 
448
- def ignore diagnostic
448
+ def _accept(diagnostic)
449
449
  @diagnostics << diagnostic
450
- end
451
-
452
- def error diagnostic
453
- @diagnostics << diagnostic
454
- @error_count += 1
455
- end
456
-
457
- def warning diagnostic
458
- @diagnostics << diagnostic
459
- @warning_count += 1
460
- end
461
-
462
- def deprecation diagnostic
463
- warning diagnostic
450
+ case diagnostic.severity
451
+ when :error
452
+ @error_count += 1
453
+ when :deprecation, :warning
454
+ @warning_count += 1
455
+ end
464
456
  end
465
457
  end
466
458
  end
@@ -35,6 +35,12 @@ Puppet::Type.type(:service).provide :windows, :parent => :service do
35
35
  raise Puppet::Error.new(_("Cannot enable %{resource_name} for manual start, error was: %{detail}") % { resource_name: @resource[:name], detail: detail }, detail )
36
36
  end
37
37
 
38
+ def delayed_start
39
+ Puppet::Util::Windows::Service.set_startup_mode( @resource[:name], :SERVICE_AUTO_START, true )
40
+ rescue => detail
41
+ raise Puppet::Error.new(_("Cannot enable %{resource_name} for delayed start, error was: %{detail}") % { resource_name: @resource[:name], detail: detail }, detail )
42
+ end
43
+
38
44
  def enabled?
39
45
  return :false unless Puppet::Util::Windows::Service.exists?(@resource[:name])
40
46
 
@@ -47,6 +53,8 @@ Puppet::Type.type(:service).provide :windows, :parent => :service do
47
53
  :true
48
54
  when :SERVICE_DEMAND_START
49
55
  :manual
56
+ when :SERVICE_DELAYED_AUTO_START
57
+ :delayed
50
58
  when :SERVICE_DISABLED
51
59
  :false
52
60
  else
@@ -11,11 +11,12 @@ module Puppet
11
11
  newproperty(:message, :idempotent => false) do
12
12
  desc "The message to be sent to the log."
13
13
  def sync
14
+ message = @sensitive ? 'Sensitive [value redacted]' : self.should
14
15
  case @resource["withpath"]
15
16
  when :true
16
- send(@resource[:loglevel], self.should)
17
+ send(@resource[:loglevel], message)
17
18
  else
18
- Puppet.send(@resource[:loglevel], self.should)
19
+ Puppet.send(@resource[:loglevel], message)
19
20
  end
20
21
  return
21
22
  end
@@ -75,6 +75,11 @@ module Puppet
75
75
  provider.enabled?
76
76
  end
77
77
 
78
+ # This only works on Windows systems.
79
+ newvalue(:delayed, :event => :service_delayed_start) do
80
+ provider.delayed_start
81
+ end
82
+
78
83
  # This only makes sense on systemd systems. Static services cannot be enabled
79
84
  # or disabled manually.
80
85
  def insync?(current)
@@ -87,8 +92,8 @@ module Puppet
87
92
  end
88
93
 
89
94
  validate do |value|
90
- if value == :manual && !Puppet::Util::Platform.windows?
91
- raise Puppet::Error.new(_("Setting enable to manual is only supported on Microsoft Windows."))
95
+ if (value == :manual || value == :delayed) && !Puppet::Util::Platform.windows?
96
+ raise Puppet::Error.new(_("Setting enable to %{value} is only supported on Microsoft Windows.") % { value: value.to_s} )
92
97
  end
93
98
  end
94
99
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  require 'puppet/util/windows'
2
3
  require 'ffi'
3
4
 
@@ -180,7 +181,30 @@ module Puppet::Util::Windows
180
181
  # // Value to indicate no change to an optional parameter
181
182
  # //
182
183
  # #define SERVICE_NO_CHANGE 0xffffffff
183
- SERVICE_NO_CHANGE = 0xffffffff
184
+ # https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-changeserviceconfig2w
185
+ SERVICE_CONFIG_DESCRIPTION = 0x00000001
186
+ SERVICE_CONFIG_FAILURE_ACTIONS = 0x00000002
187
+ SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 0x00000003
188
+ SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 0x00000004
189
+ SERVICE_CONFIG_SERVICE_SID_INFO = 0x00000005
190
+ SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 0x00000006
191
+ SERVICE_CONFIG_PRESHUTDOWN_INFO = 0x00000007
192
+ SERVICE_CONFIG_TRIGGER_INFO = 0x00000008
193
+ SERVICE_CONFIG_PREFERRED_NODE = 0x00000009
194
+ SERVICE_CONFIG_LAUNCH_PROTECTED = 0x00000012
195
+ SERVICE_NO_CHANGE = 0xffffffff
196
+ SERVICE_CONFIG_TYPES = {
197
+ SERVICE_CONFIG_DESCRIPTION => :SERVICE_CONFIG_DESCRIPTION,
198
+ SERVICE_CONFIG_FAILURE_ACTIONS => :SERVICE_CONFIG_FAILURE_ACTIONS,
199
+ SERVICE_CONFIG_DELAYED_AUTO_START_INFO => :SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
200
+ SERVICE_CONFIG_FAILURE_ACTIONS_FLAG => :SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
201
+ SERVICE_CONFIG_SERVICE_SID_INFO => :SERVICE_CONFIG_SERVICE_SID_INFO,
202
+ SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO => :SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO,
203
+ SERVICE_CONFIG_PRESHUTDOWN_INFO => :SERVICE_CONFIG_PRESHUTDOWN_INFO,
204
+ SERVICE_CONFIG_TRIGGER_INFO => :SERVICE_CONFIG_TRIGGER_INFO,
205
+ SERVICE_CONFIG_PREFERRED_NODE => :SERVICE_CONFIG_PREFERRED_NODE,
206
+ SERVICE_CONFIG_LAUNCH_PROTECTED => :SERVICE_CONFIG_LAUNCH_PROTECTED,
207
+ }
184
208
 
185
209
  # Service enum codes
186
210
  # https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexa
@@ -219,6 +243,19 @@ module Puppet::Util::Windows
219
243
  )
220
244
  end
221
245
 
246
+ # https://docs.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_delayed_auto_start_info
247
+ # typedef struct _SERVICE_DELAYED_AUTO_START_INFO {
248
+ # BOOL fDelayedAutostart;
249
+ # } SERVICE_DELAYED_AUTO_START_INFO, *LPSERVICE_DELAYED_AUTO_START_INFO;
250
+ class SERVICE_DELAYED_AUTO_START_INFO < FFI::Struct
251
+ layout(:fDelayedAutostart, :int)
252
+ alias aset []=
253
+ # Intercept the accessor so that we can handle either true/false or 1/0.
254
+ # Since there is only one member, there’s no need to check the key name.
255
+ def []=(key, value)
256
+ [0, false].include?(value) ? aset(key, 0) : aset(key, 1)
257
+ end
258
+ end
222
259
 
223
260
  # https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_enum_service_status_processw
224
261
  # typedef struct _ENUM_SERVICE_STATUS_PROCESSW {
@@ -377,6 +414,7 @@ module Puppet::Util::Windows
377
414
  module_function :service_state
378
415
 
379
416
  # Query the configuration of a service using QueryServiceConfigW
417
+ # or QueryServiceConfig2W
380
418
  #
381
419
  # @param [String] service_name name of the service to query
382
420
  # @return [QUERY_SERVICE_CONFIGW.struct] the configuration of the service
@@ -387,6 +425,14 @@ module Puppet::Util::Windows
387
425
  start_type = SERVICE_START_TYPES[config[:dwStartType]]
388
426
  end
389
427
  end
428
+ # if the service has type AUTO_START, check if it's a delayed service
429
+ if start_type == :SERVICE_AUTO_START
430
+ open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_CONFIG) do |service|
431
+ query_config2(service, SERVICE_CONFIG_DELAYED_AUTO_START_INFO) do |config|
432
+ return :SERVICE_DELAYED_AUTO_START if config[:fDelayedAutostart] == 1
433
+ end
434
+ end
435
+ end
390
436
  if start_type.nil?
391
437
  raise Puppet::Error.new(_("Unknown start type '%{start_type}' for '%{service_name}'") % { start_type: start_type.to_s, service_name: service_name})
392
438
  end
@@ -396,11 +442,12 @@ module Puppet::Util::Windows
396
442
 
397
443
  # Change the startup mode of a windows service
398
444
  #
399
- # @param [string] service_name the name of the service to modify
400
- # @param [Int] startup_type a code corresponding to a start type for
445
+ # @param [String] service_name the name of the service to modify
446
+ # @param [Integer] startup_type a code corresponding to a start type for
401
447
  # windows service, see the "Service start type codes" section in the
402
448
  # Puppet::Util::Windows::Service file for the list of available codes
403
- def set_startup_mode(service_name, startup_type)
449
+ # @param [Bool] delayed whether the service should be started with a delay
450
+ def set_startup_mode(service_name, startup_type, delayed=false)
404
451
  startup_code = SERVICE_START_TYPES.key(startup_type)
405
452
  if startup_code.nil?
406
453
  raise Puppet::Error.new(_("Unknown start type %{start_type}") % {startup_type: startup_type.to_s})
@@ -427,6 +474,7 @@ module Puppet::Util::Windows
427
474
  raise Puppet::Util::Windows::Error.new(_("Failed to update service configuration"))
428
475
  end
429
476
  end
477
+ set_startup_mode_delayed(service_name, delayed)
430
478
  end
431
479
  module_function :set_startup_mode
432
480
 
@@ -709,6 +757,82 @@ module Puppet::Util::Windows
709
757
  end
710
758
  private :query_config
711
759
 
760
+ # @api private
761
+ # perform QueryServiceConfig2W on a windows service and return the
762
+ # result
763
+ #
764
+ # @param [:handle] service handle of the service to query
765
+ # @param [Integer] info_level the configuration information to be queried
766
+ # @return [QUERY_SERVICE_CONFIG2W struct] the result of the query
767
+ def query_config2(service, info_level, &block)
768
+ config = nil
769
+ size_required = nil
770
+ # Fetch the bytes of memory required to be allocated
771
+ # for QueryServiceConfig2W to return succesfully. This
772
+ # is done by sending NULL and 0 for the pointer and size
773
+ # respectively, letting the command fail, then reading the
774
+ # value of pcbBytesNeeded
775
+ FFI::MemoryPointer.new(:lpword) do |bytes_pointer|
776
+ # return value will be false from this call, since it's designed
777
+ # to fail. Just ignore it
778
+ QueryServiceConfig2W(service, info_level, FFI::Pointer::NULL, 0, bytes_pointer)
779
+ size_required = bytes_pointer.read_dword
780
+ FFI::MemoryPointer.new(size_required) do |ssp_ptr|
781
+ # We need to supply the appropriate struct to be created based on
782
+ # the info_level
783
+ case info_level
784
+ when SERVICE_CONFIG_DELAYED_AUTO_START_INFO
785
+ config = SERVICE_DELAYED_AUTO_START_INFO.new(ssp_ptr)
786
+ end
787
+ success = QueryServiceConfig2W(
788
+ service,
789
+ info_level,
790
+ ssp_ptr,
791
+ size_required,
792
+ bytes_pointer
793
+ )
794
+ if success == FFI::WIN32_FALSE
795
+ raise Puppet::Util::Windows::Error.new(_("Service query for %{parameter_name} failed") % { parameter_name: SERVICE_CONFIG_TYPES[info_level] } )
796
+ end
797
+ yield config
798
+ end
799
+ end
800
+ end
801
+ private :query_config2
802
+
803
+ # @api private
804
+ # Sets an optional parameter on a service by calling
805
+ # ChangeServiceConfig2W
806
+ #
807
+ # @param [String] service_name name of service
808
+ # @param [Integer] change parameter to change
809
+ # @param [struct] value appropriate struct based on the parameter to change
810
+ def set_optional_parameter(service_name, change, value)
811
+ open_service(service_name, SC_MANAGER_CONNECT, SERVICE_CHANGE_CONFIG) do |service|
812
+ success = ChangeServiceConfig2W(
813
+ service,
814
+ change, # dwInfoLevel
815
+ value, # lpInfo
816
+ )
817
+ if success == FFI::WIN32_FALSE
818
+ raise Puppet::Util::windows::Error.new(_("Failed to update service %{change} configuration") % { change: change } )
819
+ end
820
+ end
821
+ end
822
+ private :set_optional_parameter
823
+
824
+ # @api private
825
+ # Controls the delayed auto-start setting of a service
826
+ #
827
+ # @param [String] service_name name of service
828
+ # @param [Bool] delayed whether the service should be started with a delay or not
829
+ def set_startup_mode_delayed(service_name, delayed)
830
+ delayed_start = SERVICE_DELAYED_AUTO_START_INFO.new
831
+ delayed_start[:fDelayedAutostart] = delayed
832
+ set_optional_parameter(service_name, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, delayed_start)
833
+ end
834
+ private :set_startup_mode_delayed
835
+
712
836
  # @api private
713
837
  # Sends a service control signal to a service
714
838
  #
@@ -905,6 +1029,18 @@ module Puppet::Util::Windows
905
1029
  attach_function_private :QueryServiceConfigW,
906
1030
  [:handle, :lpbyte, :dword, :lpdword], :win32_bool
907
1031
 
1032
+ # https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceconfig2w
1033
+ # BOOL QueryServiceConfig2W(
1034
+ # SC_HANDLE hService,
1035
+ # DWORD dwInfoLevel,
1036
+ # LPBYTE lpBuffer,
1037
+ # DWORD cbBufSize,
1038
+ # LPDWORD pcbBytesNeeded
1039
+ # );
1040
+ ffi_lib :advapi32
1041
+ attach_function_private :QueryServiceConfig2W,
1042
+ [:handle, :dword, :lpbyte, :dword, :lpdword], :win32_bool
1043
+
908
1044
  # https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-startservicew
909
1045
  # BOOL StartServiceW(
910
1046
  # SC_HANDLE hService,
@@ -955,6 +1091,15 @@ module Puppet::Util::Windows
955
1091
  :lpcwstr
956
1092
  ], :win32_bool
957
1093
 
1094
+ # https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-changeserviceconfig2w
1095
+ # BOOL ChangeServiceConfig2W(
1096
+ # SC_HANDLE hService,
1097
+ # DWORD dwInfoLevel,
1098
+ # LPVOID lpInfo
1099
+ # );
1100
+ ffi_lib :advapi32
1101
+ attach_function_private :ChangeServiceConfig2W,
1102
+ [:handle, :dword, :lpvoid], :win32_bool
958
1103
 
959
1104
  # https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexw
960
1105
  # BOOL EnumServicesStatusExW(