puppet 6.0.0 → 6.1.0

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.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +20 -20
  4. data/Guardfile.example +76 -0
  5. data/LICENSE +189 -4
  6. data/README.md +3 -3
  7. data/Rakefile +5 -2
  8. data/ext/solaris/smf/svc-puppetd +8 -1
  9. data/ext/solaris/smf/svc-puppetmasterd +8 -1
  10. data/lib/puppet/application/apply.rb +100 -59
  11. data/lib/puppet/application/cert.rb +4 -114
  12. data/lib/puppet/application/device.rb +48 -32
  13. data/lib/puppet/application/script.rb +1 -1
  14. data/lib/puppet/application/ssl.rb +135 -51
  15. data/lib/puppet/application.rb +5 -0
  16. data/lib/puppet/configurer.rb +2 -3
  17. data/lib/puppet/defaults.rb +33 -49
  18. data/lib/puppet/etc.rb +20 -0
  19. data/lib/puppet/face/config.rb +3 -3
  20. data/lib/puppet/face/key.rb +1 -1
  21. data/lib/puppet/face/node/clean.rb +0 -1
  22. data/lib/puppet/feature/base.rb +1 -1
  23. data/lib/puppet/file_bucket/dipper.rb +1 -1
  24. data/lib/puppet/file_serving/fileset.rb +1 -1
  25. data/lib/puppet/functions/abs.rb +1 -1
  26. data/lib/puppet/functions/new.rb +1 -1
  27. data/lib/puppet/module/task.rb +29 -38
  28. data/lib/puppet/pal/catalog_compiler.rb +96 -0
  29. data/lib/puppet/pal/compiler.rb +221 -0
  30. data/lib/puppet/pal/function_signature.rb +52 -0
  31. data/lib/puppet/pal/json_catalog_encoder.rb +67 -0
  32. data/lib/puppet/pal/pal_api.rb +15 -0
  33. data/lib/puppet/pal/pal_impl.rb +523 -0
  34. data/lib/puppet/pal/plan_signature.rb +71 -0
  35. data/lib/puppet/pal/script_compiler.rb +71 -0
  36. data/lib/puppet/pal/task_signature.rb +58 -0
  37. data/lib/puppet/parser/catalog_compiler.rb +24 -0
  38. data/lib/puppet/parser/compiler.rb +3 -1
  39. data/lib/puppet/parser/functions/generate.rb +7 -6
  40. data/lib/puppet/plugins/configuration.rb +5 -1
  41. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +3 -1
  42. data/lib/puppet/pops/evaluator/deferred_resolver.rb +3 -0
  43. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
  44. data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -3
  45. data/lib/puppet/pops/evaluator/runtime3_converter.rb +2 -2
  46. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +19 -10
  47. data/lib/puppet/pops/loader/task_instantiator.rb +13 -70
  48. data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
  49. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  50. data/lib/puppet/pops/pcore.rb +10 -33
  51. data/lib/puppet/pops/serialization/to_data_converter.rb +9 -1
  52. data/lib/puppet/pops/serialization.rb +1 -0
  53. data/lib/puppet/pops/types/p_timespan_type.rb +2 -2
  54. data/lib/puppet/pops/types/string_converter.rb +18 -4
  55. data/lib/puppet/pops/validation/checker4_0.rb +17 -2
  56. data/lib/puppet/provider/exec.rb +59 -57
  57. data/lib/puppet/provider/group/aix.rb +18 -2
  58. data/lib/puppet/provider/group/windows_adsi.rb +7 -3
  59. data/lib/puppet/provider/nameservice.rb +1 -25
  60. data/lib/puppet/provider/package/dnf.rb +2 -0
  61. data/lib/puppet/provider/package/pkgng.rb +37 -21
  62. data/lib/puppet/provider/package/portage.rb +2 -2
  63. data/lib/puppet/provider/package/windows/exe_package.rb +16 -10
  64. data/lib/puppet/provider/package/windows/msi_package.rb +8 -0
  65. data/lib/puppet/provider/package/windows/package.rb +9 -1
  66. data/lib/puppet/provider/package/windows.rb +2 -2
  67. data/lib/puppet/provider/package/yum.rb +1 -1
  68. data/lib/puppet/provider/parsedfile.rb +25 -4
  69. data/lib/puppet/provider/service/launchd.rb +19 -3
  70. data/lib/puppet/provider/service/smf.rb +54 -0
  71. data/lib/puppet/provider/service/systemd.rb +19 -0
  72. data/lib/puppet/provider/service/upstart.rb +1 -0
  73. data/lib/puppet/provider/service/windows.rb +22 -5
  74. data/lib/puppet/provider/user/aix.rb +48 -2
  75. data/lib/puppet/provider/user/useradd.rb +2 -10
  76. data/lib/puppet/provider/user/windows_adsi.rb +9 -1
  77. data/lib/puppet/resource/catalog.rb +1 -5
  78. data/lib/puppet/resource.rb +3 -1
  79. data/lib/puppet/ssl/host.rb +26 -16
  80. data/lib/puppet/syntax_checkers/epp.rb +34 -0
  81. data/lib/puppet/syntax_checkers/pp.rb +34 -0
  82. data/lib/puppet/transaction/event_manager.rb +13 -1
  83. data/lib/puppet/transaction/persistence.rb +1 -1
  84. data/lib/puppet/transaction/resource_harness.rb +3 -1
  85. data/lib/puppet/type/group.rb +29 -1
  86. data/lib/puppet/type/package.rb +5 -1
  87. data/lib/puppet/type/resources.rb +12 -2
  88. data/lib/puppet/type/schedule.rb +7 -0
  89. data/lib/puppet/type/service.rb +12 -0
  90. data/lib/puppet/type/user.rb +5 -2
  91. data/lib/puppet/type.rb +6 -0
  92. data/lib/puppet/util/command_line.rb +2 -3
  93. data/lib/puppet/util/execution.rb +15 -1
  94. data/lib/puppet/util/filetype.rb +56 -8
  95. data/lib/puppet/util/log/destinations.rb +3 -2
  96. data/lib/puppet/util/logging.rb +3 -2
  97. data/lib/puppet/util/posix.rb +15 -0
  98. data/lib/puppet/util/selinux.rb +1 -1
  99. data/lib/puppet/util/storage.rb +12 -0
  100. data/lib/puppet/util/windows/adsi.rb +79 -2
  101. data/lib/puppet/util/windows/api_types.rb +1 -1
  102. data/lib/puppet/util/windows/process.rb +23 -3
  103. data/lib/puppet/util/windows/registry.rb +29 -5
  104. data/lib/puppet/util/windows/security.rb +14 -0
  105. data/lib/puppet/util/windows/service.rb +294 -74
  106. data/lib/puppet/util/windows/user.rb +3 -5
  107. data/lib/puppet/util.rb +7 -3
  108. data/lib/puppet/version.rb +1 -1
  109. data/lib/puppet.rb +1 -0
  110. data/lib/puppet_pal.rb +5 -1099
  111. data/locales/ja/puppet.po +952 -986
  112. data/locales/puppet.pot +592 -347
  113. data/man/man5/puppet.conf.5 +26 -31
  114. data/man/man8/puppet-agent.8 +1 -1
  115. data/man/man8/puppet-apply.8 +1 -1
  116. data/man/man8/puppet-catalog.8 +1 -1
  117. data/man/man8/puppet-config.8 +4 -4
  118. data/man/man8/puppet-describe.8 +1 -1
  119. data/man/man8/puppet-device.8 +23 -19
  120. data/man/man8/puppet-doc.8 +1 -1
  121. data/man/man8/puppet-epp.8 +1 -1
  122. data/man/man8/puppet-facts.8 +1 -1
  123. data/man/man8/puppet-filebucket.8 +1 -1
  124. data/man/man8/puppet-generate.8 +1 -1
  125. data/man/man8/puppet-help.8 +1 -1
  126. data/man/man8/puppet-key.8 +2 -2
  127. data/man/man8/puppet-lookup.8 +1 -1
  128. data/man/man8/puppet-man.8 +1 -1
  129. data/man/man8/puppet-module.8 +1 -1
  130. data/man/man8/puppet-node.8 +1 -1
  131. data/man/man8/puppet-parser.8 +1 -1
  132. data/man/man8/puppet-plugin.8 +1 -1
  133. data/man/man8/puppet-report.8 +1 -1
  134. data/man/man8/puppet-resource.8 +1 -1
  135. data/man/man8/puppet-script.8 +1 -1
  136. data/man/man8/puppet-ssl.8 +26 -3
  137. data/man/man8/puppet-status.8 +1 -1
  138. data/man/man8/puppet.8 +2 -2
  139. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load.rb +11 -0
  140. data/spec/fixtures/unit/provider/package/pkgng/pkg.query +7 -1
  141. data/spec/fixtures/unit/provider/package/pkgng/pkg.query.zsh +1 -0
  142. data/spec/fixtures/unit/provider/service/smf/svcs_fmri.out +6 -0
  143. data/spec/fixtures/unit/provider/service/smf/svcs_multiple_fmris.out +13 -0
  144. data/spec/integration/application/apply_spec.rb +4 -1
  145. data/spec/integration/parser/collection_spec.rb +4 -8
  146. data/spec/integration/provider/service/windows_spec.rb +5 -5
  147. data/spec/integration/ssl/key_spec.rb +0 -4
  148. data/spec/integration/transaction_spec.rb +559 -0
  149. data/spec/integration/type/file_spec.rb +6 -6
  150. data/spec/integration/util/windows/registry_spec.rb +39 -0
  151. data/spec/integration/util/windows/security_spec.rb +10 -7
  152. data/spec/integration/util/windows/user_spec.rb +37 -17
  153. data/spec/lib/puppet/test_ca.rb +1 -1
  154. data/spec/spec_helper.rb +1 -1
  155. data/spec/unit/agent_spec.rb +2 -2
  156. data/spec/unit/application/apply_spec.rb +55 -2
  157. data/spec/unit/application/device_spec.rb +10 -7
  158. data/spec/unit/application/face_base_spec.rb +1 -1
  159. data/spec/unit/application/lookup_spec.rb +2 -1
  160. data/spec/unit/application/ssl_spec.rb +178 -109
  161. data/spec/unit/application_spec.rb +29 -11
  162. data/spec/unit/configurer/downloader_spec.rb +1 -1
  163. data/spec/unit/configurer_spec.rb +16 -5
  164. data/spec/unit/etc_spec.rb +25 -0
  165. data/spec/unit/face/node_spec.rb +1 -3
  166. data/spec/unit/face/parser_spec.rb +15 -0
  167. data/spec/unit/file_serving/fileset_spec.rb +11 -11
  168. data/spec/unit/functions/logging_spec.rb +10 -3
  169. data/spec/unit/indirector/catalog/json_spec.rb +9 -3
  170. data/spec/unit/indirector/yaml_spec.rb +1 -1
  171. data/spec/unit/network/http/connection_spec.rb +2 -2
  172. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +36 -0
  173. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +22 -4
  174. data/spec/unit/pops/loaders/loader_spec.rb +9 -17
  175. data/spec/unit/pops/loaders/loaders_spec.rb +48 -0
  176. data/spec/unit/pops/loaders/module_loaders_spec.rb +7 -7
  177. data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
  178. data/spec/unit/pops/serialization/to_from_hr_spec.rb +9 -0
  179. data/spec/unit/pops/types/p_timespan_type_spec.rb +22 -0
  180. data/spec/unit/pops/types/p_timestamp_type_spec.rb +19 -0
  181. data/spec/unit/pops/types/string_converter_spec.rb +25 -1
  182. data/spec/unit/pops/types/task_spec.rb +42 -116
  183. data/spec/unit/pops/validator/validator_spec.rb +24 -10
  184. data/spec/unit/provider/exec/posix_spec.rb +24 -0
  185. data/spec/unit/provider/group/aix_spec.rb +20 -6
  186. data/spec/unit/provider/group/ldap_spec.rb +22 -25
  187. data/spec/unit/provider/group/pw_spec.rb +7 -10
  188. data/spec/unit/provider/group/windows_adsi_spec.rb +42 -33
  189. data/spec/unit/provider/nameservice/directoryservice_spec.rb +97 -103
  190. data/spec/unit/provider/package/aix_spec.rb +5 -8
  191. data/spec/unit/provider/package/apt_spec.rb +3 -6
  192. data/spec/unit/provider/package/dnf_spec.rb +38 -25
  193. data/spec/unit/provider/package/dpkg_spec.rb +18 -21
  194. data/spec/unit/provider/package/freebsd_spec.rb +4 -7
  195. data/spec/unit/provider/package/gem_spec.rb +41 -41
  196. data/spec/unit/provider/package/hpux_spec.rb +7 -10
  197. data/spec/unit/provider/package/macports_spec.rb +13 -15
  198. data/spec/unit/provider/package/nim_spec.rb +3 -10
  199. data/spec/unit/provider/package/openbsd_spec.rb +14 -17
  200. data/spec/unit/provider/package/pip3_spec.rb +3 -6
  201. data/spec/unit/provider/package/pip_spec.rb +45 -49
  202. data/spec/unit/provider/package/pkgin_spec.rb +13 -18
  203. data/spec/unit/provider/package/pkgng_spec.rb +32 -27
  204. data/spec/unit/provider/package/puppet_gem_spec.rb +6 -9
  205. data/spec/unit/provider/package/tdnf_spec.rb +9 -12
  206. data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
  207. data/spec/unit/provider/package/windows_spec.rb +4 -4
  208. data/spec/unit/provider/package/yum_spec.rb +30 -16
  209. data/spec/unit/provider/package/zypper_spec.rb +17 -19
  210. data/spec/unit/provider/service/bsd_spec.rb +7 -9
  211. data/spec/unit/provider/service/daemontools_spec.rb +12 -16
  212. data/spec/unit/provider/service/debian_spec.rb +6 -10
  213. data/spec/unit/provider/service/freebsd_spec.rb +2 -2
  214. data/spec/unit/provider/service/launchd_spec.rb +19 -0
  215. data/spec/unit/provider/service/openbsd_spec.rb +13 -17
  216. data/spec/unit/provider/service/rcng_spec.rb +2 -4
  217. data/spec/unit/provider/service/redhat_spec.rb +12 -11
  218. data/spec/unit/provider/service/runit_spec.rb +7 -14
  219. data/spec/unit/provider/service/smf_spec.rb +77 -13
  220. data/spec/unit/provider/service/src_spec.rb +11 -16
  221. data/spec/unit/provider/service/systemd_spec.rb +39 -1
  222. data/spec/unit/provider/service/windows_spec.rb +39 -7
  223. data/spec/unit/provider/user/aix_spec.rb +43 -2
  224. data/spec/unit/provider/user/hpux_spec.rb +3 -5
  225. data/spec/unit/provider/user/ldap_spec.rb +29 -32
  226. data/spec/unit/provider/user/pw_spec.rb +10 -13
  227. data/spec/unit/provider/user/useradd_spec.rb +2 -2
  228. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  229. data/spec/unit/puppet_pal_2pec.rb +6 -6
  230. data/spec/unit/puppet_pal_catalog_spec.rb +58 -0
  231. data/spec/unit/resource/catalog_spec.rb +2 -2
  232. data/spec/unit/resource_spec.rb +31 -0
  233. data/spec/unit/ssl/host_spec.rb +22 -1
  234. data/spec/unit/ssl/key_spec.rb +2 -4
  235. data/spec/unit/task_spec.rb +50 -5
  236. data/spec/unit/transaction/event_manager_spec.rb +12 -1
  237. data/spec/unit/transaction/persistence_spec.rb +4 -4
  238. data/spec/unit/transaction/resource_harness_spec.rb +18 -0
  239. data/spec/unit/type/group_spec.rb +11 -3
  240. data/spec/unit/type/resources_spec.rb +18 -0
  241. data/spec/unit/type/service_spec.rb +27 -1
  242. data/spec/unit/util/execution_spec.rb +77 -0
  243. data/spec/unit/util/filetype_spec.rb +13 -5
  244. data/spec/unit/util/log/destinations_spec.rb +10 -0
  245. data/spec/unit/util/logging_spec.rb +58 -41
  246. data/spec/unit/util/monkey_patches_spec.rb +18 -5
  247. data/spec/unit/util/posix_spec.rb +28 -0
  248. data/spec/unit/util/selinux_spec.rb +4 -0
  249. data/spec/unit/util/storage_spec.rb +107 -0
  250. data/spec/unit/util/suidmanager_spec.rb +1 -3
  251. data/spec/unit/util/windows/adsi_spec.rb +95 -0
  252. data/spec/unit/util/windows/service_spec.rb +377 -131
  253. metadata +24 -11
  254. data/ext/autotest/Rakefile +0 -8
  255. data/ext/autotest/config +0 -43
  256. data/ext/autotest/readme.rst +0 -16
  257. data/spec/fixtures/unit/provider/package/pkgng/pkg.info +0 -7
  258. data/spec/fixtures/unit/provider/package/pkgng/pkg.query_absent +0 -1
  259. data/spec/watchr.rb +0 -137
