right_agent 2.0.7-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +82 -0
  3. data/Rakefile +113 -0
  4. data/lib/right_agent.rb +59 -0
  5. data/lib/right_agent/actor.rb +182 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +232 -0
  8. data/lib/right_agent/agent.rb +1149 -0
  9. data/lib/right_agent/agent_config.rb +480 -0
  10. data/lib/right_agent/agent_identity.rb +210 -0
  11. data/lib/right_agent/agent_tag_manager.rb +237 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/clients.rb +31 -0
  14. data/lib/right_agent/clients/api_client.rb +383 -0
  15. data/lib/right_agent/clients/auth_client.rb +247 -0
  16. data/lib/right_agent/clients/balanced_http_client.rb +369 -0
  17. data/lib/right_agent/clients/base_retry_client.rb +495 -0
  18. data/lib/right_agent/clients/right_http_client.rb +279 -0
  19. data/lib/right_agent/clients/router_client.rb +493 -0
  20. data/lib/right_agent/command.rb +30 -0
  21. data/lib/right_agent/command/agent_manager_commands.rb +150 -0
  22. data/lib/right_agent/command/command_client.rb +136 -0
  23. data/lib/right_agent/command/command_constants.rb +33 -0
  24. data/lib/right_agent/command/command_io.rb +126 -0
  25. data/lib/right_agent/command/command_parser.rb +87 -0
  26. data/lib/right_agent/command/command_runner.rb +118 -0
  27. data/lib/right_agent/command/command_serializer.rb +63 -0
  28. data/lib/right_agent/connectivity_checker.rb +179 -0
  29. data/lib/right_agent/console.rb +65 -0
  30. data/lib/right_agent/core_payload_types.rb +44 -0
  31. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  32. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  33. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  34. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  35. data/lib/right_agent/core_payload_types/dev_repositories.rb +100 -0
  36. data/lib/right_agent/core_payload_types/dev_repository.rb +76 -0
  37. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  38. data/lib/right_agent/core_payload_types/executable_bundle.rb +130 -0
  39. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  40. data/lib/right_agent/core_payload_types/login_user.rb +79 -0
  41. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  42. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +73 -0
  43. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  44. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  45. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +94 -0
  46. data/lib/right_agent/core_payload_types/runlist_policy.rb +44 -0
  47. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  48. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  49. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  50. data/lib/right_agent/daemonize.rb +35 -0
  51. data/lib/right_agent/dispatched_cache.rb +109 -0
  52. data/lib/right_agent/dispatcher.rb +272 -0
  53. data/lib/right_agent/enrollment_result.rb +221 -0
  54. data/lib/right_agent/exceptions.rb +87 -0
  55. data/lib/right_agent/history.rb +145 -0
  56. data/lib/right_agent/log.rb +460 -0
  57. data/lib/right_agent/minimal.rb +46 -0
  58. data/lib/right_agent/monkey_patches.rb +30 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch.rb +55 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  64. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  65. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  66. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +60 -0
  67. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  68. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  69. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  70. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  71. data/lib/right_agent/multiplexer.rb +102 -0
  72. data/lib/right_agent/offline_handler.rb +270 -0
  73. data/lib/right_agent/operation_result.rb +300 -0
  74. data/lib/right_agent/packets.rb +673 -0
  75. data/lib/right_agent/payload_formatter.rb +104 -0
  76. data/lib/right_agent/pending_requests.rb +128 -0
  77. data/lib/right_agent/pid_file.rb +159 -0
  78. data/lib/right_agent/platform.rb +770 -0
  79. data/lib/right_agent/platform/unix/darwin/platform.rb +102 -0
  80. data/lib/right_agent/platform/unix/linux/platform.rb +305 -0
  81. data/lib/right_agent/platform/unix/platform.rb +226 -0
  82. data/lib/right_agent/platform/windows/mingw/platform.rb +447 -0
  83. data/lib/right_agent/platform/windows/mswin/platform.rb +236 -0
  84. data/lib/right_agent/platform/windows/platform.rb +1808 -0
  85. data/lib/right_agent/protocol_version_mixin.rb +69 -0
  86. data/lib/right_agent/retryable_request.rb +195 -0
  87. data/lib/right_agent/scripts/agent_controller.rb +543 -0
  88. data/lib/right_agent/scripts/agent_deployer.rb +400 -0
  89. data/lib/right_agent/scripts/common_parser.rb +160 -0
  90. data/lib/right_agent/scripts/log_level_manager.rb +192 -0
  91. data/lib/right_agent/scripts/stats_manager.rb +268 -0
  92. data/lib/right_agent/scripts/usage.rb +58 -0
  93. data/lib/right_agent/secure_identity.rb +92 -0
  94. data/lib/right_agent/security.rb +32 -0
  95. data/lib/right_agent/security/cached_certificate_store_proxy.rb +77 -0
  96. data/lib/right_agent/security/certificate.rb +102 -0
  97. data/lib/right_agent/security/certificate_cache.rb +89 -0
  98. data/lib/right_agent/security/distinguished_name.rb +56 -0
  99. data/lib/right_agent/security/encrypted_document.rb +83 -0
  100. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  101. data/lib/right_agent/security/signature.rb +86 -0
  102. data/lib/right_agent/security/static_certificate_store.rb +85 -0
  103. data/lib/right_agent/sender.rb +792 -0
  104. data/lib/right_agent/serialize.rb +29 -0
  105. data/lib/right_agent/serialize/message_pack.rb +107 -0
  106. data/lib/right_agent/serialize/secure_serializer.rb +151 -0
  107. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  108. data/lib/right_agent/serialize/serializable.rb +151 -0
  109. data/lib/right_agent/serialize/serializer.rb +159 -0
  110. data/lib/right_agent/subprocess.rb +38 -0
  111. data/lib/right_agent/tracer.rb +124 -0
  112. data/right_agent.gemspec +101 -0
  113. data/spec/actor_registry_spec.rb +80 -0
  114. data/spec/actor_spec.rb +162 -0
  115. data/spec/agent_config_spec.rb +235 -0
  116. data/spec/agent_identity_spec.rb +78 -0
  117. data/spec/agent_spec.rb +734 -0
  118. data/spec/agent_tag_manager_spec.rb +319 -0
  119. data/spec/clients/api_client_spec.rb +423 -0
  120. data/spec/clients/auth_client_spec.rb +272 -0
  121. data/spec/clients/balanced_http_client_spec.rb +576 -0
  122. data/spec/clients/base_retry_client_spec.rb +635 -0
  123. data/spec/clients/router_client_spec.rb +594 -0
  124. data/spec/clients/spec_helper.rb +111 -0
  125. data/spec/command/agent_manager_commands_spec.rb +51 -0
  126. data/spec/command/command_io_spec.rb +93 -0
  127. data/spec/command/command_parser_spec.rb +79 -0
  128. data/spec/command/command_runner_spec.rb +107 -0
  129. data/spec/command/command_serializer_spec.rb +51 -0
  130. data/spec/connectivity_checker_spec.rb +83 -0
  131. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  132. data/spec/core_payload_types/dev_repository_spec.rb +33 -0
  133. data/spec/core_payload_types/executable_bundle_spec.rb +67 -0
  134. data/spec/core_payload_types/login_user_spec.rb +102 -0
  135. data/spec/core_payload_types/recipe_instantiation_spec.rb +81 -0
  136. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  137. data/spec/core_payload_types/right_script_instantiation_spec.rb +79 -0
  138. data/spec/core_payload_types/spec_helper.rb +23 -0
  139. data/spec/dispatched_cache_spec.rb +136 -0
  140. data/spec/dispatcher_spec.rb +324 -0
  141. data/spec/enrollment_result_spec.rb +53 -0
  142. data/spec/history_spec.rb +246 -0
  143. data/spec/log_spec.rb +192 -0
  144. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  145. data/spec/multiplexer_spec.rb +48 -0
  146. data/spec/offline_handler_spec.rb +340 -0
  147. data/spec/operation_result_spec.rb +208 -0
  148. data/spec/packets_spec.rb +461 -0
  149. data/spec/pending_requests_spec.rb +136 -0
  150. data/spec/platform/spec_helper.rb +216 -0
  151. data/spec/platform/unix/darwin/platform_spec.rb +181 -0
  152. data/spec/platform/unix/linux/platform_spec.rb +540 -0
  153. data/spec/platform/unix/spec_helper.rb +149 -0
  154. data/spec/platform/windows/mingw/platform_spec.rb +222 -0
  155. data/spec/platform/windows/mswin/platform_spec.rb +259 -0
  156. data/spec/platform/windows/spec_helper.rb +720 -0
  157. data/spec/retryable_request_spec.rb +306 -0
  158. data/spec/secure_identity_spec.rb +50 -0
  159. data/spec/security/cached_certificate_store_proxy_spec.rb +62 -0
  160. data/spec/security/certificate_cache_spec.rb +71 -0
  161. data/spec/security/certificate_spec.rb +49 -0
  162. data/spec/security/distinguished_name_spec.rb +46 -0
  163. data/spec/security/encrypted_document_spec.rb +55 -0
  164. data/spec/security/rsa_key_pair_spec.rb +55 -0
  165. data/spec/security/signature_spec.rb +66 -0
  166. data/spec/security/static_certificate_store_spec.rb +58 -0
  167. data/spec/sender_spec.rb +1045 -0
  168. data/spec/serialize/message_pack_spec.rb +131 -0
  169. data/spec/serialize/secure_serializer_spec.rb +132 -0
  170. data/spec/serialize/serializable_spec.rb +90 -0
  171. data/spec/serialize/serializer_spec.rb +197 -0
  172. data/spec/spec.opts +2 -0
  173. data/spec/spec.win32.opts +1 -0
  174. data/spec/spec_helper.rb +130 -0
  175. data/spec/tracer_spec.rb +114 -0
  176. metadata +447 -0
