puppet 6.4.3-x64-mingw32 → 6.4.4-x64-mingw32

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +9 -9
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +23 -23
  5. data/ext/project_data.yaml +2 -2
  6. data/install.rb +3 -21
  7. data/lib/puppet/application/agent.rb +12 -0
  8. data/lib/puppet/application/device.rb +14 -4
  9. data/lib/puppet/application/resource.rb +4 -4
  10. data/lib/puppet/defaults.rb +12 -0
  11. data/lib/puppet/face/config.rb +10 -48
  12. data/lib/puppet/face/facts.rb +1 -1
  13. data/lib/puppet/face/help.rb +1 -1
  14. data/lib/puppet/face/plugin.rb +9 -2
  15. data/lib/puppet/indirector/catalog/compiler.rb +11 -5
  16. data/lib/puppet/module_tool/tar/mini.rb +11 -1
  17. data/lib/puppet/network/http/factory.rb +1 -11
  18. data/lib/puppet/provider/file/posix.rb +5 -0
  19. data/lib/puppet/provider/nameservice.rb +10 -3
  20. data/lib/puppet/provider/package/dnf.rb +1 -1
  21. data/lib/puppet/provider/package/pip.rb +2 -2
  22. data/lib/puppet/provider/package/rpm.rb +51 -13
  23. data/lib/puppet/provider/package/yum.rb +8 -4
  24. data/lib/puppet/provider/service/launchd.rb +20 -5
  25. data/lib/puppet/provider/service/systemd.rb +5 -10
  26. data/lib/puppet/provider/service/windows.rb +8 -0
  27. data/lib/puppet/provider/user/pw.rb +12 -3
  28. data/lib/puppet/provider/user/user_role_add.rb +4 -0
  29. data/lib/puppet/provider/user/useradd.rb +23 -7
  30. data/lib/puppet/resource.rb +17 -0
  31. data/lib/puppet/settings.rb +40 -0
  32. data/lib/puppet/type/exec.rb +14 -6
  33. data/lib/puppet/type/package.rb +10 -0
  34. data/lib/puppet/type/service.rb +7 -2
  35. data/lib/puppet/util/execution.rb +4 -3
  36. data/lib/puppet/util/http_proxy.rb +19 -5
  37. data/lib/puppet/util/selinux.rb +5 -1
  38. data/lib/puppet/util/windows/security.rb +2 -0
  39. data/lib/puppet/util/windows/service.rb +149 -4
  40. data/lib/puppet/util/windows/sid.rb +1 -0
  41. data/lib/puppet/version.rb +1 -1
  42. data/locales/puppet.pot +168 -152
  43. data/man/man5/puppet.conf.5 +18 -2
  44. data/man/man8/puppet-agent.8 +1 -1
  45. data/man/man8/puppet-apply.8 +1 -1
  46. data/man/man8/puppet-catalog.8 +1 -1
  47. data/man/man8/puppet-config.8 +1 -1
  48. data/man/man8/puppet-describe.8 +1 -1
  49. data/man/man8/puppet-device.8 +1 -1
  50. data/man/man8/puppet-doc.8 +1 -1
  51. data/man/man8/puppet-epp.8 +1 -1
  52. data/man/man8/puppet-facts.8 +1 -1
  53. data/man/man8/puppet-filebucket.8 +1 -1
  54. data/man/man8/puppet-generate.8 +1 -1
  55. data/man/man8/puppet-help.8 +1 -1
  56. data/man/man8/puppet-key.8 +1 -1
  57. data/man/man8/puppet-lookup.8 +1 -1
  58. data/man/man8/puppet-man.8 +1 -1
  59. data/man/man8/puppet-module.8 +1 -1
  60. data/man/man8/puppet-node.8 +1 -1
  61. data/man/man8/puppet-parser.8 +1 -1
  62. data/man/man8/puppet-plugin.8 +1 -1
  63. data/man/man8/puppet-report.8 +1 -1
  64. data/man/man8/puppet-resource.8 +1 -1
  65. data/man/man8/puppet-script.8 +1 -1
  66. data/man/man8/puppet-ssl.8 +1 -1
  67. data/man/man8/puppet-status.8 +1 -1
  68. data/man/man8/puppet.8 +3 -3
  69. data/spec/integration/provider/service/systemd_spec.rb +8 -5
  70. data/spec/integration/type/file_spec.rb +28 -0
  71. data/spec/integration/util/execution_spec.rb +27 -0
  72. data/spec/unit/application/agent_spec.rb +20 -8
  73. data/spec/unit/application/device_spec.rb +27 -1
  74. data/spec/unit/face/facts_spec.rb +9 -0
  75. data/spec/unit/face/plugin_spec.rb +8 -0
  76. data/spec/unit/indirector/catalog/compiler_spec.rb +62 -5
  77. data/spec/unit/module_tool/tar/mini_spec.rb +1 -1
  78. data/spec/unit/network/http/api/indirected_routes_spec.rb +25 -10
  79. data/spec/unit/network/http/factory_spec.rb +27 -5
  80. data/spec/unit/pops/validator/validator_spec.rb +7 -0
  81. data/spec/unit/provider/package/aptrpm_spec.rb +1 -1
  82. data/spec/unit/provider/package/dnf_spec.rb +7 -0
  83. data/spec/unit/provider/package/dpkg_spec.rb +2 -2
  84. data/spec/unit/provider/package/pip_spec.rb +8 -0
  85. data/spec/unit/provider/package/rpm_spec.rb +150 -16
  86. data/spec/unit/provider/package/yum_spec.rb +7 -0
  87. data/spec/unit/provider/service/launchd_spec.rb +28 -0
  88. data/spec/unit/provider/service/systemd_spec.rb +14 -0
  89. data/spec/unit/provider/service/windows_spec.rb +20 -0
  90. data/spec/unit/provider/user/pw_spec.rb +37 -0
  91. data/spec/unit/provider/user/useradd_spec.rb +42 -0
  92. data/spec/unit/resource_spec.rb +26 -1
  93. data/spec/unit/transaction_spec.rb +18 -0
  94. data/spec/unit/type/exec_spec.rb +9 -0
  95. data/spec/unit/type/file/source_spec.rb +4 -4
  96. data/spec/unit/type/schedule_spec.rb +3 -1
  97. data/spec/unit/type/service_spec.rb +16 -0
  98. data/spec/unit/util/http_proxy_spec.rb +40 -1
  99. data/spec/unit/util/log_spec.rb +27 -1
  100. data/spec/unit/util/windows/service_spec.rb +9 -0
  101. metadata +5 -9
  102. data/ext/windows/eventlog/Rakefile +0 -32
  103. data/ext/windows/eventlog/puppetres.dll +0 -0
  104. data/ext/windows/eventlog/puppetres.mc +0 -18