@@ -17,6 +17,10 @@ module Puppet::Util::Windows
17
17
  # no shorter
18
18
  DEFAULT_TIMEOUT = 30
19
19
 
20
+ # Service error codes
21
+ # https://docs.microsoft.com/en-us/windows/desktop/debug/system-error-codes--1000-1299-
22
+ ERROR_SERVICE_DOES_NOT_EXIST = 0x00000424
23
+
20
24
  # Service control codes
21
25
  # https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-controlserviceexw
22
26
  SERVICE_CONTROL_STOP = 0x00000001
@@ -36,6 +40,26 @@ module Puppet::Util::Windows
36
40
  SERVICE_CONTROL_PRESHUTDOWN = 0x0000000F
37
41
  SERVICE_CONTROL_TIMECHANGE = 0x00000010
38
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
+
39
63
 
40
64
  # Service start type codes
41
65
  # https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-changeserviceconfigw
@@ -77,7 +101,14 @@ module Puppet::Util::Windows
77
101
  SERVICE_START_PENDING = 0x00000002
78
102
  SERVICE_STOP_PENDING = 0x00000003
79
103
  SERVICE_STOPPED = 0x00000001
80
- SERVICE_STATES = {
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 = {
81
112
  SERVICE_CONTINUE_PENDING => :SERVICE_CONTINUE_PENDING,
82
113
  SERVICE_PAUSE_PENDING => :SERVICE_PAUSE_PENDING,
83
114
  SERVICE_PAUSED => :SERVICE_PAUSED,
@@ -249,59 +280,97 @@ module Puppet::Util::Windows
249
280
  )
250
281
  end
251
282
 
252
- # Start a windows service, assume that the service is already in the stopped state
283
+ # Returns true if the service exists, false otherwise.
253
284
  #
254
- # @param [:string] service_name name of the service to start
255
- def start(service_name)
256
- open_service(service_name, SC_MANAGER_CONNECT, SERVICE_START | SERVICE_QUERY_STATUS) do |service|
257
- # don't attempt to fail here if the service isn't stopped because windows error codes
258
- # are likely more informative than ours and a failed call to StartServiceW will produce
259
- # those errors
260
- wait_for_pending_transition(service, SERVICE_STOP_PENDING, SERVICE_STOPPED)
285
+ # @param [String] service_name name of the service
286
+ def exists?(service_name)
287
+ open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_STATUS) do |_|
288
+ true
289
+ end
290
+ rescue Puppet::Util::Windows::Error => e
291
+ return false if e.code == ERROR_SERVICE_DOES_NOT_EXIST
292
+ raise e
293
+ end
294
+ module_function :exists?
295
+
296
+ # Start a windows service
297
+ #
298
+ # @param [String] service_name name of the service to start
299
+ # @param optional [Integer] timeout the minumum number of seconds to wait before timing out
300
+ def start(service_name, timeout: DEFAULT_TIMEOUT)
301
+ Puppet.debug _("Starting the %{service_name} service. Timeout set to: %{timeout} seconds") % { service_name: service_name, timeout: timeout }
302
+
303
+ valid_initial_states = [
304
+ SERVICE_STOP_PENDING,
305
+ SERVICE_STOPPED,
306
+ SERVICE_START_PENDING
307
+ ]
308
+
309
+ transition_service_state(service_name, valid_initial_states, SERVICE_RUNNING, timeout) do |service|
261
310
  if StartServiceW(service, 0, FFI::Pointer::NULL) == FFI::WIN32_FALSE