@@ -0,0 +1,447 @@
1
+ #
2
+ # Copyright (c) 2013 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require ::File.expand_path('../../../../platform', __FILE__)
24
+
25
+ # ignore unless Windows as a concession to spec testing from non-Windows.
26
+ # any windows-only gems must be fully mocked under test.
27
+ if RUBY_PLATFORM =~ /mingw/
28
+ # Foreign Function Interface used for all API calls in mingw
29
+ require 'ffi'
30
+ end
31
+
32
+ module RightScale
33
+
34
+ # Windows specific implementation
35
+ class Platform
36
+
37
+ # helpers
38
+ class PlatformHelperBase
39
+ # _W (i.e. 'wide') Windows APIs all use little-endian unicode.
40
+ #
41
+ # _A doesn't correspond to any particular single/multi-byte encoding (even
42
+ # though n00bs get confused and think in means ASCII). _A actually means
43
+ # 'use the current codepage' for which you would need to make another API
44
+ # call to discover what the current thread thinks is the current codepage.
45
+ WIDE = ::Encoding::UTF_16LE
46
+
47
+ # We favor the _W APIs to ensure proper marshalling of Unicode characters
48
+ # to/from the ruby interpreter's default codepage. This method facilitates
49
+ # API calls that fill a Unicode buffer and need to marshal the buffered
50
+ # data to a multi-byte (default encoding) buffer.
51
+ #
52
+ # @param [String] buffer to receive marshalled data from Unicode API or
53
+ # nil to query required buffer.
54
+ # @param [Hash] copy_options for copy_to_string_buffer
55
+ #
56
+ # @yield [buffer] yields the buffer at current size for API call
57
+ # @yieldparam [String] buffer to use for API call (get size from buffer)
58
+ # or nil to query required buffer size.
59
+ #
60
+ # @return [String] buffered data length or zero for failure
61
+ def with_unicode_buffer(buffer, copy_options = {})
62
+ # note that _W methods always expect UTF-16 LE (Little Endian) due to
63
+ # the Intel chipset representing word values as LE. Windows runs on
64
+ # other chipsets but LE is always used by API calls.
65
+ if buffer && buffer.encoding != WIDE
66
+ unicode_buffer = 0.chr.encode(WIDE) * buffer.size
67
+ unicode_length_or_buffer_count = yield(unicode_buffer)
68
+
69
+ if unicode_length_or_buffer_count > 0 &&
70
+ unicode_length_or_buffer_count < unicode_buffer.size
71
+
72
+ # reencode to non-Unicode buffer, including trailing NUL character.
73
+ #
74
+ # note that reencoding may exceed given (Unicode) buffer size
75
+ # because of two-byte chars expanded from single unicode chars.
76
+ # in this case the required multi-byte buffer size will be returned
77
+ # and then promoted to a 'doubled' Unicode buffer size on next call.
78
+ result = copy_to_string_buffer(
79
+ unicode_buffer[0, unicode_length_or_buffer_count + 1],
80
+ buffer,
81
+ copy_options)
82
+ else
83
+ result = unicode_length_or_buffer_count
84
+ end
85
+ else
86
+ # buffer is already UTF-16LE or else nil
87
+ result = yield(buffer)
88
+ end
89
+ result
90
+ end
91
+
92
+ # Performs a bytewise copy to given target buffer with respect for the
93
+ # encoding of the source and target buffers. Assumes a NUL terminator
94
+ # appears in the string to be copied per normal Windows API behavor.
95
+ #
96
+ # @param [String] source_buffer encoded source
97
+ # @param [String] target_buffer encoded target
98
+ # @param [Hash] options for copy
99
+ # @option options [TrueClass|FalseClass] :truncate is true to allow
100
+ # trunction of string to fit buffer, false to return required buffer
101
+ # size if copy would exceed buffer
102
+ #
103
+ # @return [Integer] length of encoded target or else buffer length needed for full copy
104
+ def copy_to_string_buffer(source_buffer, target_buffer, options = {})
105
+ options = { :truncate => false }.merge(options)
106
+
107
+ # note that a buffer of NULs will default to ASCII encoding in
108
+ # ruby 1.9 so change to use default encoding automagically. this makes
109
+ # it easier to support the default codepage in 1.9 but be oblivious to
110
+ # it in 1.8, which does not support these encoding methods. if the
111
+ # caller wants any other codepage (in 1.9) then it should be specified
112
+ # on the target.
113
+ if target_buffer.encoding == Encoding::ASCII
114
+ # we can force encoding only if the default encoding is ASCII
115
+ # compatible. we are going to clobber the bytes so the old bytes are
116
+ # irrelevant unless the bytesize of the buffer would differ.
117
+ if ::Encoding.default_external.ascii_compatible?
118
+ # note that force_encoding modifies self even though it's not a
119
+ # banged! method.
120
+ target_buffer.force_encoding(::Encoding.default_external)
121
+ else
122
+ target_buffer.encode!(::Encoding.default_external)
123
+ end
124
+ end
125
+
126
+ # reencode the source buffer, changing any characters that cannot be
127
+ # encoded to the default replacement character, which is usually '?'
128
+ target_encoding = target_buffer.encoding
129
+ reencoded_source_buffer = source_buffer.encode(
130
+ target_encoding, :invalid => :replace, :undef => :replace)
131
+
132
+ # determine if sufficient buffer exists.
133
+ result = nil
134
+ nul_char = 0.chr.encode(target_encoding)
135
+ reencoded_source_length = reencoded_source_buffer.index(nul_char) ||
136
+ reencoded_source_buffer.length
137
+ if reencoded_source_length <= target_buffer.length || options[:truncate]
138
+ # bytewise replacement (to reuse caller's buffer instead of
139
+ # reallocating the string's buffer).
140
+ copy_length = [reencoded_source_length, target_buffer.length - 1].min
141
+ copy_byte_count = nul_char.bytesize * copy_length
142
+ reencoded_source_buffer.bytes.each_with_index do |b, b_index|
143
+ break if b_index >= copy_byte_count
144
+ target_buffer.setbyte(b_index, b)
145
+ end
146
+ target_buffer[copy_length] = nul_char
147
+ result = copy_length
148
+ else
149
+ result = reencoded_source_length
150
+ end
151
+ result
152
+ end
153
+ end
154
+
155
+ class Filesystem
156
+
157
+ # FFI APIs
158
+ class API
159
+ extend FFI::Library
160
+
161
+ typedef :ulong, :dword
162
+
163
+ ffi_lib :kernel32
164
+
165
+ # the FFI wiki documents that it is important to specify the stdcall
166
+ # calling convention properly, but public gems like win32-dir don't
167
+ # bother; who do you believe?
168
+ #
169
+ # @see https://github.com/ffi/ffi/wiki/Windows-Examples
170
+ #
171
+ # looking at the FFI assembly code, it may workaround a gem using the
172
+ # wrong calling convention by always restoring the stack pointer after
173
+ # the call, but that's no excuse to call things improperly.
174
+ ffi_convention :stdcall
175
+
176
+ # yes, we could import the _A APIs but what codepage would they use?
177
+ # it's better not to think about it and do the extra marshalling for _W,
178
+ # which is always Encoding::UTF_16LE. the reality of WinNT+ is that it
179
+ # implements all APIs as _W and does extra marshalling with a lookup to
180
+ # the thread's current codepage on every call to an _A API.
181
+ attach_function :GetShortPathNameW, [:buffer_in, :buffer_out, :dword], :dword
182
+ attach_function :GetTempPathW, [:dword, :buffer_out], :dword
183
+
184
+ begin
185
+ attach_function :CreateSymbolicLinkW, [:buffer_in, :buffer_in, :dword], :bool
186
+ rescue FFI::NotFoundError
187
+ # we don't really support 2003 server any longer but ignore this.
188
+ end
189
+ end
190
+
191
+ # Overrides base Filesystem#CreateSymbolicLink
192
+ def CreateSymbolicLink(symlink_file_path, target_file_path, flags)
193
+ must_be_string(symlink_file_path)
194
+ must_be_string(target_file_path)
195
+ must_be_dword(flags)
196
+ if defined?(API.CreateSymbolicLinkW)
197
+ API.CreateSymbolicLinkW(
198
+ symlink_file_path.encode(WIDE),
199
+ target_file_path.encode(WIDE),
200
+ flags)
201
+ else
202
+ raise ::RightScale::Exceptions::PlatformError,
203
+ 'Cannot create symlinks on this platform'
204
+ end
205
+ end
206
+
207
+ # Overrides base Filesystem#GetShortPathName
208
+ def GetShortPathName(long_path, short_path_buffer, short_path_buffer_length)
209
+ must_be_string(long_path)
210
+ must_be_char_buffer_or_nil(short_path_buffer, short_path_buffer_length)
211
+ with_unicode_buffer(short_path_buffer) do |unicode_buffer|
212
+ API.GetShortPathNameW(
213
+ long_path.encode(WIDE),
214
+ unicode_buffer,
215
+ unicode_buffer ? unicode_buffer.size : 0)
216
+ end
217
+ end
218
+
219
+ # Overrides base Filesystem#GetTempDir
220
+ def GetTempPath(buffer_length, buffer)
221
+ must_be_char_buffer_or_nil(buffer, buffer_length)
222
+ with_unicode_buffer(buffer) do |unicode_buffer|
223
+ API.GetTempPathW(
224
+ unicode_buffer ? unicode_buffer.size : 0,
225
+ unicode_buffer)
226
+ end
227
+ end
228
+ end # Filesystem
229
+
230
+ class Controller
231
+
232
+ # FFI APIs
233
+ class API
234
+ extend FFI::Library
235
+
236
+ typedef :ulong, :dword
237
+
238
+ ffi_lib :advapi32
239
+ ffi_convention :stdcall
240
+
241
+ attach_function :InitiateSystemShutdownW, [:buffer_in, :buffer_in, :dword, :bool, :bool], :bool
242
+ end
243
+
244
+ # Overrides base Controller#InitiateSystemShutdown
245
+ def InitiateSystemShutdown(machine_name, message, timeout, force_apps_closed, reboot_after_shutdown)
246
+ must_be_string_or_nil(machine_name)
247
+ must_be_string_or_nil(message)
248
+ must_be_dword(timeout)
249
+ must_be_bool(force_apps_closed)
250
+ must_be_bool(reboot_after_shutdown)
251
+ API.InitiateSystemShutdownW(
252
+ machine_name ? machine_name.encode(WIDE) : nil,
253
+ message ? message.encode(WIDE) : nil,
254
+ timeout,
255
+ force_apps_closed,
256
+ reboot_after_shutdown)
257
+ end
258
+ end # Controller
259
+
260
+ class Process
261
+
262
+ # FFI APIs
263
+ class API
264
+ extend FFI::Library
265
+
266
+ typedef :uintptr_t, :handle
267
+ typedef :ulong, :dword
268
+
269
+ ffi_lib :kernel32
270
+ ffi_convention :stdcall
271
+
272
+ attach_function :GetCurrentProcess, [], :handle
273
+
274
+ ffi_lib :psapi
275
+ ffi_convention :stdcall
276
+
277
+ attach_function :GetProcessMemoryInfo, [:handle, :buffer_out, :dword], :bool
278
+
279
+ ffi_lib :advapi32
280
+ ffi_convention :stdcall
281
+
282
+ attach_function :OpenProcessToken, [:handle, :dword, :buffer_out], :bool
283
+ end
284
+
285
+ # Overrides base Process#GetCurrentProcess
286
+ def GetCurrentProcess
287
+ API.GetCurrentProcess
288
+ end
289
+
290
+ # Overrides base Process#GetProcessMemoryInfo
291
+ def GetProcessMemoryInfo(process_handle, process_memory_info_buffer, process_memory_info_buffer_size)
292
+ must_be_dword(process_handle)
293
+ must_be_size_prefixed_buffer(process_memory_info_buffer, process_memory_info_buffer_size)
294
+ API.GetProcessMemoryInfo(
295
+ process_handle,
296
+ process_memory_info_buffer,
297
+ process_memory_info_buffer_size)
298
+ end
299
+
300
+ # Overrides base Process#OpenProcessToken
301
+ def OpenProcessToken(process_handle, desired_access, token_handle)
302
+ must_be_dword(process_handle)
303
+ must_be_dword(desired_access)
304
+ must_be_byte_buffer(token_handle, SIZEOF_DWORD)
305
+ API.OpenProcessToken(process_handle, desired_access, token_handle)
306
+ end
307
+ end # Process
308
+
309
+ class WindowsCommon
310
+
311
+ # FFI APIs
312
+ class API
313
+ extend FFI::Library
314
+
315
+ typedef :uintptr_t, :handle
316
+ typedef :ulong, :dword
317
+
318
+ ffi_lib :kernel32
319
+ ffi_convention :stdcall
320
+
321
+ attach_function :CloseHandle, [:handle], :bool
322
+ attach_function :FormatMessageW, [:dword, :buffer_in, :dword, :dword, :buffer_out, :dword, :buffer_in], :dword
323
+ end
324
+
325
+ # Overrides base WindowsCommon#CloseHandle
326
+ def CloseHandle(handle)
327
+ must_be_dword(handle)
328
+ API.CloseHandle(handle)
329
+ end
330
+
331
+ # Overrides base WindowsCommon#FormatMessage
332
+ def FormatMessage(flags, source, message_id, language_id, buffer, buffer_size, arguments)
333
+ unless source.nil? && arguments.nil?
334
+ raise ::NotImplementedError,
335
+ 'Not supporting FormatMessage source or arguments'
336
+ end
337
+ must_be_dword(message_id)
338
+ must_be_dword(language_id)
339
+ must_be_char_buffer(buffer, buffer_size)
340
+ with_unicode_buffer(buffer, :truncate => true) do |unicode_buffer|
341
+ API.FormatMessageW(
342
+ flags, source, message_id, language_id,
343
+ unicode_buffer, unicode_buffer.size, arguments)
344
+ end
345
+ end
346
+
347
+ # Overrides base WindowsCommon#GetLastError
348
+ def GetLastError
349
+ # note that you cannot call GetLastError API via FFI without changing
350
+ # the last error code; Heisenberg Uncertainty API. the documented
351
+ # workaround is to call the following method.
352
+ ::FFI::errno
353
+ end
354
+ end # WindowsCommon
355
+
356
+ class WindowsSecurity
357
+
358
+ # FFI APIs
359
+ class API
360
+ extend FFI::Library
361
+
362
+ typedef :uintptr_t, :handle
363
+ typedef :ulong, :dword
364
+
365
+ ffi_lib :advapi32
366
+ ffi_convention :stdcall
367
+
368
+ attach_function :LookupPrivilegeValueW, [:buffer_in, :buffer_in, :pointer], :bool
369
+ attach_function :AdjustTokenPrivileges, [:handle, :bool, :buffer_in, :dword, :buffer_out, :buffer_out], :bool
370
+ end
371
+
372
+ # Overrides base WindowsSecurity#LookupPrivilegeValue
373
+ def LookupPrivilegeValue(system_name, name, luid)
374
+ must_be_string_or_nil(system_name)
375
+ must_be_string(name)
376
+ must_be_byte_buffer(luid, SIZEOF_QWORD)
377
+ API.LookupPrivilegeValueW(
378
+ system_name ? system_name.encode(WIDE) : nil,
379
+ name.encode(WIDE),
380
+ luid)
381
+ end
382
+
383
+ # Overrides base WindowsSecurity#AdjustTokenPrivileges
384
+ def AdjustTokenPrivileges(token_handle, disable_all_privileges, new_state, buffer_length, previous_state, return_length)
385
+ must_be_dword(token_handle)
386
+ must_be_bool(disable_all_privileges)
387
+ must_be_buffer_or_nil(new_state)
388
+ must_be_byte_buffer_or_nil(previous_state, buffer_length)
389
+ must_be_byte_buffer_or_nil(return_length, return_length ? SIZEOF_DWORD : 0)
390
+ API.AdjustTokenPrivileges(
391
+ token_handle, disable_all_privileges, new_state,
392
+ buffer_length, previous_state, return_length)
393
+ end
394
+ end # WindowsSecurity
395
+
396
+ class WindowsSystemInformation
397
+
398
+ # FFI APIs
399
+ class API
400
+ extend FFI::Library
401
+
402
+ typedef :ulong, :dword
403
+
404
+ ffi_lib :kernel32
405
+ ffi_convention :stdcall
406
+
407
+ attach_function :GetVersionExW, [:buffer_out], :bool
408
+ end
409
+
410
+ # Overrides base WindowsSystemInformation#GetVersionEx
411
+ def GetVersionEx(version_info_buffer)
412
+ must_be_size_prefixed_buffer(version_info_buffer)
413
+ API.GetVersionExW(version_info_buffer)
414
+ end
415
+
416
+ # Overrides base WindowsSystemInformation#create_os_version_info
417
+ def create_os_version_info
418
+ [
419
+ 276, # 0 - size of OSVERSIONINFO (IN)
420
+ 0, # 4 - major version (OUT)
421
+ 0, # 8 - minor version (OUT)
422
+ 0, # 12 - build (OUT)
423
+ 0, # 16 - platform (OUT)
424
+ 0.chr * 128 * 2 # 20 - additional info (OUT)
425
+ ].pack('LLLLLa256')
426
+ end
427
+
428
+ # Overrides base WindowsSystemInformation#unpack_os_version_info
429
+ def unpack_os_version_info(buffer)
430
+ result = buffer.unpack('LLLLL')
431
+ additional_info = buffer[20, 256].force_encoding(WIDE)
432
+ additional_info_length = additional_info.index(0.chr.encode(additional_info.encoding)) || additional_info.length
433
+ result << additional_info[0, additional_info_length].encode(::Encoding.default_external)
434
+ result
435
+ end
436
+ end # WindowsSystemInformation
437
+
438
+ private
439
+
440
+ # Overrides base Platform#initialize_species
441
+ def initialize_species
442
+ true # do nothing
443
+ end
444
+
445
+ end # Platform
446
+
447
+ end # RightScale
@@ -0,0 +1,236 @@
1
+ #
2
+ # Copyright (c) 2009-2013 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require ::File.expand_path('../../../../platform', __FILE__)
24
+
25
+ # ignore unless Windows as a concession to spec testing from non-Windows.
26
+ # any windows-only gems must be fully mocked under test.
27
+ if RUBY_PLATFORM =~ /mswin/
28
+ # legacy API gem for ruby 1.8, superceded by FFI in ruby 1.9
29
+ require 'win32/api'
30
+ end
31
+
32
+ module RightScale
33
+
34
+ # Windows specific implementation
35
+ class Platform
36
+
37
+ # helpers
38
+ class PlatformHelperBase
39
+ API_NULL = 0
40
+ API_FALSE = 0
41
+ API_TRUE = 1
42
+
43
+ private
44
+
45
+ # it is incorrect in the general case to say result == API_TRUE
46
+ # Quote from every API doc I've ever read:
47
+ # "If the function succeeds, the return value is nonzero"
48
+ def api_succeeded(result)
49
+ result != API_FALSE
50
+ end
51
+ end
52
+
53
+ class Filesystem
54
+
55
+ # Overrides base Filesystem#CreateSymbolicLink
56
+ def CreateSymbolicLink(symlink_file_path, target_file_path, flags)
57
+ must_be_string(symlink_file_path)
58
+ must_be_string(target_file_path)
59
+ must_be_dword(flags)
60
+ @create_symbolic_link ||= ::Win32::API.new('CreateSymbolicLink', 'SSL', 'B', 'kernel32')
61
+ api_succeeded(
62
+ @create_symbolic_link.call(
63
+ symlink_file_path, target_file_path, flags))
64
+ rescue ::Win32::API::LoadLibraryError
65
+ raise ::RightScale::Exceptions::PlatformError,
66
+ 'Cannot create symlinks on this platform'
67
+ end
68
+
69
+ # Overrides base Filesystem#GetShortPathName
70
+ def GetShortPathName(long_path, short_path_buffer, short_path_buffer_length)
71
+ must_be_string(long_path)
72
+ must_be_char_buffer(short_path_buffer, short_path_buffer_length)
73
+ @get_short_path_name ||= ::Win32::API.new('GetShortPathName', 'SPL', 'L', 'kernel32')
74
+ @get_short_path_name.call(
75
+ long_path, short_path_buffer, short_path_buffer_length)
76
+ end
77
+
78
+ # Overrides base Filesystem#GetTempPath
79
+ def GetTempPath(buffer_length, buffer)
80
+ must_be_char_buffer_or_nil(buffer, buffer_length)
81
+ @get_temp_dir_api ||= ::Win32::API.new('GetTempPath', 'LP', 'L', 'kernel32')
82
+ @get_temp_dir_api.call(buffer_length, buffer ? buffer : API_NULL)
83
+ end
84
+ end # Filesystem
85
+
86
+ class Controller
87
+
88
+ # Overrides base Controller#InitiateSystemShutdown
89
+ def InitiateSystemShutdown(machine_name, message, timeout, force_apps_closed, reboot_after_shutdown)
90
+ must_be_string_or_nil(machine_name)
91
+ must_be_string_or_nil(message)
92
+ must_be_dword(timeout)
93
+ must_be_bool(force_apps_closed)
94
+ must_be_bool(reboot_after_shutdown)
95
+ @initiate_system_shutdown ||= ::Win32::API.new('InitiateSystemShutdown', 'PPLLL', 'B', 'advapi32')
96
+ api_succeeded(
97
+ @initiate_system_shutdown.call(
98
+ machine_name ? machine_name : API_NULL,
99
+ message ? message : API_NULL,
100
+ timeout,
101
+ force_apps_closed ? API_TRUE : API_FALSE,
102
+ reboot_after_shutdown ? API_TRUE : API_FALSE))
103
+ end
104
+ end # Controller
105
+
106
+ class Process
107
+
108
+ # Overrides base Process#GetCurrentProcess
109
+ def GetCurrentProcess
110
+ @get_current_process ||= ::Win32::API.new('GetCurrentProcess', 'V', 'L', 'kernel32')
111
+ @get_current_process.call
112
+ end
113
+
114
+ # Overrides base Process#GetProcessMemoryInfo
115
+ def GetProcessMemoryInfo(process_handle, process_memory_info_buffer, process_memory_info_buffer_size)
116
+ must_be_dword(process_handle)
117
+ must_be_size_prefixed_buffer(process_memory_info_buffer, process_memory_info_buffer_size)
118
+ @get_process_memory_info ||= ::Win32::API.new('GetProcessMemoryInfo', 'LPL', 'B', 'psapi')
119
+ api_succeeded(
120
+ @get_process_memory_info.call(
121
+ process_handle,
122
+ process_memory_info_buffer,
123
+ process_memory_info_buffer_size))
124
+ end
125
+
126
+ # Overrides base Process#OpenProcessToken
127
+ def OpenProcessToken(process_handle, desired_access, token_handle)
128
+ must_be_dword(process_handle)
129
+ must_be_dword(desired_access)
130
+ must_be_byte_buffer(token_handle, SIZEOF_DWORD)
131
+ @open_process_token ||= ::Win32::API.new('OpenProcessToken', 'LLP', 'B', 'advapi32')
132
+ api_succeeded(
133
+ @open_process_token.call(
134
+ process_handle, desired_access, token_handle))
135
+ end
136
+ end # Process
137
+
138
+ class WindowsCommon
139
+
140
+ # Overrides base WindowsCommon#CloseHandle
141
+ def CloseHandle(handle)
142
+ must_be_dword(handle)
143
+ @close_handle ||= ::Win32::API.new('CloseHandle', 'L', 'B', 'kernel32')
144
+ api_succeeded(@close_handle.call(handle))
145
+ end
146
+
147
+ # Overrides base WindowsCommon#FormatMessage
148
+ def FormatMessage(flags, source, message_id, language_id, buffer, buffer_size, arguments)
149
+ if source || arguments
150
+ raise ::NotImplementedError, 'Not supporting FormatMessage source or arguments'
151
+ end
152
+ must_be_dword(message_id)
153
+ must_be_dword(language_id)
154
+ must_be_char_buffer(buffer, buffer_size)
155
+ @format_message ||= ::Win32::API.new('FormatMessage', 'LLLLPLP', 'L', 'kernel32')
156
+ @format_message.call(flags, API_NULL, message_id, language_id, buffer, buffer_size, API_NULL)
157
+ end
158
+
159
+ # Overrides base WindowsCommon#GetLastError
160
+ def GetLastError
161
+ @get_last_error ||= ::Win32::API.new('GetLastError', 'V', 'L', 'kernel32')
162
+ @get_last_error.call
163
+ end
164
+ end # WindowsCommon
165
+
166
+ class WindowsSecurity
167
+
168
+ # Overrides base WindowsSecurity#LookupPrivilegeValue
169
+ def LookupPrivilegeValue(system_name, name, luid)
170
+ must_be_string_or_nil(system_name)
171
+ must_be_string(name)
172
+ must_be_byte_buffer(luid, SIZEOF_QWORD)
173
+ @lookup_privilege_value ||= ::Win32::API.new('LookupPrivilegeValue', 'PPP', 'B', 'advapi32')
174
+ api_succeeded(
175
+ @lookup_privilege_value.call(
176
+ system_name ? system_name : API_NULL,
177
+ name,
178
+ luid))
179
+ end
180
+
181
+ # Overrides base WindowsSecurity#AdjustTokenPrivileges
182
+ def AdjustTokenPrivileges(token_handle, disable_all_privileges, new_state, buffer_length, previous_state, return_length)
183
+ must_be_dword(token_handle)
184
+ must_be_bool(disable_all_privileges)
185
+ must_be_buffer_or_nil(new_state)
186
+ must_be_byte_buffer_or_nil(previous_state, buffer_length)
187
+ must_be_byte_buffer_or_nil(return_length, return_length ? SIZEOF_DWORD : 0)
188
+ @adjust_token_privileges ||= ::Win32::API.new('AdjustTokenPrivileges', 'LLPLPP', 'B', 'advapi32')
189
+ api_succeeded(
190
+ @adjust_token_privileges.call(
191
+ token_handle,
192
+ disable_all_privileges ? API_TRUE : API_FALSE,
193
+ new_state ? new_state : API_NULL,
194
+ buffer_length,
195
+ previous_state ? previous_state : API_NULL,
196
+ return_length ? return_length : API_NULL))
197
+ end
198
+ end # WindowsSecurity
199
+
200
+ class WindowsSystemInformation
201
+
202
+ # Overrides base WindowsSystemInformation#GetVersionEx
203
+ def GetVersionEx(version_info_buffer)
204
+ must_be_size_prefixed_buffer(version_info_buffer)
205
+ @get_version_ex ||= ::Win32::API.new('GetVersionEx', 'P', 'L', 'kernel32')
206
+ api_succeeded(@get_version_ex.call(version_info_buffer))
207
+ end
208
+
209
+ # Overrides base WindowsSystemInformation#create_os_version_info
210
+ def create_os_version_info
211
+ [
212
+ 148, # 0 - size of OSVERSIONINFO (IN)
213
+ 0, # 4 - major version (OUT)
214
+ 0, # 8 - minor version (OUT)
215
+ 0, # 12 - build (OUT)
216
+ 0, # 16 - platform (OUT)
217
+ 0.chr * 128 # 20 - additional info (OUT)
218
+ ].pack('LLLLLa128')
219
+ end
220
+
221
+ # Overrides base WindowsSystemInformation#unpack_os_version_info
222
+ def unpack_os_version_info(buffer)
223
+ buffer.unpack('LLLLLZ128') # 'Z' means ASCIIZ string
224
+ end
225
+ end # WindowsSystemInformation
226
+
227
+ private
228
+
229
+ # Overrides base Platform#initialize_species
230
+ def initialize_species
231
+ true # do nothing
232
+ end
233
+
234
+ end # Platform
235
+
236
+ end # RightScale