@@ -202,6 +202,10 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source =>
202
202
  shadow_entry[5].empty? ? -1 : shadow_entry[5]
203
203
  end
204
204
 
205
+ def has_sensitive_data?(property = nil)
206
+ false
207
+ end
208
+
205
209
  # Read in /etc/shadow, find the line for our used and rewrite it with the
206
210
  # new pw. Smooth like 80 grit sandpaper.
207
211
  #
@@ -147,19 +147,35 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
147
147
  # validproperties is a list of properties in undefined order
148
148
  # sort them to have a predictable command line in tests
149
149
  Puppet::Type.type(:user).validproperties.sort.each do |property|
150
- next if property == :ensure
151
- next if property_manages_password_age?(property)
152
- next if (property == :groups) && @resource.forcelocal?
153
- next if (property == :expiry) && @resource.forcelocal?
150
+ value = get_value_for_property(property)
151
+ next if value.nil?
154
152
  # the value needs to be quoted, mostly because -c might
155
153
  # have spaces in it
156
- if (value = @resource.should(property)) && (value != "")
157
- cmd << flag(property) << munge(property, value)
158
- end
154
+ cmd << flag(property) << munge(property, value)
159
155
  end
160
156
  cmd
161
157
  end
162
158
 
159
+ def get_value_for_property(property)
160
+ return nil if property == :ensure
161
+ return nil if property_manages_password_age?(property)
162
+ return nil if property == :groups and @resource.forcelocal?
163
+ return nil if property == :expiry and @resource.forcelocal?
164
+ value = @resource.should(property)
165
+ return nil if !value || value == ""
166
+
167
+ value
168
+ end
169
+
170
+ def has_sensitive_data?(property = nil)
171
+ #Check for sensitive values?
172
+ properties = property ? [property] : Puppet::Type.type(:user).validproperties
173
+ properties.any? do |prop|
174
+ p = @resource.parameter(prop)
175
+ p && p.respond_to?(:is_sensitive) && p.is_sensitive
176
+ end
177
+ end
178
+
163
179
  def addcmd
164
180
  if @resource.forcelocal?
165
181
  cmd = [command(:localadd)]
@@ -427,6 +427,8 @@ class Puppet::Resource
427
427
  end
428
428
 
429
429
  # Convert our resource to yaml for Hiera purposes.
430
+ #
431
+ # @deprecated Use {to_hiera_hash} instead.
430
432
  def to_hierayaml
431
433
  # Collect list of attributes to align => and move ensure first
432
434
  attr = parameters.keys
@@ -446,6 +448,21 @@ class Puppet::Resource
446
448
  " %s:\n%s" % [self.title, attributes]
447
449
  end
448
450
 