262
- raise Puppet::Util::Windows::Error.new(_("Failed to start the service"))
263
- end
264
- unless wait_for_pending_transition(service, SERVICE_START_PENDING, SERVICE_RUNNING)
265
- raise Puppet::Error.new(_("Failed to start the service, after calling StartService the service is not in SERVICE_START_PENDING or SERVICE_RUNNING"))
311
+ raise Puppet::Util::Windows::Error, _("Failed to start the service")
266
312
  end
267
313
  end
314
+
315
+ Puppet.debug _("Successfully started the %{service_name} service") % { service_name: service_name }
268
316
  end
269
317
  module_function :start
270
318
 
271
- # Use ControlService to send a stop signal to a windows service
319
+ # Stop a windows service
272
320
  #
273
- # @param [:string] service_name name of the service to stop
274
- def stop(service_name)
275
- open_service(service_name, SC_MANAGER_CONNECT, SERVICE_STOP | SERVICE_QUERY_STATUS) do |service|
276
- FFI::MemoryPointer.new(SERVICE_STATUS.size) do |status_ptr|
277
- status = SERVICE_STATUS.new(status_ptr)
278
- # don't attempt to fail here if the service isn't started because windows error codes
279
- # are likely more informative than ours and a failed call to ControlService will produce
280
- # those errors
281
- wait_for_pending_transition(service, SERVICE_START_PENDING, SERVICE_RUNNING)
282
- if ControlService(service, SERVICE_CONTROL_STOP, status) == FFI::WIN32_FALSE
283
- raise Puppet::Util::Windows::Error.new(_("Failed to send stop control to service, current state is %{current_state}. Failed with") % { current_state: status[:dwCurrentState].to_s })
284
- end
285
- unless wait_for_pending_transition(service, SERVICE_STOP_PENDING, SERVICE_STOPPED)
286
- raise Puppet::Error.new(_("Failed to stop the service, after calling ControlService the service is not in SERVICE_STOP_PENDING or SERVICE_STOPPED"))
287
- end
288
- end
321
+ # @param [String] service_name name of the service to stop
322
+ # @param optional [Integer] timeout the minumum number of seconds to wait before timing out
323
+ def stop(service_name, timeout: DEFAULT_TIMEOUT)
324
+ Puppet.debug _("Stopping the %{service_name} service. Timeout set to: %{timeout} seconds") % { service_name: service_name, timeout: timeout }
325
+
326
+ valid_initial_states = SERVICE_STATES.keys - [SERVICE_STOPPED]
327
+
328
+ transition_service_state(service_name, valid_initial_states, SERVICE_STOPPED, timeout) do |service|
329
+ send_service_control_signal(service, SERVICE_CONTROL_STOP)
289
330
  end
