right_agent 2.0.7-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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