451
+ # Convert our resource to a hiera hash suitable for serialization.
452
+ def to_hiera_hash
453
+ # to_data_hash converts to safe Data types, e.g. no symbols, unicode replacement character
454
+ h = to_data_hash
455
+
456
+ params = h['parameters'] || {}
457
+ value = params.delete('ensure')
458
+
459
+ res = {}
460
+ res['ensure'] = value if value
461
+ res.merge!(Hash[params.sort])
462
+
463
+ return { h['title'] => res }
464
+ end
465
+
449
466
  # Convert our resource to Puppet code.
450
467
  def to_manifest
451
468
  # Collect list of attributes to align => and move ensure first
@@ -84,6 +84,46 @@ class Puppet::Settings
84
84
  "puppet.conf"
85
85
  end
86
86
 
87
+ def stringify_settings(section, settings = :all)
88
+ values_from_the_selected_section =
89
+ values(nil, section.to_sym)
90
+
91
+ loader_settings = {
92
+ :environmentpath => values_from_the_selected_section.interpolate(:environmentpath),
93
+ :basemodulepath => values_from_the_selected_section.interpolate(:basemodulepath),
94
+ }
95
+
96
+ Puppet.override(Puppet.base_context(loader_settings),
97
+ _("New environment loaders generated from the requested section.")) do
98
+ # And now we can lookup values that include those from environments configured from
99
+ # the requested section
100
+ values = values(Puppet[:environment].to_sym, section.to_sym)
101
+
102
+ to_be_rendered = {}
103
+ settings = Puppet.settings.to_a.collect(&:first) if settings == :all
104
+ settings.sort.each do |setting_name|
105
+ to_be_rendered[setting_name] = values.print(setting_name.to_sym)
106
+ end
107
+
108
+ stringifyhash(to_be_rendered)
109
+ end
110
+ end
111
+
112
+ def stringifyhash(hash)
113
+ newhash = {}
114
+ hash.each do |key, val|
115
+ key = key.to_s
116
+ if val.is_a? Hash
117
+ newhash[key] = stringifyhash(val)
118
+ elsif val.is_a? Symbol
119
+ newhash[key] = val.to_s
120
+ else
121
+ newhash[key] = val
122
+ end
123
+ end
124
+ newhash
125
+ end
126
+
87
127
  # Create a new collection of config settings.
88
128
  def initialize
89
129
  @config = {}
@@ -457,9 +457,13 @@ module Puppet
457
457
  return false
458
458
  end
459
459
 
460
- output.split(/\n/).each { |line|
461
- self.debug(line)
462
- }
460
+ if sensitive
461
+ self.debug("[output redacted]")
462
+ else
463
+ output.split(/\n/).each { |line|
464
+ self.debug(line)
465
+ }
466
+ end
463
467
 
464
468
  status.exitstatus != 0
465
469
  end
@@ -509,9 +513,13 @@ module Puppet
509
513
  return false
510
514
  end
511
515
 
512
- output.split(/\n/).each { |line|
513
- self.debug(line)
514
- }
516
+ if sensitive
517
+ self.debug("[output redacted]")
518
+ else
519
+ output.split(/\n/).each { |line|
520
+ self.debug(line)
521
+ }
522
+ end
515
523
 
516
524
  status.exitstatus == 0
517
525
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  # Define the different packaging systems. Each package system is implemented
2
3
  # in a module, which then gets used to individually extend each package object.
3
4
  # This allows packages to exist on the same machine using different packaging
@@ -56,6 +57,7 @@ module Puppet
56
57
  a user or another package. Held is considered a superset of
57
58
  installed.",
58
59
  :methods => [:hold]
60
+ feature :install_only, "The provider accepts options to only install packages never update (kernels, etc.)"
59
61
  feature :install_options, "The provider accepts options to be
60
62
  passed to the installer command."
61
63
  feature :uninstall_options, "The provider accepts options to be
@@ -487,6 +489,14 @@ module Puppet
487
489
  which type of package you want."
488
490
  end
489
491
 
492
+ newparam(:install_only, :boolean => false, :parent => Puppet::Parameter::Boolean, :required_features => :install_only) do
493
+ desc <<-EOT
494
+ It should be set for packages that should only ever be installed,
495
+ never updated. Kernels in particular fall into this category.
496
+ EOT
497
+ defaultto false
498
+ end
499
+
490
500
  newparam(:install_options, :parent => Puppet::Parameter::PackageOptions, :required_features => :install_options) do
491
501
  desc <<-EOT
492
502
  An array of additional options to pass when installing a package. These
@@ -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
@@ -162,15 +162,16 @@ module Puppet::Util::Execution
162
162
 
163
163
  options = default_options.merge(options)
164
164
 
165
- if options[:sensitive]
166
- command_str = '[redacted]'
167
- elsif command.is_a?(Array)
165
+ if command.is_a?(Array)
168
166
  command = command.flatten.map(&:to_s)
169
167
  command_str = command.join(" ")