331
+
332
+ Puppet.debug _("Successfully stopped the %{service_name} service") % { service_name: service_name }
290
333
  end
291
334
  module_function :stop
292
335
 
336
+ # Resume a paused windows service
337
+ #
338
+ # @param [String] service_name name of the service to resume
339
+ # @param optional [Integer] :timeout the minumum number of seconds to wait before timing out
340
+ def resume(service_name, timeout: DEFAULT_TIMEOUT)
341
+ Puppet.debug _("Resuming the %{service_name} service. Timeout set to: %{timeout} seconds") % { service_name: service_name, timeout: timeout }
342
+
343
+ valid_initial_states = [
344
+ SERVICE_PAUSE_PENDING,
345
+ SERVICE_PAUSED,
346
+ SERVICE_CONTINUE_PENDING
347
+ ]
348
+
349
+ transition_service_state(service_name, valid_initial_states, SERVICE_RUNNING, timeout) do |service|
350
+ # The SERVICE_CONTROL_CONTINUE signal can only be sent when
351
+ # the service is in the SERVICE_PAUSED state
352
+ wait_on_pending_state(service, SERVICE_PAUSE_PENDING, timeout)
353
+
354
+ send_service_control_signal(service, SERVICE_CONTROL_CONTINUE)
355
+ end
356
+
357
+ Puppet.debug _("Successfully resumed the %{service_name} service") % { service_name: service_name }
358
+ end
359
+ module_function :resume
360
+
293
361
  # Query the state of a service using QueryServiceStatusEx
