bolt 0.23.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +5 -2
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +5 -8
- data/lib/bolt/applicator.rb +11 -8
- data/lib/bolt/boltdir.rb +13 -5
- data/lib/bolt/catalog.rb +22 -47
- data/lib/bolt/config.rb +1 -26
- data/lib/bolt/executor.rb +1 -1
- data/lib/bolt/outputter.rb +0 -9
- data/lib/bolt/outputter/human.rb +29 -14
- data/lib/bolt/outputter/json.rb +12 -1
- data/lib/bolt/pal.rb +12 -10
- data/lib/bolt/target.rb +0 -6
- data/lib/bolt/task.rb +53 -10
- data/lib/bolt/transport/base.rb +1 -6
- data/lib/bolt/transport/local.rb +11 -13
- data/lib/bolt/transport/local/shell.rb +2 -2
- data/lib/bolt/transport/ssh.rb +16 -11
- data/lib/bolt/transport/winrm.rb +8 -11
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_ext/schemas/task.json +12 -5
- data/libexec/apply_catalog.rb +3 -1
- data/libexec/bolt_catalog +4 -0
- data/vendored/puppet/lib/puppet.rb +2 -1
- data/vendored/puppet/lib/puppet/application/agent.rb +2 -6
- data/vendored/puppet/lib/puppet/application/apply.rb +100 -60
- data/vendored/puppet/lib/puppet/application/cert.rb +26 -291
- data/vendored/puppet/lib/puppet/application/device.rb +0 -5
- data/vendored/puppet/lib/puppet/application/lookup.rb +1 -1
- data/vendored/puppet/lib/puppet/application/ssl.rb +133 -0
- data/vendored/puppet/lib/puppet/application_support.rb +1 -2
- data/vendored/puppet/lib/puppet/configurer.rb +34 -50
- data/vendored/puppet/lib/puppet/configurer/downloader.rb +1 -1
- data/vendored/puppet/lib/puppet/configurer/plugin_handler.rb +1 -1
- data/vendored/puppet/lib/puppet/daemon.rb +1 -1
- data/vendored/puppet/lib/puppet/defaults.rb +40 -117
- data/vendored/puppet/lib/puppet/face/epp.rb +2 -2
- data/vendored/puppet/lib/puppet/face/help.rb +21 -7
- data/vendored/puppet/lib/puppet/face/node/clean.rb +14 -10
- data/vendored/puppet/lib/puppet/feature/base.rb +7 -23
- data/vendored/puppet/lib/puppet/feature/eventlog.rb +1 -1
- data/vendored/puppet/lib/puppet/file_serving/base.rb +2 -2
- data/vendored/puppet/lib/puppet/file_serving/fileset.rb +1 -1
- data/vendored/puppet/lib/puppet/file_serving/metadata.rb +2 -2
- data/vendored/puppet/lib/puppet/functions.rb +133 -0
- data/vendored/puppet/lib/puppet/functions/eyaml_lookup_key.rb +4 -5
- data/vendored/puppet/lib/puppet/functions/filter.rb +7 -6
- data/vendored/puppet/lib/puppet/functions/new.rb +37 -53
- data/vendored/puppet/lib/puppet/functions/warning.rb +1 -1
- data/vendored/puppet/lib/puppet/functions/yaml_data.rb +4 -5
- data/vendored/puppet/lib/puppet/gettext/config.rb +1 -1
- data/vendored/puppet/lib/puppet/graph.rb +0 -2
- data/vendored/puppet/lib/puppet/indirector/catalog/json.rb +14 -3
- data/vendored/puppet/lib/puppet/indirector/catalog/yaml.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/certificate/file.rb +0 -1
- data/vendored/puppet/lib/puppet/indirector/facts/yaml.rb +4 -2
- data/vendored/puppet/lib/puppet/indirector/key/file.rb +1 -6
- data/vendored/puppet/lib/puppet/indirector/node/exec.rb +1 -3
- data/vendored/puppet/lib/puppet/indirector/node/yaml.rb +0 -6
- data/vendored/puppet/lib/puppet/indirector/request.rb +1 -1
- data/vendored/puppet/lib/puppet/indirector/ssl_file.rb +3 -44
- data/vendored/puppet/lib/puppet/indirector/yaml.rb +4 -4
- data/vendored/puppet/lib/puppet/info_service/task_information_service.rb +7 -3
- data/vendored/puppet/lib/puppet/loaders.rb +1 -0
- data/vendored/puppet/lib/puppet/module/task.rb +198 -29
- data/vendored/puppet/lib/puppet/module_tool/applications/unpacker.rb +1 -1
- data/vendored/puppet/lib/puppet/network/format_support.rb +13 -8
- data/vendored/puppet/lib/puppet/network/formats.rb +93 -2
- data/vendored/puppet/lib/puppet/network/http/api/indirected_routes.rb +10 -3
- data/vendored/puppet/lib/puppet/node/facts.rb +11 -1
- data/vendored/puppet/lib/puppet/parser/catalog_compiler.rb +56 -0
- data/vendored/puppet/lib/puppet/parser/compiler.rb +3 -1
- data/vendored/puppet/lib/puppet/parser/functions.rb +3 -1
- data/vendored/puppet/lib/puppet/parser/functions/filter.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/functions/generate.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/functions/sprintf.rb +12 -1
- data/vendored/puppet/lib/puppet/parser/functions/tagged.rb +1 -4
- data/vendored/puppet/lib/puppet/parser/scope.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/script_compiler.rb +7 -2
- data/vendored/puppet/lib/puppet/pops/evaluator/deferred_resolver.rb +5 -3
- data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_converter.rb +23 -4
- data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
- data/vendored/puppet/lib/puppet/pops/functions/dispatch.rb +4 -0
- data/vendored/puppet/lib/puppet/pops/issues.rb +8 -0
- data/vendored/puppet/lib/puppet/pops/loader/loader.rb +2 -2
- data/vendored/puppet/lib/puppet/pops/loader/loader_paths.rb +3 -1
- data/vendored/puppet/lib/puppet/pops/loader/module_loaders.rb +30 -9
- data/vendored/puppet/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
- data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +0 -1
- data/vendored/puppet/lib/puppet/pops/loader/task_instantiator.rb +13 -70
- data/vendored/puppet/lib/puppet/pops/loaders.rb +19 -29
- data/vendored/puppet/lib/puppet/pops/lookup/hiera_config.rb +1 -1
- data/vendored/puppet/lib/puppet/pops/model/model_label_provider.rb +4 -1
- data/vendored/puppet/lib/puppet/pops/pcore.rb +10 -33
- data/vendored/puppet/lib/puppet/pops/serialization.rb +2 -0
- data/vendored/puppet/lib/puppet/pops/serialization/from_data_converter.rb +2 -1
- data/vendored/puppet/lib/puppet/pops/serialization/to_data_converter.rb +11 -3
- data/vendored/puppet/lib/puppet/pops/serialization/to_stringified_converter.rb +226 -0
- data/vendored/puppet/lib/puppet/pops/types/p_object_type.rb +3 -0
- data/vendored/puppet/lib/puppet/pops/validation/checker4_0.rb +97 -47
- data/vendored/puppet/lib/puppet/pops/validation/validator_factory_4_0.rb +7 -8
- data/vendored/puppet/lib/puppet/property/keyvalue.rb +70 -8
- data/vendored/puppet/lib/puppet/provider/aix_object.rb +483 -0
- data/vendored/puppet/lib/puppet/provider/file/windows.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/group/aix.rb +51 -112
- data/vendored/puppet/lib/puppet/provider/package/gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/pip.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/puppet_gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/rpm.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/windows/package.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/zypper.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/service/systemd.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/service/windows.rb +37 -40
- data/vendored/puppet/lib/puppet/provider/user/aix.rb +142 -254
- data/vendored/puppet/lib/puppet/resource.rb +20 -3
- data/vendored/puppet/lib/puppet/resource/catalog.rb +2 -12
- data/vendored/puppet/lib/puppet/rest/routes.rb +97 -34
- data/vendored/puppet/lib/puppet/settings.rb +1 -1
- data/vendored/puppet/lib/puppet/settings/file_setting.rb +1 -1
- data/vendored/puppet/lib/puppet/ssl/base.rb +1 -9
- data/vendored/puppet/lib/puppet/ssl/certificate_request.rb +1 -13
- data/vendored/puppet/lib/puppet/ssl/certificate_request_attributes.rb +1 -1
- data/vendored/puppet/lib/puppet/ssl/host.rb +114 -232
- data/vendored/puppet/lib/puppet/ssl/key.rb +1 -5
- data/vendored/puppet/lib/puppet/ssl/oids.rb +1 -1
- data/vendored/puppet/lib/puppet/test/test_helper.rb +0 -4
- data/vendored/puppet/lib/puppet/transaction/event.rb +3 -7
- data/vendored/puppet/lib/puppet/transaction/persistence.rb +1 -1
- data/vendored/puppet/lib/puppet/type/exec.rb +18 -16
- data/vendored/puppet/lib/puppet/type/file.rb +3 -3
- data/vendored/puppet/lib/puppet/type/file/source.rb +20 -7
- data/vendored/puppet/lib/puppet/type/group.rb +3 -5
- data/vendored/puppet/lib/puppet/type/notify.rb +1 -1
- data/vendored/puppet/lib/puppet/type/package.rb +2 -5
- data/vendored/puppet/lib/puppet/type/schedule.rb +1 -1
- data/vendored/puppet/lib/puppet/type/service.rb +3 -6
- data/vendored/puppet/lib/puppet/type/tidy.rb +1 -1
- data/vendored/puppet/lib/puppet/type/user.rb +13 -20
- data/vendored/puppet/lib/puppet/util.rb +8 -9
- data/vendored/puppet/lib/puppet/util/execution.rb +3 -3
- data/vendored/puppet/lib/puppet/util/feature.rb +61 -39
- data/vendored/puppet/lib/puppet/util/log/destinations.rb +1 -1
- data/vendored/puppet/lib/puppet/util/rdoc.rb +1 -1
- data/vendored/puppet/lib/puppet/util/run_mode.rb +1 -1
- data/vendored/puppet/lib/puppet/util/storage.rb +1 -1
- data/vendored/puppet/lib/puppet/util/suidmanager.rb +7 -5
- data/vendored/puppet/lib/puppet/util/tag_set.rb +1 -1
- data/vendored/puppet/lib/puppet/util/tagging.rb +1 -1
- data/vendored/puppet/lib/puppet/util/windows.rb +18 -2
- data/vendored/puppet/lib/puppet/util/windows/adsi.rb +154 -205
- data/vendored/puppet/lib/puppet/util/windows/service.rb +770 -0
- data/vendored/puppet/lib/puppet/util/yaml.rb +41 -5
- data/vendored/puppet/lib/puppet/version.rb +1 -1
- data/vendored/puppet/lib/puppet_pal.rb +280 -24
- metadata +8 -38
- data/lib/bolt/catalog/compiler.rb +0 -48
- data/lib/bolt/catalog/loaders.rb +0 -19
- data/vendored/puppet/lib/puppet/application/ca.rb +0 -11
- data/vendored/puppet/lib/puppet/application/certificate.rb +0 -17
- data/vendored/puppet/lib/puppet/application/certificate_request.rb +0 -7
- data/vendored/puppet/lib/puppet/application/certificate_revocation_list.rb +0 -7
- data/vendored/puppet/lib/puppet/face/ca.rb +0 -266
- data/vendored/puppet/lib/puppet/face/certificate.rb +0 -167
- data/vendored/puppet/lib/puppet/face/certificate_request.rb +0 -56
- data/vendored/puppet/lib/puppet/face/certificate_revocation_list.rb +0 -56
- data/vendored/puppet/lib/puppet/graph/random_prioritizer.rb +0 -16
- data/vendored/puppet/lib/puppet/graph/title_hash_prioritizer.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/certificate/ca.rb +0 -9
- data/vendored/puppet/lib/puppet/indirector/certificate/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_request/ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_request/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/ca.rb +0 -8
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/file.rb +0 -8
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/rest.rb +0 -11
- data/vendored/puppet/lib/puppet/indirector/certificate_status.rb +0 -4
- data/vendored/puppet/lib/puppet/indirector/certificate_status/file.rb +0 -91
- data/vendored/puppet/lib/puppet/indirector/certificate_status/rest.rb +0 -11
- data/vendored/puppet/lib/puppet/indirector/key/ca.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/key/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/ldap.rb +0 -86
- data/vendored/puppet/lib/puppet/indirector/node/ldap.rb +0 -275
- data/vendored/puppet/lib/puppet/provider/aixobject.rb +0 -392
- data/vendored/puppet/lib/puppet/provider/cron/crontab.rb +0 -297
- data/vendored/puppet/lib/puppet/ssl/certificate_authority.rb +0 -475
- data/vendored/puppet/lib/puppet/ssl/certificate_authority/autosign_command.rb +0 -45
- data/vendored/puppet/lib/puppet/ssl/certificate_authority/interface.rb +0 -324
- data/vendored/puppet/lib/puppet/ssl/certificate_factory.rb +0 -219
- data/vendored/puppet/lib/puppet/ssl/certificate_revocation_list.rb +0 -111
- data/vendored/puppet/lib/puppet/ssl/inventory.rb +0 -55
- data/vendored/puppet/lib/puppet/type/cron.rb +0 -480
@@ -0,0 +1,770 @@
|
|
1
|
+
require 'puppet/util/windows'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module Puppet::Util::Windows
|
5
|
+
# This module is designed to provide an API between the windows system and puppet for
|
6
|
+
# service management.
|
7
|
+
#
|
8
|
+
# for an overview of the service state transitions see: https://docs.microsoft.com/en-us/windows/desktop/Services/service-status-transitions
|
9
|
+
module Service
|
10
|
+
extend FFI::Library
|
11
|
+
extend Puppet::Util::Windows::String
|
12
|
+
|
13
|
+
FILE = Puppet::Util::Windows::File
|
14
|
+
|
15
|
+
# integer value of the floor for timeouts when waiting for service pending states.
|
16
|
+
# puppet will wait the length of dwWaitHint if it is longer than this value, but
|
17
|
+
# no shorter
|
18
|
+
DEFAULT_TIMEOUT = 30
|
19
|
+
|
20
|
+
# Service control codes
|
21
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-controlserviceexw
|
22
|
+
SERVICE_CONTROL_STOP = 0x00000001
|
23
|
+
SERVICE_CONTROL_PAUSE = 0x00000002
|
24
|
+
SERVICE_CONTROL_CONTINUE = 0x00000003
|
25
|
+
SERVICE_CONTROL_INTERROGATE = 0x00000004
|
26
|
+
SERVICE_CONTROL_SHUTDOWN = 0x00000005
|
27
|
+
SERVICE_CONTROL_PARAMCHANGE = 0x00000006
|
28
|
+
SERVICE_CONTROL_NETBINDADD = 0x00000007
|
29
|
+
SERVICE_CONTROL_NETBINDREMOVE = 0x00000008
|
30
|
+
SERVICE_CONTROL_NETBINDENABLE = 0x00000009
|
31
|
+
SERVICE_CONTROL_NETBINDDISABLE = 0x0000000A
|
32
|
+
SERVICE_CONTROL_DEVICEEVENT = 0x0000000B
|
33
|
+
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 0x0000000C
|
34
|
+
SERVICE_CONTROL_POWEREVENT = 0x0000000D
|
35
|
+
SERVICE_CONTROL_SESSIONCHANGE = 0x0000000E
|
36
|
+
SERVICE_CONTROL_PRESHUTDOWN = 0x0000000F
|
37
|
+
SERVICE_CONTROL_TIMECHANGE = 0x00000010
|
38
|
+
SERVICE_CONTROL_TRIGGEREVENT = 0x00000020
|
39
|
+
|
40
|
+
# Service start type codes
|
41
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-changeserviceconfigw
|
42
|
+
SERVICE_AUTO_START = 0x00000002
|
43
|
+
SERVICE_BOOT_START = 0x00000000
|
44
|
+
SERVICE_DEMAND_START = 0x00000003
|
45
|
+
SERVICE_DISABLED = 0x00000004
|
46
|
+
SERVICE_SYSTEM_START = 0x00000001
|
47
|
+
SERVICE_START_TYPES = {
|
48
|
+
SERVICE_AUTO_START => :SERVICE_AUTO_START,
|
49
|
+
SERVICE_BOOT_START => :SERVICE_BOOT_START,
|
50
|
+
SERVICE_DEMAND_START => :SERVICE_DEMAND_START,
|
51
|
+
SERVICE_DISABLED => :SERVICE_DISABLED,
|
52
|
+
SERVICE_SYSTEM_START => :SERVICE_SYSTEM_START,
|
53
|
+
}
|
54
|
+
|
55
|
+
# Service type codes
|
56
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-changeserviceconfigw
|
57
|
+
SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
|
58
|
+
SERVICE_KERNEL_DRIVER = 0x00000001
|
59
|
+
SERVICE_WIN32_OWN_PROCESS = 0x00000010
|
60
|
+
SERVICE_WIN32_SHARE_PROCESS = 0x00000020
|
61
|
+
SERVICE_USER_OWN_PROCESS = 0x00000050
|
62
|
+
SERVICE_USER_SHARE_PROCESS = 0x00000060
|
63
|
+
# Available only if service is also SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS
|
64
|
+
SERVICE_INTERACTIVE_PROCESS = 0x00000100
|
65
|
+
ALL_SERVICE_TYPES =
|
66
|
+
SERVICE_FILE_SYSTEM_DRIVER |
|
67
|
+
SERVICE_KERNEL_DRIVER |
|
68
|
+
SERVICE_WIN32_OWN_PROCESS |
|
69
|
+
SERVICE_WIN32_SHARE_PROCESS
|
70
|
+
|
71
|
+
# Current state codes
|
72
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_status_process
|
73
|
+
SERVICE_CONTINUE_PENDING = 0x00000005
|
74
|
+
SERVICE_PAUSE_PENDING = 0x00000006
|
75
|
+
SERVICE_PAUSED = 0x00000007
|
76
|
+
SERVICE_RUNNING = 0x00000004
|
77
|
+
SERVICE_START_PENDING = 0x00000002
|
78
|
+
SERVICE_STOP_PENDING = 0x00000003
|
79
|
+
SERVICE_STOPPED = 0x00000001
|
80
|
+
SERVICE_STATES = {
|
81
|
+
SERVICE_CONTINUE_PENDING => :SERVICE_CONTINUE_PENDING,
|
82
|
+
SERVICE_PAUSE_PENDING => :SERVICE_PAUSE_PENDING,
|
83
|
+
SERVICE_PAUSED => :SERVICE_PAUSED,
|
84
|
+
SERVICE_RUNNING => :SERVICE_RUNNING,
|
85
|
+
SERVICE_START_PENDING => :SERVICE_START_PENDING,
|
86
|
+
SERVICE_STOP_PENDING => :SERVICE_STOP_PENDING,
|
87
|
+
SERVICE_STOPPED => :SERVICE_STOPPED,
|
88
|
+
}
|
89
|
+
|
90
|
+
# Service accepts control codes
|
91
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_status_process
|
92
|
+
SERVICE_ACCEPT_STOP = 0x00000001
|
93
|
+
SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
|
94
|
+
SERVICE_ACCEPT_SHUTDOWN = 0x00000004
|
95
|
+
SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
|
96
|
+
SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
|
97
|
+
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
|
98
|
+
SERVICE_ACCEPT_POWEREVENT = 0x00000040
|
99
|
+
SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
|
100
|
+
SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
|
101
|
+
SERVICE_ACCEPT_TIMECHANGE = 0x00000200
|
102
|
+
SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
|
103
|
+
SERVICE_ACCEPT_USER_LOGOFF = 0x00000800
|
104
|
+
|
105
|
+
# Service manager access codes
|
106
|
+
# https://docs.microsoft.com/en-us/windows/desktop/Services/service-security-and-access-rights
|
107
|
+
SC_MANAGER_CREATE_SERVICE = 0x00000002
|
108
|
+
SC_MANAGER_CONNECT = 0x00000001
|
109
|
+
SC_MANAGER_ENUMERATE_SERVICE = 0x00000004
|
110
|
+
SC_MANAGER_LOCK = 0x00000008
|
111
|
+
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00000020
|
112
|
+
SC_MANAGER_QUERY_LOCK_STATUS = 0x00000010
|
113
|
+
SC_MANAGER_ALL_ACCESS =
|
114
|
+
FILE::STANDARD_RIGHTS_REQUIRED |
|
115
|
+
SC_MANAGER_CREATE_SERVICE |
|
116
|
+
SC_MANAGER_CONNECT |
|
117
|
+
SC_MANAGER_ENUMERATE_SERVICE |
|
118
|
+
SC_MANAGER_LOCK |
|
119
|
+
SC_MANAGER_MODIFY_BOOT_CONFIG |
|
120
|
+
SC_MANAGER_QUERY_LOCK_STATUS
|
121
|
+
|
122
|
+
|
123
|
+
# Service access codes
|
124
|
+
# https://docs.microsoft.com/en-us/windows/desktop/Services/service-security-and-access-rights
|
125
|
+
SERVICE_CHANGE_CONFIG = 0x0002
|
126
|
+
SERVICE_ENUMERATE_DEPENDENTS = 0x0008
|
127
|
+
SERVICE_INTERROGATE = 0x0080
|
128
|
+
SERVICE_PAUSE_CONTINUE = 0x0040
|
129
|
+
SERVICE_QUERY_STATUS = 0x0004
|
130
|
+
SERVICE_QUERY_CONFIG = 0x0001
|
131
|
+
SERVICE_START = 0x0010
|
132
|
+
SERVICE_STOP = 0x0020
|
133
|
+
SERVICE_USER_DEFINED_CONTROL = 0x0100
|
134
|
+
SERVICE_ALL_ACCESS =
|
135
|
+
FILE::STANDARD_RIGHTS_REQUIRED |
|
136
|
+
SERVICE_CHANGE_CONFIG |
|
137
|
+
SERVICE_ENUMERATE_DEPENDENTS |
|
138
|
+
SERVICE_INTERROGATE |
|
139
|
+
SERVICE_PAUSE_CONTINUE |
|
140
|
+
SERVICE_QUERY_STATUS |
|
141
|
+
SERVICE_QUERY_CONFIG |
|
142
|
+
SERVICE_START |
|
143
|
+
SERVICE_STOP |
|
144
|
+
SERVICE_USER_DEFINED_CONTROL
|
145
|
+
|
146
|
+
# Service config codes
|
147
|
+
# From the windows 10 SDK:
|
148
|
+
# //
|
149
|
+
# // Value to indicate no change to an optional parameter
|
150
|
+
# //
|
151
|
+
# #define SERVICE_NO_CHANGE 0xffffffff
|
152
|
+
SERVICE_NO_CHANGE = 0xffffffff
|
153
|
+
|
154
|
+
# Service enum codes
|
155
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexa
|
156
|
+
SERVICE_ACTIVE = 0x00000001
|
157
|
+
SERVICE_INACTIVE = 0x00000002
|
158
|
+
SERVICE_STATE_ALL =
|
159
|
+
SERVICE_ACTIVE |
|
160
|
+
SERVICE_INACTIVE
|
161
|
+
|
162
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_enum_service_status_processw
|
163
|
+
SERVICENAME_MAX = 256
|
164
|
+
|
165
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_service_status_process
|
166
|
+
# typedef struct _SERVICE_STATUS_PROCESS {
|
167
|
+
# DWORD dwServiceType;
|
168
|
+
# DWORD dwCurrentState;
|
169
|
+
# DWORD dwControlsAccepted;
|
170
|
+
# DWORD dwWin32ExitCode;
|
171
|
+
# DWORD dwServiceSpecificExitCode;
|
172
|
+
# DWORD dwCheckPoint;
|
173
|
+
# DWORD dwWaitHint;
|
174
|
+
# DWORD dwProcessId;
|
175
|
+
# DWORD dwServiceFlags;
|
176
|
+
# } SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;
|
177
|
+
class SERVICE_STATUS_PROCESS < FFI::Struct
|
178
|
+
layout(
|
179
|
+
:dwServiceType, :dword,
|
180
|
+
:dwCurrentState, :dword,
|
181
|
+
:dwControlsAccepted, :dword,
|
182
|
+
:dwWin32ExitCode, :dword,
|
183
|
+
:dwServiceSpecificExitCode, :dword,
|
184
|
+
:dwCheckPoint, :dword,
|
185
|
+
:dwWaitHint, :dword,
|
186
|
+
:dwProcessId, :dword,
|
187
|
+
:dwServiceFlags, :dword
|
188
|
+
)
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/ns-winsvc-_enum_service_status_processw
|
193
|
+
# typedef struct _ENUM_SERVICE_STATUS_PROCESSW {
|
194
|
+
# LPWSTR lpServiceName;
|
195
|
+
# LPWSTR lpDisplayName;
|
196
|
+
# SERVICE_STATUS_PROCESS ServiceStatusProcess;
|
197
|
+
# } ENUM_SERVICE_STATUS_PROCESSW, *LPENUM_SERVICE_STATUS_PROCESSW;
|
198
|
+
class ENUM_SERVICE_STATUS_PROCESSW < FFI::Struct
|
199
|
+
layout(
|
200
|
+
:lpServiceName, :pointer,
|
201
|
+
:lpDisplayName, :pointer,
|
202
|
+
:ServiceStatusProcess, SERVICE_STATUS_PROCESS
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
# typedef struct _SERVICE_STATUS {
|
207
|
+
# DWORD dwServiceType;
|
208
|
+
# DWORD dwCurrentState;
|
209
|
+
# DWORD dwControlsAccepted;
|
210
|
+
# DWORD dwWin32ExitCode;
|
211
|
+
# DWORD dwServiceSpecificExitCode;
|
212
|
+
# DWORD dwCheckPoint;
|
213
|
+
# DWORD dwWaitHint;
|
214
|
+
# } SERVICE_STATUS, *LPSERVICE_STATUS;
|
215
|
+
class SERVICE_STATUS < FFI::Struct
|
216
|
+
layout(
|
217
|
+
:dwServiceType, :dword,
|
218
|
+
:dwCurrentState, :dword,
|
219
|
+
:dwControlsAccepted, :dword,
|
220
|
+
:dwWin32ExitCode, :dword,
|
221
|
+
:dwServiceSpecificExitCode, :dword,
|
222
|
+
:dwCheckPoint, :dword,
|
223
|
+
:dwWaitHint, :dword,
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
# typedef struct _QUERY_SERVICE_CONFIGW {
|
228
|
+
# DWORD dwServiceType;
|
229
|
+
# DWORD dwStartType;
|
230
|
+
# DWORD dwErrorControl;
|
231
|
+
# LPWSTR lpBinaryPathName;
|
232
|
+
# LPWSTR lpLoadOrderGroup;
|
233
|
+
# DWORD dwTagId;
|
234
|
+
# LPWSTR lpDependencies;
|
235
|
+
# LPWSTR lpServiceStartName;
|
236
|
+
# LPWSTR lpDisplayName;
|
237
|
+
# } QUERY_SERVICE_CONFIGW, *LPQUERY_SERVICE_CONFIGW;
|
238
|
+
class QUERY_SERVICE_CONFIGW < FFI::Struct
|
239
|
+
layout(
|
240
|
+
:dwServiceType, :dword,
|
241
|
+
:dwStartType, :dword,
|
242
|
+
:dwErrorControl, :dword,
|
243
|
+
:lpBinaryPathName, :pointer,
|
244
|
+
:lpLoadOrderGroup, :pointer,
|
245
|
+
:dwTagId, :dword,
|
246
|
+
:lpDependencies, :pointer,
|
247
|
+
:lpServiceStartName, :pointer,
|
248
|
+
:lpDisplayName, :pointer,
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Start a windows service, assume that the service is already in the stopped state
|
253
|
+
#
|
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)
|
261
|
+
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"))
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
module_function :start
|
270
|
+
|
271
|
+
# Use ControlService to send a stop signal to a windows service
|
272
|
+
#
|
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
|
289
|
+
end
|
290
|
+
end
|
291
|
+
module_function :stop
|
292
|
+
|
293
|
+
# Query the state of a service using QueryServiceStatusEx
|
294
|
+
#
|
295
|
+
# @param [:string] service_name name of the service to query
|
296
|
+
# @return [string] the status of the service
|
297
|
+
def service_state(service_name)
|
298
|
+
status = nil
|
299
|
+
open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_STATUS) do |service|
|
300
|
+
status = query_status(service)
|
301
|
+
end
|
302
|
+
state = SERVICE_STATES[status[:dwCurrentState]]
|
303
|
+
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})
|
305
|
+
end
|
306
|
+
state
|
307
|
+
end
|
308
|
+
module_function :service_state
|
309
|
+
|
310
|
+
# Query the configuration of a service using QueryServiceConfigW
|
311
|
+
#
|
312
|
+
# @param [:string] service_name name of the service to query
|
313
|
+
# @return [QUERY_SERVICE_CONFIGW.struct] the configuration of the service
|
314
|
+
def service_start_type(service_name)
|
315
|
+
config = nil
|
316
|
+
open_service(service_name, SC_MANAGER_CONNECT, SERVICE_QUERY_CONFIG) do |service|
|
317
|
+
config = query_config(service)
|
318
|
+
end
|
319
|
+
start_type = SERVICE_START_TYPES[config[:dwStartType]]
|
320
|
+
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})
|
322
|
+
end
|
323
|
+
start_type
|
324
|
+
end
|
325
|
+
module_function :service_start_type
|
326
|
+
|
327
|
+
# Change the startup mode of a windows service
|
328
|
+
#
|
329
|
+
# @param [string] service_name the name of the service to modify
|
330
|
+
# @param [Int] startup_type a code corresponding to a start type for
|
331
|
+
# windows service, see the "Service start type codes" section in the
|
332
|
+
# Puppet::Util::Windows::Service file for the list of available codes
|
333
|
+
def set_startup_mode(service_name, startup_type)
|
334
|
+
startup_code = SERVICE_START_TYPES.key(startup_type)
|
335
|
+
if startup_code.nil?
|
336
|
+
raise Puppet::Error.new(_("Unknown start type %{start_type}") % {startup_type: startup_type.to_s})
|
337
|
+
end
|
338
|
+
open_service(service_name, SC_MANAGER_CONNECT, SERVICE_CHANGE_CONFIG) do |service|
|
339
|
+
# Currently the only thing puppet's API can really manage
|
340
|
+
# in this list is dwStartType (the third param). Thus no
|
341
|
+
# generic function was written to make use of all the params
|
342
|
+
# since the API as-is couldn't use them anyway
|
343
|
+
success = ChangeServiceConfigW(
|
344
|
+
service,
|
345
|
+
SERVICE_NO_CHANGE, # dwServiceType
|
346
|
+
startup_code, # dwStartType
|
347
|
+
SERVICE_NO_CHANGE, # dwErrorControl
|
348
|
+
FFI::Pointer::NULL, # lpBinaryPathName
|
349
|
+
FFI::Pointer::NULL, # lpLoadOrderGroup
|
350
|
+
FFI::Pointer::NULL, # lpdwTagId
|
351
|
+
FFI::Pointer::NULL, # lpDependencies
|
352
|
+
FFI::Pointer::NULL, # lpServiceStartName
|
353
|
+
FFI::Pointer::NULL, # lpPassword
|
354
|
+
FFI::Pointer::NULL # lpDisplayName
|
355
|
+
)
|
356
|
+
if success == FFI::WIN32_FALSE
|
357
|
+
raise Puppet::Util::Windows::Error.new(_("Failed to update service configuration"))
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
module_function :set_startup_mode
|
362
|
+
|
363
|
+
# enumerate over all services in all states and return them as a hash
|
364
|
+
#
|
365
|
+
# @return [Hash] a hash containing services:
|
366
|
+
# { 'service name' => {
|
367
|
+
# 'display_name' => 'display name',
|
368
|
+
# 'service_status_process' => SERVICE_STATUS_PROCESS struct
|
369
|
+
# }
|
370
|
+
# }
|
371
|
+
def services
|
372
|
+
services = {}
|
373
|
+
open_scm(SC_MANAGER_ENUMERATE_SERVICE) do |scm|
|
374
|
+
size_required = 0
|
375
|
+
services_returned = 0
|
376
|
+
FFI::MemoryPointer.new(:dword) do |bytes_pointer|
|
377
|
+
FFI::MemoryPointer.new(:dword) do |svcs_ret_ptr|
|
378
|
+
FFI::MemoryPointer.new(:dword) do |resume_ptr|
|
379
|
+
resume_ptr.write_dword(0)
|
380
|
+
# Fetch the bytes of memory required to be allocated
|
381
|
+
# for QueryServiceConfigW to return succesfully. This
|
382
|
+
# is done by sending NULL and 0 for the pointer and size
|
383
|
+
# respectively, letting the command fail, then reading the
|
384
|
+
# value of pcbBytesNeeded
|
385
|
+
#
|
386
|
+
# return value will be false from this call, since it's designed
|
387
|
+
# to fail. Just ignore it
|
388
|
+
EnumServicesStatusExW(
|
389
|
+
scm,
|
390
|
+
:SC_ENUM_PROCESS_INFO,
|
391
|
+
ALL_SERVICE_TYPES,
|
392
|
+
SERVICE_STATE_ALL,
|
393
|
+
FFI::Pointer::NULL,
|
394
|
+
0,
|
395
|
+
bytes_pointer,
|
396
|
+
svcs_ret_ptr,
|
397
|
+
resume_ptr,
|
398
|
+
FFI::Pointer::NULL
|
399
|
+
)
|
400
|
+
size_required = bytes_pointer.read_dword
|
401
|
+
FFI::MemoryPointer.new(size_required) do |buffer_ptr|
|
402
|
+
resume_ptr.write_dword(0)
|
403
|
+
svcs_ret_ptr.write_dword(0)
|
404
|
+
success = EnumServicesStatusExW(
|
405
|
+
scm,
|
406
|
+
:SC_ENUM_PROCESS_INFO,
|
407
|
+
ALL_SERVICE_TYPES,
|
408
|
+
SERVICE_STATE_ALL,
|
409
|
+
buffer_ptr,
|
410
|
+
buffer_ptr.size,
|
411
|
+
bytes_pointer,
|
412
|
+
svcs_ret_ptr,
|
413
|
+
resume_ptr,
|
414
|
+
FFI::Pointer::NULL
|
415
|
+
)
|
416
|
+
if success == FFI::WIN32_FALSE
|
417
|
+
raise Puppet::Util::Windows::Error.new(_("Failed to fetch services"))
|
418
|
+
end
|
419
|
+
# Now that the buffer is populated with services
|
420
|
+
# we pull the data from memory using pointer arithmetic:
|
421
|
+
# the number of services returned by the function is
|
422
|
+
# available to be read from svcs_ret_ptr, and we iterate
|
423
|
+
# that many times moving the cursor pointer the length of
|
424
|
+
# ENUM_SERVICE_STATUS_PROCESSW.size. This should iterate
|
425
|
+
# over the buffer and extract each struct.
|
426
|
+
services_returned = svcs_ret_ptr.read_dword
|
427
|
+
cursor_ptr = FFI::Pointer.new(ENUM_SERVICE_STATUS_PROCESSW, buffer_ptr)
|
428
|
+
0.upto(services_returned - 1) do |index|
|
429
|
+
service = ENUM_SERVICE_STATUS_PROCESSW.new(cursor_ptr[index])
|
430
|
+
services[service[:lpServiceName].read_arbitrary_wide_string_up_to(SERVICENAME_MAX)] = {
|
431
|
+
:display_name => service[:lpDisplayName].read_arbitrary_wide_string_up_to(SERVICENAME_MAX),
|
432
|
+
:service_status_process => service[:ServiceStatusProcess]
|
433
|
+
}
|
434
|
+
end
|
435
|
+
end # buffer_ptr
|
436
|
+
end # resume_ptr
|
437
|
+
end # scvs_ret_ptr
|
438
|
+
end # bytes_ptr
|
439
|
+
end # open_scm
|
440
|
+
services
|
441
|
+
end
|
442
|
+
module_function :services
|
443
|
+
|
444
|
+
class << self
|
445
|
+
# @api private
|
446
|
+
# Opens a connection to the SCManager on windows then uses that
|
447
|
+
# handle to create a handle to a specific service in windows
|
448
|
+
# corresponding to service_name
|
449
|
+
#
|
450
|
+
# this function takes a block that executes within the context of
|
451
|
+
# the open service handler, and will close the service and SCManager
|
452
|
+
# handles once the block finishes
|
453
|
+
#
|
454
|
+
# @param [string] service_name the name of the service to open
|
455
|
+
# @param [Integer] scm_access code corresponding to the access type requested for the scm
|
456
|
+
# @param [Integer] service_access code corresponding to the access type requested for the service
|
457
|
+
# @yieldparam [:handle] service the windows native handle used to access
|
458
|
+
# the service
|
459
|
+
def open_service(service_name, scm_access, service_access, &block)
|
460
|
+
service = FFI::Pointer::NULL_HANDLE
|
461
|
+
open_scm(scm_access) do |scm|
|
462
|
+
service = OpenServiceW(scm, wide_string(service_name), service_access)
|
463
|
+
raise Puppet::Util::Windows::Error.new(_("Failed to open a handle to the service")) if service == FFI::Pointer::NULL_HANDLE
|
464
|
+
yield service
|
465
|
+
end
|
466
|
+
ensure
|
467
|
+
CloseServiceHandle(service)
|
468
|
+
end
|
469
|
+
private :open_service
|
470
|
+
|
471
|
+
# @api private
|
472
|
+
#
|
473
|
+
# Opens a handle to the service control manager
|
474
|
+
#
|
475
|
+
# @param [Integer] scm_access code corresponding to the access type requested for the scm
|
476
|
+
def open_scm(scm_access, &block)
|
477
|
+
scm = OpenSCManagerW(FFI::Pointer::NULL, FFI::Pointer::NULL, scm_access)
|
478
|
+
raise Puppet::Util::Windows::Error.new(_("Failed to open a handle to the service control manager")) if scm == FFI::Pointer::NULL_HANDLE
|
479
|
+
yield scm
|
480
|
+
ensure
|
481
|
+
CloseServiceHandle(scm)
|
482
|
+
end
|
483
|
+
private :open_scm
|
484
|
+
|
485
|
+
# @api private
|
486
|
+
# perform QueryServiceStatusEx on a windows service and return the
|
487
|
+
# result
|
488
|
+
#
|
489
|
+
# @param [:handle] service handle of the service to query
|
490
|
+
# @return [SERVICE_STATUS_PROCESS struct] the result of the query
|
491
|
+
def query_status(service)
|
492
|
+
size_required = nil
|
493
|
+
status = nil
|
494
|
+
# Fetch the bytes of memory required to be allocated
|
495
|
+
# for QueryServiceConfigW to return succesfully. This
|
496
|
+
# is done by sending NULL and 0 for the pointer and size
|
497
|
+
# respectively, letting the command fail, then reading the
|
498
|
+
# value of pcbBytesNeeded
|
499
|
+
FFI::MemoryPointer.new(:lpword) do |bytes_pointer|
|
500
|
+
# return value will be false from this call, since it's designed
|
501
|
+
# to fail. Just ignore it
|
502
|
+
QueryServiceStatusEx(
|
503
|
+
service,
|
504
|
+
:SC_STATUS_PROCESS_INFO,
|
505
|
+
FFI::Pointer::NULL,
|
506
|
+
0,
|
507
|
+
bytes_pointer
|
508
|
+
)
|
509
|
+
size_required = bytes_pointer.read_dword
|
510
|
+
FFI::MemoryPointer.new(size_required) do |ssp_ptr|
|
511
|
+
status = SERVICE_STATUS_PROCESS.new(ssp_ptr)
|
512
|
+
success = QueryServiceStatusEx(
|
513
|
+
service,
|
514
|
+
:SC_STATUS_PROCESS_INFO,
|
515
|
+
ssp_ptr,
|
516
|
+
size_required,
|
517
|
+
bytes_pointer
|
518
|
+
)
|
519
|
+
if success == FFI::WIN32_FALSE
|
520
|
+
raise Puppet::Util::Windows::Error.new(_("Service query failed"))
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
status
|
525
|
+
end
|
526
|
+
private :query_status
|
527
|
+
|
528
|
+
# @api private
|
529
|
+
# perform QueryServiceConfigW on a windows service and return the
|
530
|
+
# result
|
531
|
+
#
|
532
|
+
# @param [:handle] service handle of the service to query
|
533
|
+
# @return [QUERY_SERVICE_CONFIGW struct] the result of the query
|
534
|
+
def query_config(service)
|
535
|
+
config = nil
|
536
|
+
size_required = nil
|
537
|
+
# Fetch the bytes of memory required to be allocated
|
538
|
+
# for QueryServiceConfigW to return succesfully. This
|
539
|
+
# is done by sending NULL and 0 for the pointer and size
|
540
|
+
# respectively, letting the command fail, then reading the
|
541
|
+
# value of pcbBytesNeeded
|
542
|
+
FFI::MemoryPointer.new(:lpword) do |bytes_pointer|
|
543
|
+
# return value will be false from this call, since it's designed
|
544
|
+
# to fail. Just ignore it
|
545
|
+
QueryServiceConfigW(service, FFI::Pointer::NULL, 0, bytes_pointer)
|
546
|
+
size_required = bytes_pointer.read_dword
|
547
|
+
FFI::MemoryPointer.new(size_required) do |ssp_ptr|
|
548
|
+
config = QUERY_SERVICE_CONFIGW.new(ssp_ptr)
|
549
|
+
success = QueryServiceConfigW(
|
550
|
+
service,
|
551
|
+
ssp_ptr,
|
552
|
+
size_required,
|
553
|
+
bytes_pointer
|
554
|
+
)
|
555
|
+
if success == FFI::WIN32_FALSE
|
556
|
+
raise Puppet::Util::Windows::Error.new(_("Service query failed"))
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
config
|
561
|
+
end
|
562
|
+
private :query_config
|
563
|
+
|
564
|
+
# @api private
|
565
|
+
# waits for a windows service to report final_state if it
|
566
|
+
# is in pending_state
|
567
|
+
#
|
568
|
+
# @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)
|
574
|
+
elapsed_time = 0
|
575
|
+
last_checkpoint = -1
|
576
|
+
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"))
|
596
|
+
end
|
597
|
+
end
|
598
|
+
last_checkpoint = status[:dwCheckPoint]
|
599
|
+
sleep(time_to_wait)
|
600
|
+
elapsed_time += time_to_wait
|
601
|
+
end
|
602
|
+
end
|
603
|
+
private :wait_for_pending_transition
|
604
|
+
|
605
|
+
# @api private
|
606
|
+
#
|
607
|
+
# create a usable wait time to wait between querying the service.
|
608
|
+
#
|
609
|
+
# @param [Integer] wait_hint the wait hint of a service in milliseconds
|
610
|
+
# @return [Integer] the time to wait in seconds between querying the service
|
611
|
+
def wait_hint_to_wait_time(wait_hint)
|
612
|
+
# Wait 1/10th the wait_hint, but no less than 1 and
|
613
|
+
# no more than 10 seconds
|
614
|
+
wait_time = milliseconds_to_seconds(wait_hint) / 10;
|
615
|
+
wait_time = 1 if wait_time < 1
|
616
|
+
wait_time = 10 if wait_time > 10
|
617
|
+
wait_time
|
618
|
+
end
|
619
|
+
private :wait_hint_to_wait_time
|
620
|
+
|
621
|
+
# @api private
|
622
|
+
#
|
623
|
+
# process the wait hint listed by a service to something
|
624
|
+
# usable by ruby sleep
|
625
|
+
#
|
626
|
+
# @param [Integer] wait_hint the wait hint of a service in milliseconds
|
627
|
+
# @return [Integer] wait_hint in seconds
|
628
|
+
def milliseconds_to_seconds(wait_hint)
|
629
|
+
wait_hint / 1000;
|
630
|
+
end
|
631
|
+
private :milliseconds_to_seconds
|
632
|
+
end
|
633
|
+
|
634
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-openscmanagerw
|
635
|
+
# SC_HANDLE OpenSCManagerW(
|
636
|
+
# LPCWSTR lpMachineName,
|
637
|
+
# LPCWSTR lpDatabaseName,
|
638
|
+
# DWORD dwDesiredAccess
|
639
|
+
# );
|
640
|
+
ffi_lib :advapi32
|
641
|
+
attach_function_private :OpenSCManagerW,
|
642
|
+
[:lpcwstr, :lpcwstr, :dword], :handle
|
643
|
+
|
644
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-openservicew
|
645
|
+
# SC_HANDLE OpenServiceW(
|
646
|
+
# SC_HANDLE hSCManager,
|
647
|
+
# LPCWSTR lpServiceName,
|
648
|
+
# DWORD dwDesiredAccess
|
649
|
+
# );
|
650
|
+
ffi_lib :advapi32
|
651
|
+
attach_function_private :OpenServiceW,
|
652
|
+
[:handle, :lpcwstr, :dword], :handle
|
653
|
+
|
654
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-closeservicehandle
|
655
|
+
# BOOL CloseServiceHandle(
|
656
|
+
# SC_HANDLE hSCObject
|
657
|
+
# );
|
658
|
+
ffi_lib :advapi32
|
659
|
+
attach_function_private :CloseServiceHandle,
|
660
|
+
[:handle], :win32_bool
|
661
|
+
|
662
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-queryservicestatusex
|
663
|
+
# BOOL QueryServiceStatusEx(
|
664
|
+
# SC_HANDLE hService,
|
665
|
+
# SC_STATUS_TYPE InfoLevel,
|
666
|
+
# LPBYTE lpBuffer,
|
667
|
+
# DWORD cbBufSize,
|
668
|
+
# LPDWORD pcbBytesNeeded
|
669
|
+
# );
|
670
|
+
SC_STATUS_TYPE = enum(
|
671
|
+
:SC_STATUS_PROCESS_INFO, 0,
|
672
|
+
)
|
673
|
+
ffi_lib :advapi32
|
674
|
+
attach_function_private :QueryServiceStatusEx,
|
675
|
+
[:handle, SC_STATUS_TYPE, :lpbyte, :dword, :lpdword], :win32_bool
|
676
|
+
|
677
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-queryserviceconfigw
|
678
|
+
# BOOL QueryServiceConfigW(
|
679
|
+
# SC_HANDLE hService,
|
680
|
+
# LPQUERY_SERVICE_CONFIGW lpServiceConfig,
|
681
|
+
# DWORD cbBufSize,
|
682
|
+
# LPDWORD pcbBytesNeeded
|
683
|
+
# );
|
684
|
+
ffi_lib :advapi32
|
685
|
+
attach_function_private :QueryServiceConfigW,
|
686
|
+
[:handle, :lpbyte, :dword, :lpdword], :win32_bool
|
687
|
+
|
688
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/Winsvc/nf-winsvc-startservicew
|
689
|
+
# BOOL StartServiceW(
|
690
|
+
# SC_HANDLE hService,
|
691
|
+
# DWORD dwNumServiceArgs,
|
692
|
+
# LPCWSTR *lpServiceArgVectors
|
693
|
+
# );
|
694
|
+
ffi_lib :advapi32
|
695
|
+
attach_function_private :StartServiceW,
|
696
|
+
[:handle, :dword, :pointer], :win32_bool
|
697
|
+
|
698
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-controlservice
|
699
|
+
# BOOL ControlService(
|
700
|
+
# SC_HANDLE hService,
|
701
|
+
# DWORD dwControl,
|
702
|
+
# LPSERVICE_STATUS lpServiceStatus
|
703
|
+
# );
|
704
|
+
ffi_lib :advapi32
|
705
|
+
attach_function_private :ControlService,
|
706
|
+
[:handle, :dword, :pointer], :win32_bool
|
707
|
+
|
708
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-changeserviceconfigw
|
709
|
+
# BOOL ChangeServiceConfigW(
|
710
|
+
# SC_HANDLE hService,
|
711
|
+
# DWORD dwServiceType,
|
712
|
+
# DWORD dwStartType,
|
713
|
+
# DWORD dwErrorControl,
|
714
|
+
# LPCWSTR lpBinaryPathName,
|
715
|
+
# LPCWSTR lpLoadOrderGroup,
|
716
|
+
# LPDWORD lpdwTagId,
|
717
|
+
# LPCWSTR lpDependencies,
|
718
|
+
# LPCWSTR lpServiceStartName,
|
719
|
+
# LPCWSTR lpPassword,
|
720
|
+
# LPCWSTR lpDisplayName
|
721
|
+
# );
|
722
|
+
ffi_lib :advapi32
|
723
|
+
attach_function_private :ChangeServiceConfigW,
|
724
|
+
[
|
725
|
+
:handle,
|
726
|
+
:dword,
|
727
|
+
:dword,
|
728
|
+
:dword,
|
729
|
+
:lpcwstr,
|
730
|
+
:lpcwstr,
|
731
|
+
:lpdword,
|
732
|
+
:lpcwstr,
|
733
|
+
:lpcwstr,
|
734
|
+
:lpcwstr,
|
735
|
+
:lpcwstr
|
736
|
+
], :win32_bool
|
737
|
+
|
738
|
+
|
739
|
+
# https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexw
|
740
|
+
# BOOL EnumServicesStatusExW(
|
741
|
+
# SC_HANDLE hSCManager,
|
742
|
+
# SC_ENUM_TYPE InfoLevel,
|
743
|
+
# DWORD dwServiceType,
|
744
|
+
# DWORD dwServiceState,
|
745
|
+
# LPBYTE lpServices,
|
746
|
+
# DWORD cbBufSize,
|
747
|
+
# LPDWORD pcbBytesNeeded,
|
748
|
+
# LPDWORD lpServicesReturned,
|
749
|
+
# LPDWORD lpResumeHandle,
|
750
|
+
# LPCWSTR pszGroupName
|
751
|
+
# );
|
752
|
+
SC_ENUM_TYPE = enum(
|
753
|
+
:SC_ENUM_PROCESS_INFO, 0,
|
754
|
+
)
|
755
|
+
ffi_lib :advapi32
|
756
|
+
attach_function_private :EnumServicesStatusExW,
|
757
|
+
[
|
758
|
+
:handle,
|
759
|
+
SC_ENUM_TYPE,
|
760
|
+
:dword,
|
761
|
+
:dword,
|
762
|
+
:lpbyte,
|
763
|
+
:dword,
|
764
|
+
:lpdword,
|
765
|
+
:lpdword,
|
766
|
+
:lpdword,
|
767
|
+
:lpcwstr
|
768
|
+
], :win32_bool
|
769
|
+
end
|
770
|
+
end
|