170
168
  elsif command.is_a?(String)
171
169
  command_str = command
172
170
  end
173
171
 
172
+ # do this after processing 'command' array or string
173
+ command_str = '[redacted]' if options[:sensitive]
174
+
174
175
  user_log_s = ''
175
176
  if options[:uid]
176
177
  user_log_s << " uid=#{options[:uid]}"
@@ -33,7 +33,7 @@ module Puppet::Util::HttpProxy
33
33
  # .example.com
34
34
  # We'll accommodate both here.
35
35
  def self.no_proxy?(dest)
36
- unless no_proxy_env = ENV["no_proxy"] || ENV["NO_PROXY"]
36
+ unless no_proxy = self.no_proxy
37
37
  return false
38
38
  end
39
39
 
@@ -45,7 +45,7 @@ module Puppet::Util::HttpProxy
45
45
  end
46
46
  end
47
47
 
48
- no_proxy_env.split(/\s*,\s*/).each do |d|
48
+ no_proxy.split(/\s*,\s*/).each do |d|
49
49
  host, port = d.split(':')
50
50
  host = Regexp.escape(host).gsub('\*', '.*')
51
51
 
@@ -127,6 +127,20 @@ module Puppet::Util::HttpProxy
127
127
  return Puppet.settings[:http_proxy_password]
128
128
  end
129
129
 
130
+ def self.no_proxy
131
+ no_proxy_env = ENV["no_proxy"] || ENV["NO_PROXY"]
132
+
133
+ if no_proxy_env
134
+ return no_proxy_env
135
+ end
136
+
137
+ if Puppet.settings[:no_proxy] == 'none'
138
+ return nil
139
+ end
140
+
141
+ return Puppet.settings[:no_proxy]
142
+ end
143
+
130
144
  # Return a Net::HTTP::Proxy object.
131
145
  #
132
146
  # This method optionally configures SSL correctly if the URI scheme is
@@ -181,7 +195,7 @@ module Puppet::Util::HttpProxy
181
195
  headers.merge!({"Accept-Encoding" => Puppet::Network::HTTP::Compression::ACCEPT_ENCODING})
182
196
  end
183
197
 
184
- response = proxy.send(:head, current_uri.path, headers)
198
+ response = proxy.send(:head, current_uri, headers)
185
199
  Puppet.debug("HTTP HEAD request to #{current_uri} returned #{response.code} #{response.message}")
186
200
 
187
201
  if [301, 302, 307].include?(response.code.to_i)
@@ -192,9 +206,9 @@ module Puppet::Util::HttpProxy
192
206
 
193
207
  if method != :head
194
208
  if block_given?
195
- response = proxy.send("request_#{method}".to_sym, current_uri.path, headers, &block)
209
+ response = proxy.send("request_#{method}".to_sym, current_uri, headers, &block)
196
210
  else
197
- response = proxy.send(method, current_uri.path, headers)
211
+ response = proxy.send(method, current_uri, headers)
198
212
  end
199
213
 
200
214
  Puppet.debug("HTTP #{method.to_s.upcase} request to #{current_uri} returned #{response.code} #{response.message}")
@@ -13,7 +13,7 @@ require 'pathname'
13
13
 
14
14
  module Puppet::Util::SELinux
15
15
 
16
- def selinux_support?
16
+ def self.selinux_support?
17
17
  return false unless defined?(Selinux)
18
18
  if Selinux.is_selinux_enabled == 1
19
19
  return true
@@ -21,6 +21,10 @@ module Puppet::Util::SELinux
21
21
  false
22
22
  end
23
23
 
24
+ def selinux_support?
25
+ Puppet::Util::SELinux.selinux_support?
26
+ end
27
+
24
28
  # Retrieve and return the full context of the file. If we don't have
25
29
  # SELinux support or if the SELinux call fails then return nil.
26
30
  def get_selinux_current_context(file)
@@ -200,6 +200,7 @@ module Puppet::Util::Windows::Security
200
200
  well_known_world_sid = Puppet::Util::Windows::SID::Everyone
201
201
  well_known_nobody_sid = Puppet::Util::Windows::SID::Nobody
202
202
  well_known_system_sid = Puppet::Util::Windows::SID::LocalSystem
203
+ well_known_app_packages_sid = Puppet::Util::Windows::SID::AllAppPackages
203
204
 
204
205
  mode = S_ISYSTEM_MISSING
205
206
 
@@ -234,6 +235,7 @@ module Puppet::Util::Windows::Security
234
235
  if (ace.mask & FILE::FILE_APPEND_DATA).nonzero?
235
236
  mode |= S_ISVTX
236
237
  end
238
+ when well_known_app_packages_sid
237
239
  when well_known_system_sid
238
240
  else
239
241
  #puts "Warning, unable to map SID into POSIX mode: #{ace.sid}"
@@ -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(