294
362
  #
295
- # @param [:string] service_name name of the service to query
363
+ # @param [string] service_name name of the service to query
296
364
  # @return [string] the status of the service
297
365
  def service_state(service_name)
298
- status = nil
366
+ state = nil
299
367
  open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_STATUS) do |service|
300
- status = query_status(service)
368
+ query_status(service) do |status|
369
+ state = SERVICE_STATES[status[:dwCurrentState]]
370
+ end
301
371
  end
302
- state = SERVICE_STATES[status[:dwCurrentState]]
303
372
  if state.nil?
304
- raise Puppet::Error.new(_("Unknown Service state '%{current_state}' for '%{service_name}'") % { current_state: status[:dwCurrentState].to_s, service_name: service_name})
373
+ raise Puppet::Error.new(_("Unknown Service state '%{current_state}' for '%{service_name}'") % { current_state: state.to_s, service_name: service_name})
305
374
  end
306
375
  state
307
376
  end
@@ -309,16 +378,17 @@ module Puppet::Util::Windows
309
378
 
310
379
  # Query the configuration of a service using QueryServiceConfigW
311
380
  #
312
- # @param [:string] service_name name of the service to query
381
+ # @param [String] service_name name of the service to query
313
382
  # @return [QUERY_SERVICE_CONFIGW.struct] the configuration of the service
314
383
  def service_start_type(service_name)
315
- config = nil
384
+ start_type = nil
316
385
  open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_CONFIG) do |service|
317
- config = query_config(service)
386
+ query_config(service) do |config|
387
+ start_type = SERVICE_START_TYPES[config[:dwStartType]]
388
+ end
318
389
  end
319
- start_type = SERVICE_START_TYPES[config[:dwStartType]]
320
390
  if start_type.nil?
321
- raise Puppet::Error.new(_("Unknown start type '%{start_type}' for '%{service_name}'") % { start_type: config[:dwStartType].to_s, service_name: service_name})
391
+ raise Puppet::Error.new(_("Unknown start type '%{start_type}' for '%{service_name}'") % { start_type: start_type.to_s, service_name: service_name})
322
392
  end
323
393
  start_type
324
394
  end
@@ -456,13 +526,18 @@ module Puppet::Util::Windows
456
526
  # @param [Integer] service_access code corresponding to the access type requested for the service
457
527
  # @yieldparam [:handle] service the windows native handle used to access
458
528
  # the service
529
+ # @return the result of the block
459
530
  def open_service(service_name, scm_access, service_access, &block)
460
531
  service = FFI::Pointer::NULL_HANDLE
532
+
533
+ result = nil
461
534
  open_scm(scm_access) do |scm|
462
535
  service = OpenServiceW(scm, wide_string(service_name), service_access)
463
536
  raise Puppet::Util::Windows::Error.new(_("Failed to open a handle to the service")) if service == FFI::Pointer::NULL_HANDLE
464
- yield service
537
+ result = yield service
465
538
  end
539
+
540
+ result
466
541
  ensure
467
542
  CloseServiceHandle(service)
468
543
  end
@@ -482,6 +557,79 @@ module Puppet::Util::Windows
482
557
  end
483
558
  private :open_scm
484
559
 
560
+ # @api private
561
+ # Transition the service to the specified state. The block should perform
562
+ # the actual transition.
563
+ #
564
+ # @param [String] service_name the name of the service to transition
565
+ # @param [[Integer]] valid_initial_states an array of valid states that the service can transition from
566
+ # @param [Integer] final_state the state that the service will transition to
567
+ # @param [Integer] timeout the minumum number of seconds to wait before timing out
568
+ def transition_service_state(service_name, valid_initial_states, final_state, timeout, &block)
569
+ service_access = SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS
570
+ open_service(service_name, SC_MANAGER_CONNECT, service_access) do |service|
571
+ query_status(service) do |status|
572
+ initial_state = status[:dwCurrentState]
573
+ # If the service is already in the final_state, then
574
+ # no further work needs to be done
575
+ if initial_state == final_state
576
+ Puppet.debug _("The service is already in the %{final_state} state. No further work needs to be done.") % { final_state: SERVICE_STATES[final_state] }
577
+
578
+ next
579
+ end
580
+
581
+ # Check that initial_state corresponds to a valid
582
+ # initial state
583
+ unless valid_initial_states.include?(initial_state)
584
+ valid_initial_states_str = valid_initial_states.map do |state|
585
+ SERVICE_STATES[state]
586
+ end.join(", ")
587
+
588
+ 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] }
589
+ end
590
+
591
+ # Check if there's a pending transition to the final_state. If so, then wait for
592
+ # that transition to finish.
593
+ possible_pending_states = FINAL_STATES.keys.select do |pending_state|
594
+ # SERVICE_RUNNING has two pending states, SERVICE_START_PENDING and
595
+ # SERVICE_CONTINUE_PENDING. That is why we need the #select here
596
+ FINAL_STATES[pending_state] == final_state
597
+ end
598
+ if possible_pending_states.include?(initial_state)
599
+ 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 }
600
+ wait_on_pending_state(service, initial_state, timeout)
601
+
602
+ next
603
+ end
604
+
605
+ # If we are in an unsafe pending state like SERVICE_START_PENDING
606
+ # or SERVICE_STOP_PENDING, then we want to wait for that pending
607
+ # transition to finish before transitioning the service state.
608
+ # The reason we do this is because SERVICE_START_PENDING is when
609
+ # the service thread is being created and initialized, while
610
+ # SERVICE_STOP_PENDING is when the service thread is being cleaned
611
+ # up and destroyed. Thus there is a chance that when the service is
612
+ # in either of these states, its service thread may not yet be ready
613
+ # to perform the state transition (it may not even exist).
614
+ if UNSAFE_PENDING_STATES.include?(initial_state)
615
+ Puppet.debug _("The service is in the %{pending_state} state, which is an unsafe pending state.") % { pending_state: SERVICE_STATES[initial_state] }
616
+ wait_on_pending_state(service, initial_state, timeout)
617
+ initial_state = FINAL_STATES[initial_state]
618
+ end
619
+
620
+ 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] }
621
+
622
+ yield service
623
+
624
+ Puppet.debug _("Waiting for the transition to finish")
625
+ wait_on_state_transition(service, initial_state, final_state, timeout)
626
+ end
627
+ end
628
+ rescue => detail
629
+ 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
630
+ end
631
+ private :transition_service_state
632
+
485
633
  # @api private
486
634
  # perform QueryServiceStatusEx on a windows service and return the
487
635
  # result
@@ -519,9 +667,9 @@ module Puppet::Util::Windows
519
667
  if success == FFI::WIN32_FALSE
520
668
  raise Puppet::Util::Windows::Error.new(_("Service query failed"))
521
669
  end
670
+ yield status
522
671
  end
523
672
  end
524
- status
525
673
  end
526
674
  private :query_status
527
675
 
@@ -531,7 +679,7 @@ module Puppet::Util::Windows
531
679
  #
532
680
  # @param [:handle] service handle of the service to query
533
681
  # @return [QUERY_SERVICE_CONFIGW struct] the result of the query
534
- def query_config(service)
682
+ def query_config(service, &block)
535
683
  config = nil
536
684
  size_required = nil
537
685
  # Fetch the bytes of memory required to be allocated
@@ -555,52 +703,124 @@ module Puppet::Util::Windows
555
703
  if success == FFI::WIN32_FALSE
556
704
  raise Puppet::Util::Windows::Error.new(_("Service query failed"))
557
705
  end
706
+ yield config
558
707
  end
559
708
  end
560
- config
561
709
  end
562
710
  private :query_config
563
711
 
564
712
  # @api private
565
- # waits for a windows service to report final_state if it
566
- # is in pending_state
713
+ # Sends a service control signal to a service
714
+ #
715
+ # @param [:handle] service handle to the service
716
+ # @param [Integer] signal the service control signal to send
717
+ def send_service_control_signal(service, signal)
718
+ FFI::MemoryPointer.new(SERVICE_STATUS.size) do |status_ptr|
719
+ status = SERVICE_STATUS.new(status_ptr)
720
+ if ControlService(service, signal, status) == FFI::WIN32_FALSE
721
+ raise Puppet::Util::Windows::Error, _("Failed to send the %{control_signal} signal to the service. Its current state is %{current_state}. Reason for failure:") % { control_signal: SERVICE_CONTROL_SIGNALS[signal], current_state: SERVICE_STATES[status[:dwCurrentState]] }
722
+ end
723
+ end
724
+ end
725
+
726
+ # @api private
727
+ # Waits for a service to transition from one state to
728
+ # another state.
567
729
  #
568
730
  # @param [:handle] service handle to the service to wait on
569
- # @param [Integer] pending_state the state to wait on
570
- # @param [Integer] final_state the state indicating the transition is finished
571
- # @return [bool] 'true' once the service is reporting final_state,
572
- # 'false' if the service was not in pending_state or finaL_state
573
- def wait_for_pending_transition(service, pending_state, final_state)
731
+ # @param [Integer] initial_state the state that the service is transitioning from.
732
+ # @param [Integer] final_state the state that the service is transitioning to
733
+ # @param [Integer] timeout the minumum number of seconds to wait before timing out
734
+ def wait_on_state_transition(service, initial_state, final_state, timeout)
735
+ # Get the pending state for this transition. Note that SERVICE_RUNNING
736
+ # has two possible pending states, which is why we need this logic.
737
+ if final_state != SERVICE_RUNNING
738
+ pending_state = FINAL_STATES.key(final_state)
739
+ elsif initial_state == SERVICE_STOPPED
740
+ # SERVICE_STOPPED => SERVICE_RUNNING
741
+ pending_state = SERVICE_START_PENDING
742
+ else
743
+ # SERVICE_PAUSED => SERVICE_RUNNING
744
+ pending_state = SERVICE_CONTINUE_PENDING
745
+ end
746
+
747
+ # Wait for the transition to finish
748
+ state = nil
749
+ elapsed_time = 0
750
+ while elapsed_time <= timeout
751
+
752
+ query_status(service) do |status|
753
+ state = status[:dwCurrentState]
754
+ return if state == final_state
755
+ if state == pending_state
756
+ Puppet.debug _("The service transitioned to the %{pending_state} state.") % { pending_state: SERVICE_STATES[pending_state] }
757
+ wait_on_pending_state(service, pending_state, timeout)
758
+ return
759
+ end
760
+ sleep(1)
761
+ elapsed_time += 1
762
+ end
763
+ end
764
+ # Timed out while waiting for the transition to finish. Raise an error
765
+ # We can still use the state variable read from the FFI struct because
766
+ # FFI creates new Integer objects during an assignment of an integer value
767
+ # stored in an FFI struct. We verified that the '=' operater is safe
768
+ # from the freed memory since the new ruby object created during the
769
+ # assignment will remain in ruby memory and remain immutable and constant.
770
+ 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] }
771
+ end
772
+ private :wait_on_state_transition
773
+
774
+ # @api private
775
+ # Waits for a service to finish transitioning from
776
+ # a pending state. The service must be in the pending state
777
+ # before invoking this routine.
778
+ #
779
+ # @param [:handle] service handle to the service to wait on
780
+ # @param [Integer] pending_state the pending state
781
+ # @param [Integer] timeout the minumum number of seconds to wait before timing out
782
+ def wait_on_pending_state(service, pending_state, timeout)
783
+ final_state = FINAL_STATES[pending_state]
784
+
785
+ Puppet.debug _("Waiting for the pending transition to the %{final_state} state to finish.") % { final_state: SERVICE_STATES[final_state] }
786
+
574
787
  elapsed_time = 0
575
788
  last_checkpoint = -1
576
789
  loop do
577
- status = query_status(service)
578
- state = status[:dwCurrentState]
579
- return true if state == final_state
580
- unless state == pending_state
581
- return false
582
- end
583
- # When the service is in the pending state we need to do the following:
584
- # 1. check if any progress has been made since dwWaitHint using dwCheckPoint,
585
- # and fail if no progress was made
586
- # 2. if progress has been made, increment elapsed_time and set last_checkpoint
587
- # 3. sleep, then loop again if there was progress.
588
- time_to_wait = wait_hint_to_wait_time(status[:dwWaitHint])
589
- if status[:dwCheckPoint] > last_checkpoint
590
- elapsed_time = 0
591
- else
592
- timeout = milliseconds_to_seconds(status[:dwWaitHint]);
593
- timeout = DEFAULT_TIMEOUT if timeout < DEFAULT_TIMEOUT
594
- if elapsed_time >= (timeout)
595
- raise Puppet::Error.new(_("No progress made on service operation and dwWaitHint exceeded"))
790
+ query_status(service) do |status|
791
+ state = status[:dwCurrentState]
792
+ checkpoint = status[:dwCheckPoint]
793
+ wait_hint = status[:dwWaitHint]
794
+ # Check if our service has finished transitioning to
795
+ # the final_state OR if an unexpected transition
796
+ # has occurred
797
+ return if state == final_state
798
+ unless state == pending_state
799
+ 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] }
800
+ end
801
+
802
+ # Check if any progress has been made since our last sleep
803
+ # using the dwCheckPoint. If no progress has been made then
804
+ # check if we've timed out, and raise an error if so
805
+ if checkpoint > last_checkpoint
806
+ elapsed_time = 0
807
+ last_checkpoint = checkpoint
808
+ else
809
+ wait_hint = milliseconds_to_seconds(status[:dwWaitHint])
810
+ timeout = wait_hint < timeout ? timeout : wait_hint
811
+
812
+ if elapsed_time >= timeout
813
+ 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] }
814
+ end
596
815
  end
816
+ wait_time = wait_hint_to_wait_time(wait_hint)
817
+ # Wait a bit before rechecking the service's state
818
+ sleep(wait_time)
819
+ elapsed_time += wait_time
597
820
  end
598
- last_checkpoint = status[:dwCheckPoint]
599
- sleep(time_to_wait)
600
- elapsed_time += time_to_wait
601
821
  end
602
822
  end
603
- private :wait_for_pending_transition
823
+ private :wait_on_pending_state
604
824
 
605
825
  # @api private
606
826
  #
@@ -8,13 +8,11 @@ module Puppet::Util::Windows::User
8
8
  extend FFI::Library
9
9
 
10
10
  def admin?
11
- elevated_supported = Puppet::Util::Windows::Process.supports_elevated_security?
11
+ return false unless check_token_membership
12
12
 
13
13
  # if Vista or later, check for unrestricted process token
14
- return Puppet::Util::Windows::Process.elevated_security? if elevated_supported
15
-
16
- # otherwise 2003 or less
17
- check_token_membership
14
+ elevated_supported = Puppet::Util::Windows::Process.supports_elevated_security?
15
+ return elevated_supported ? Puppet::Util::Windows::Process.elevated_security? : true
18
16
  end
19
17
  module_function :admin?
20
18
 
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
- $stdin.reopen(stdin)
482
- $stdout.reopen(stdout)
483
- $stderr.reopen(stderr)
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|
@@ -6,7 +6,7 @@
6
6
  # Raketasks and such to set the version based on the output of `git describe`
7
7
 
8
8
  module Puppet
9
- PUPPETVERSION = '6.0.0'
9
+ PUPPETVERSION = '6.1.0'
10
10
 
11
11
  ##
12
12
  # version is a public API method intended to always provide a fast and
data/lib/puppet.rb CHANGED
@@ -297,3 +297,4 @@ require 'puppet/util/storage'
297
297
  require 'puppet/status'
298
298
  require 'puppet/file_bucket/file'
299
299
  require 'puppet/plugins/configuration'
300
+ require 'puppet/pal/pal_api'