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,720 @@
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('../../spec_helper', __FILE__)
24
+
25
+ shared_examples_for 'supports windows platform statics' do
26
+ it 'should be Windows' do
27
+ subject.unix?.should be_false
28
+ subject.windows?.should be_true
29
+ subject.linux?.should be_false
30
+ subject.darwin?.should be_false
31
+ end
32
+ end # supports windows platform statics
33
+
34
+ shared_examples_for 'supports windows platform initialization' do
35
+ it 'should query os info during initialize' do
36
+ instrument_os_info(6, 1, 7601)
37
+ platform_instance.send(:initialize_genus)
38
+ platform_instance.release.should == '6.1.7601'
39
+ platform_instance.codename.should == ''
40
+ end
41
+ end # supports windows platform initialization
42
+
43
+ shared_examples_for 'supports windows platform filesystem' do
44
+ context '#find_executable_in_path' do
45
+ let(:pathexts) { %w[.EXE .BAT] }
46
+ let(:paths) { %w[C:\Windows\system32 C:\Windows C:\Windows\System32\Wbem] }
47
+ let(:pathext_env) { pathexts.join(';') }
48
+ let(:path_env) { paths.join(';') }
49
+ let(:expected_path) { 'C:/Windows/foo.EXE' }
50
+
51
+ it 'should find executable' do
52
+ mock_env = flexmock(::ENV)
53
+ mock_env.should_receive(:[]).with('PATHEXT').and_return(pathext_env)
54
+ mock_env.should_receive(:[]).with('PATH').and_return(path_env)
55
+
56
+ all_paths = [::Dir.getwd.gsub("\\", '/')] + paths
57
+ foo_found = false
58
+ all_paths.each do |path|
59
+ pathexts.each do |pathext|
60
+ unless foo_found
61
+ foo_path = ::File.join(path.gsub("\\", '/'), 'foo' + pathext)
62
+ foo_matched = foo_path == expected_path
63
+ file_class.should_receive(:executable?).
64
+ with(foo_path).
65
+ and_return(foo_matched).
66
+ twice
67
+ foo_found = foo_matched
68
+ end
69
+ bar_path = ::File.join(path.gsub("\\", '/'), 'bar' + pathext)
70
+ file_class.should_receive(:executable?).with(bar_path).and_return(false).twice
71
+ end
72
+ end
73
+
74
+ subject.find_executable_in_path('foo').should == expected_path
75
+ subject.has_executable_in_path('foo').should be_true
76
+ subject.find_executable_in_path('bar').should be_nil
77
+ subject.has_executable_in_path('bar').should be_false
78
+ end
79
+ end # find_executable_in_path
80
+
81
+ context 'paths' do
82
+ context 'constants' do
83
+ before(:each) do
84
+ # win32/dir-based constants.
85
+ subject.should_receive(:common_app_data_dir).and_return('C:/ProgramData')
86
+ subject.should_receive(:program_files_dir).and_return('C:/Program Files (x86)')
87
+
88
+ # ENV-based constants.
89
+ @mock_env = flexmock(::ENV)
90
+ @mock_env.should_receive(:[]).with('SystemRoot').and_return("C:\\Windows")
91
+ @mock_env.should_receive(:[]).with('USERPROFILE').and_return("C:\\Users\\foo")
92
+ end
93
+
94
+ it 'should return windows path constants' do
95
+ # windows-specific constants.
96
+ subject.company_app_data_dir.should == 'C:/ProgramData/RightScale'
97
+ subject.company_program_files_dir.should == 'C:/Program Files (x86)/RightScale'
98
+ subject.system_root.should == 'C:/Windows'
99
+ subject.user_home_dir.should == 'C:/Users/foo'
100
+
101
+ # constants available to all platforms.
102
+ subject.right_agent_cfg_dir.should == 'C:/ProgramData/RightScale/right_agent'
103
+ subject.right_scale_static_state_dir.should == 'C:/ProgramData/RightScale/rightscale.d'
104
+ subject.right_link_static_state_dir.should == 'C:/ProgramData/RightScale/rightscale.d/right_link'
105
+ subject.right_link_dynamic_state_dir.should == 'C:/ProgramData/RightScale/right_link'
106
+ subject.spool_dir.should == 'C:/ProgramData/RightScale/spool'
107
+ subject.ssh_cfg_dir.should == 'C:/Users/foo/.ssh'
108
+ subject.cache_dir.should == 'C:/ProgramData/RightScale/cache'
109
+ subject.log_dir.should == 'C:/ProgramData/RightScale/log'
110
+ subject.source_code_dir.should == 'C:/ProgramData/RightScale/src'
111
+ subject.pid_dir.should == 'C:/ProgramData/RightScale/run'
112
+
113
+ @mock_env.
114
+ should_receive(:[]).
115
+ with('RS_RIGHT_LINK_HOME').
116
+ and_return("C:\\PROGRA~2\\RIGHTS~1\\RIGHTL~1")
117
+ file_class.
118
+ should_receive(:normalize_path).
119
+ with('C:/PROGRA~2/RIGHTS~1/RIGHTL~1').
120
+ and_return('C:/PROGRA~2/RIGHTS~1/RIGHTL~1').
121
+ once
122
+ subject.right_link_home_dir.should == 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1'
123
+ subject.private_bin_dir.should == 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1/bin'
124
+ subject.sandbox_dir.should == 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox'
125
+ end
126
+
127
+ it 'should generate right_link_home_dir when not set in ENV' do
128
+ @mock_env.should_receive(:[]).with('RS_RIGHT_LINK_HOME').and_return(nil)
129
+ file_class.
130
+ should_receive(:normalize_path).
131
+ with('C:/Program Files (x86)/RightScale/RightLink').
132
+ and_return('C:/PROGRA~2/RIGHTS~1/RIGHTL~1').
133
+ once
134
+ subject.right_link_home_dir.should == 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1'
135
+ end
136
+ end
137
+
138
+ context '#temp_dir' do
139
+ it 'should query temp_dir by calling GetTempPath API' do
140
+ temp_path_from_api = "C:\\Users\\foo\\AppData\\Local\\Temp\\"
141
+ instrument_get_temp_path_api(temp_path_from_api) { temp_path_from_api.length }
142
+ subject.temp_dir.should == 'C:/Users/foo/AppData/Local/Temp'
143
+ end
144
+ end
145
+
146
+ context '#long_path_to_short_path' do
147
+ it 'should convert existing long path to short path' do
148
+ long_path = 'C:\Program Files (x86)\RightScale\RightLink'
149
+ short_path = 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1'
150
+ instrument_get_short_path_name_api(long_path, short_path) { short_path.length }
151
+ file_class.should_receive(:exists?).with(long_path).and_return(true).once
152
+ subject.long_path_to_short_path(long_path).should == short_path
153
+ end
154
+
155
+ it 'should convert existing parent of missing long path to short path' do
156
+ long_path_parent = 'C:/Program Files (x86)/RightScale'
157
+ long_path = long_path_parent + '/RightLink'
158
+ short_path_parent = 'C:/PROGRA~2/RIGHTS~1'
159
+ short_path = short_path_parent + '/RightLink'
160
+ instrument_get_short_path_name_api(long_path_parent, short_path_parent) { short_path_parent.length }
161
+ file_class.should_receive(:exists?).with(long_path).and_return(false).once
162
+ file_class.should_receive(:exists?).with(long_path_parent).and_return(true).once
163
+ subject.long_path_to_short_path(long_path).should == short_path
164
+ end
165
+ end
166
+
167
+ context '#pretty_path' do
168
+ it 'should pretty path' do
169
+ ugly = 'c:\/make//\/me\pretty'
170
+ pretty_for_ruby = 'c:/make/me/pretty'
171
+ pretty_for_cmd_exe = 'c:\make\me\pretty'
172
+ subject.pretty_path(ugly).should == pretty_for_ruby
173
+ subject.pretty_path(ugly, true).should == pretty_for_cmd_exe
174
+ subject.pretty_path(pretty_for_ruby) == pretty_for_ruby
175
+ subject.pretty_path(pretty_for_cmd_exe) == pretty_for_ruby
176
+ subject.pretty_path(pretty_for_ruby, true) == pretty_for_cmd_exe
177
+ subject.pretty_path(pretty_for_cmd_exe, true) == pretty_for_cmd_exe
178
+ end
179
+ end
180
+
181
+ context '#ensure_local_drive_path' do
182
+ before(:each) do
183
+ flexmock(::ENV).should_receive(:[]).with('HOMEDRIVE').and_return('C:')
184
+ end
185
+
186
+ it 'should do nothing if path is already on home drive' do
187
+ path = 'c:\already\local.txt'
188
+ subject.ensure_local_drive_path(path, 'foo').should == path
189
+ end
190
+
191
+ it 'should copy file to temp directory if not local' do
192
+ network_path = 'z:/from/network/drive.txt'
193
+ local_path = 'c:/temp/foo/drive.txt'
194
+ subject.should_receive(:temp_dir).and_return('c:/temp')
195
+ mock_file_utils = flexmock(::FileUtils)
196
+ mock_file_utils.should_receive(:mkdir_p).with('c:/temp/foo').and_return(true).once
197
+ file_class.should_receive(:directory?).with(network_path).and_return(false).once
198
+ mock_file_utils.should_receive(:cp).with(network_path, local_path).and_return(true).once
199
+ subject.ensure_local_drive_path(network_path, 'foo').should == local_path
200
+ end
201
+ end
202
+ end # paths
203
+
204
+ context '#create_symlink' do
205
+ it 'should create directory symlink' do
206
+ from_path = 'c:\foo\bar'
207
+ to_path = 'c:\foo\baz'
208
+ file_class.should_receive(:directory?).with(from_path).and_return(true)
209
+ instrument_create_symbolic_link_api(from_path, to_path, 1) { 1 }
210
+ subject.create_symlink(from_path, to_path).should == 0
211
+ end
212
+
213
+ it 'should create file symlink' do
214
+ from_path = 'c:\foo\bar.txt'
215
+ to_path = 'c:\baz\bar.txt'
216
+ file_class.should_receive(:directory?).with(from_path).and_return(false)
217
+ instrument_create_symbolic_link_api(from_path, to_path, 0) { 1 }
218
+ subject.create_symlink(from_path, to_path).should == 0
219
+ end
220
+
221
+ it 'should raise Win32Error on failure' do
222
+ from_path = 'c:\some\file.txt'
223
+ to_path = 'c:\no_access\hmm.txt'
224
+ file_class.should_receive(:directory?).with(from_path).and_return(false)
225
+ instrument_create_symbolic_link_api(from_path, to_path, 0) { 0 }
226
+ instrument_win32_error(5, 'Access is denied.')
227
+ expect { subject.create_symlink(from_path, to_path) }.
228
+ to raise_error(
229
+ described_class::Win32Error,
230
+ "Failed to create link from #{from_path.inspect} to #{to_path.inspect}\nWin32 error code = 5\nAccess is denied.")
231
+ end
232
+ end # create_symlink
233
+ end # supports windows platform filesystem
234
+
235
+ shared_examples_for 'supports windows platform shell' do
236
+ # required by 'supports any platform shell'
237
+ def instrument_booted_at(booted_at)
238
+ # example:
239
+ # >echo | wmic OS Get LastBootUpTime 2>&1
240
+ # LastBootUpTime
241
+ # 20131025093127.375199-420
242
+ bat = ::Time.at(booted_at.to_i) # same bat time ...
243
+ platform_class.
244
+ should_receive(:execute).
245
+ with('echo | wmic OS Get LastBootUpTime 2>&1', {}).
246
+ and_return(
247
+ '%04d%02d%02d%02d%02d%02d.%06d%03d' %
248
+ [bat.year, bat.month, bat.day,
249
+ bat.hour, bat.min, bat.sec,
250
+ bat.usec, bat.utc_offset / 60]
251
+ )
252
+ end
253
+
254
+ it_should_behave_like 'supports any platform shell'
255
+
256
+ context 'paths' do
257
+ before(:each) do
258
+ # win32/dir-based constants.
259
+ flexmock(platform_class.filesystem).
260
+ should_receive(:sandbox_dir).
261
+ and_return('C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox')
262
+
263
+ # ENV-based constants.
264
+ @mock_env = flexmock(::ENV)
265
+ @mock_env.should_receive(:[]).
266
+ with('RS_RUBY_EXE').
267
+ and_return('C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe').
268
+ by_default
269
+ end
270
+
271
+ it 'should return path constants for windows' do
272
+ subject.null_output_name.should == 'NUL'
273
+ file_class.
274
+ should_receive(:normalize_path).
275
+ with('C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe').
276
+ and_return('C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe').
277
+ once
278
+ subject.sandbox_ruby.should == 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe'
279
+ end
280
+
281
+ it 'should generate right_link_home_dir when not set in ENV' do
282
+ @mock_env.should_receive(:[]).with('RS_RUBY_EXE').and_return(nil)
283
+ file_class.
284
+ should_receive(:normalize_path).
285
+ with('C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe').
286
+ and_return('C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe').
287
+ once
288
+ subject.sandbox_ruby.should == 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe'
289
+ end
290
+ end # paths
291
+
292
+ context 'commands' do
293
+ context '#format_script_file_name' do
294
+ let(:pathexts) { %w[.EXE .BAT] }
295
+ let(:pathext_env) { pathexts.join(';') }
296
+
297
+ before(:each) do
298
+ flexmock(::ENV).should_receive(:[]).with('PATHEXT').and_return(pathext_env)
299
+ end
300
+
301
+ it 'should format for powershell by default' do
302
+ subject.format_script_file_name('foo').should == 'foo.ps1'
303
+ end
304
+
305
+ it 'should keep extension when executable' do
306
+ subject.format_script_file_name('foo.bat').should == 'foo.bat'
307
+ end
308
+
309
+ it 'should append default extension when not executable' do
310
+ subject.format_script_file_name('foo.bar').should == 'foo.bar.ps1'
311
+ end
312
+ end
313
+
314
+ context '#format_executable_command' do
315
+ it 'should format using given script path' do
316
+ subject.format_executable_command('foo.bat', 'a/b', 'c d').should == 'foo.bat a/b "c d"'
317
+ end
318
+
319
+ it 'should insert cmd.exe if no extension was given' do
320
+ subject.format_executable_command('foo', 'bar', '1 2').should == 'cmd.exe /C "foo bar "1 2""'
321
+ end
322
+ end
323
+
324
+ context '#format_shell_command' do
325
+ it 'should insert powershell.exe when extension is .ps1' do
326
+ # RightRun runs child processes as 64-bit instead of 32-bit as would be
327
+ # the default behavior when creating a child process from ruby.exe
328
+ rrp = "C:\\PROGRA~1\\RIGHTS~1\\Shared\\RightRun.exe"
329
+ script_path = 'c:\temp\foo.ps1'
330
+ subject.should_receive(:right_run_path).and_return(rrp)
331
+
332
+ # we wrap powershell script execution with additional checks for
333
+ # $LastExitCode and $Error to ensure user script doesn't fail
334
+ # mysteriously without any kind of error reporting (i.e. it saves us
335
+ # some support calls).
336
+ expected_cmd =
337
+ "#{rrp} powershell.exe -command \"&{set-executionpolicy -executionPolicy RemoteSigned -Scope Process;" +
338
+ " &#{script_path} bar; if ($NULL -eq $LastExitCode) { $LastExitCode = 0 };" +
339
+ ' if ((0 -eq $LastExitCode) -and ($Error.Count -gt 0))' +
340
+ " { $RS_message = 'Script exited successfully but $Error contained '+($Error.Count)+' error(s):';" +
341
+ " write-output $RS_message; write-output $Error; $LastExitCode = 1 }; exit $LastExitCode}\""
342
+
343
+ subject.format_shell_command(script_path, 'bar').should == expected_cmd
344
+ end
345
+
346
+ it 'should insert ruby.exe when extension is .rb' do
347
+ ruby_exe_path = 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe'
348
+ subject.should_receive(:sandbox_ruby).and_return(ruby_exe_path)
349
+ subject.format_shell_command('foo.rb', 'bar').should == "#{ruby_exe_path} foo.rb bar"
350
+ end
351
+
352
+ it 'should format using given script path for other extensions' do
353
+ subject.format_shell_command('foo.bat', 'a/b', 'c d').should == 'foo.bat a/b "c d"'
354
+ end
355
+
356
+ it 'should insert cmd.exe if no extension was given' do
357
+ subject.format_shell_command('foo', 'bar', '1 2').should == 'cmd.exe /C "foo bar "1 2""'
358
+ end
359
+ end
360
+
361
+ context '#format_ruby_command' do
362
+ it 'should format for ruby' do
363
+ ruby_exe_path = 'C:/PROGRA~2/RIGHTS~1/RIGHTL~1/sandbox/ruby/bin/ruby.exe'
364
+ subject.should_receive(:sandbox_ruby).and_return(ruby_exe_path)
365
+ subject.format_ruby_command('foo.rb', 'bar').should == "#{ruby_exe_path} foo.rb bar"
366
+ end
367
+ end
368
+ end # commands
369
+ end # supports windows platform shell
370
+
371
+ shared_examples_for 'supports windows platform controller' do
372
+ context '#reboot' do
373
+ it 'should call InitiateSystemShutdown API' do
374
+ instrument_initiate_system_shutdown_api(true)
375
+ subject.reboot.should be_true
376
+ end
377
+ end # reboot
378
+
379
+ context '#shutdown' do
380
+ it 'should call InitiateSystemShutdown API' do
381
+ instrument_initiate_system_shutdown_api(false)
382
+ subject.shutdown.should be_true
383
+ end
384
+ end # shutdown
385
+ end # controller
386
+
387
+ shared_examples_for 'supports windows platform installer' do
388
+ context :install do
389
+ it 'should raise not implemented' do
390
+ expect { subject.install(%w[foo bar]) }.
391
+ to raise_error(
392
+ ::RightScale::Exceptions::PlatformError,
393
+ 'No package installers supported on Windows')
394
+ end
395
+ end # install
396
+ end # supports windows platform installer
397
+
398
+ shared_examples_for 'supports windows platform rng' do
399
+ context '#pseudorandom_bytes' do
400
+ it 'should generate random bytes using ruby under Windows' do
401
+ a = subject.pseudorandom_bytes(16)
402
+ b = subject.pseudorandom_bytes(16)
403
+ a.bytesize.should == 16
404
+ b.bytesize.should == 16
405
+ a.should_not == b # equality is statistically impossible
406
+ subject.pseudorandom_bytes(256).bytesize.should == 256
407
+ end
408
+ end # pseudorandom_bytes
409
+ end # supports windows platform rng
410
+
411
+ shared_examples_for 'supports windows platform process' do
412
+ context '#resident_set_size' do
413
+ it 'should return resident set size for current process' do
414
+ expected_size = 12345
415
+ instrument_get_process_memory_info_api(expected_size)
416
+ subject.resident_set_size.should == expected_size
417
+ end
418
+ end # pseudorandom_bytes
419
+ end # supports windows platform rng
420
+
421
+ shared_examples_for 'supports windows platform volume manager' do
422
+ let(:win2003_version) do
423
+ ::RightScale::Platform::WindowsSystemInformation::Version.new(5, 2, 3790)
424
+ end
425
+ let(:win2008r2_version) do
426
+ ::RightScale::Platform::WindowsSystemInformation::Version.new(6, 1, 7601)
427
+ end
428
+
429
+ before(:each) do
430
+ flexmock(platform_class.windows_system_information).
431
+ should_receive(:version).
432
+ and_return(win2008r2_version)
433
+ end
434
+
435
+ context :is_attachable_volume_path? do
436
+ it 'allows paths with hyphens and underscores' do
437
+ subject.is_attachable_volume_path?('C:\\Some_crazy-path').should == true
438
+ end
439
+
440
+ it 'allows paths with periods' do
441
+ subject.is_attachable_volume_path?('C:\\Some.crazy.path').should == true
442
+ end
443
+
444
+ it 'allows paths with tildes' do
445
+ subject.is_attachable_volume_path?('C:\\~Some~crazy~path').should == true
446
+ end
447
+ end
448
+
449
+ context :volumes do
450
+ let(:volumes_script) do
451
+ <<EOF
452
+ rescan
453
+ list volume
454
+ EOF
455
+ end
456
+
457
+ it 'can parse volumes from diskpart output' do
458
+ subject.
459
+ should_receive(:run_diskpart_script).
460
+ with(volumes_script, String).
461
+ and_return(
462
+ <<EOF
463
+ Volume ### Ltr Label Fs Type Size Status Info
464
+ ---------- --- ----------- ----- ---------- ------- --------- --------
465
+ Volume 0 C 2008Boot NTFS Partition 80 GB Healthy System
466
+ * Volume 1 D NTFS Partition 4094 MB Healthy
467
+ Volume 2 NTFS Partition 4094 MB Healthy
468
+ EOF
469
+ ).once
470
+ expected_volumes = [
471
+ { :index => 0, :device => 'C:', :label => '2008Boot', :filesystem => 'NTFS', :type => 'Partition', :total_size => 85899345920, :status => 'Healthy', :info => 'System' },
472
+ { :index => 1, :device => 'D:', :label => nil, :filesystem => 'NTFS', :type => 'Partition', :total_size => 4292870144, :status => 'Healthy', :info => nil },
473
+ { :index => 2, :device => nil, :label => nil, :filesystem => 'NTFS', :type => 'Partition', :total_size => 4292870144, :status => 'Healthy', :info => nil }
474
+ ]
475
+ subject.volumes.should == expected_volumes
476
+ end
477
+
478
+ it 'can parse volumes from diskpart output with mounted paths' do
479
+ subject.
480
+ should_receive(:run_diskpart_script).
481
+ with(volumes_script, String).
482
+ and_return(
483
+ <<EOF
484
+ Volume ### Ltr Label Fs Type Size Status Info
485
+ ---------- --- ----------- ----- ---------- ------- --------- --------
486
+ Volume 0 C NTFS Partition 80 GB Healthy System
487
+ * Volume 1 FAT32 Partition 1023 MB Healthy
488
+ C:\\Program Files\\RightScale\\Mount\\Softlayer\\
489
+ EOF
490
+ ).once
491
+ expected_volumes = [
492
+ { :index => 0, :device => 'C:', :label => nil, :filesystem => 'NTFS', :type => 'Partition', :total_size => 85899345920, :status => 'Healthy', :info => 'System' },
493
+ { :index => 1, :device => 'C:\\Program Files\\RightScale\\Mount\\Softlayer\\', :label => nil, :filesystem => 'FAT32', :type => 'Partition', :total_size => 1072693248, :status => 'Healthy', :info => nil }
494
+ ]
495
+ subject.volumes.should == expected_volumes
496
+ end
497
+
498
+ it 'raises a parser error when diskpart output is malformed' do
499
+ subject.
500
+ should_receive(:run_diskpart_script).
501
+ with(volumes_script, String).
502
+ and_return('gibberish').
503
+ once
504
+ expect { subject.volumes }.
505
+ to raise_error(RightScale::Platform::VolumeManager::ParserError)
506
+ end
507
+
508
+ it 'can filter results with only one condition' do
509
+ subject.
510
+ should_receive(:run_diskpart_script).
511
+ with(volumes_script, String).
512
+ and_return(
513
+ <<EOF
514
+ Volume ### Ltr Label Fs Type Size Status Info
515
+ ---------- --- ----------- ----- ---------- ------- --------- --------
516
+ Volume 0 C 2008Boot NTFS Partition 80 GB Healthy System
517
+ * Volume 1 D NTFS Partition 4094 MB Healthy
518
+ Volume 2 NTFS Partition 4094 MB Healthy
519
+ EOF
520
+ ).once
521
+ expected_volumes = [
522
+ { :index => 1, :device => 'D:', :label => nil, :filesystem => 'NTFS', :type => 'Partition', :total_size => 4292870144, :status => 'Healthy', :info => nil }
523
+ ]
524
+ subject.volumes(:device => 'D:').should == expected_volumes
525
+ end
526
+
527
+ it 'can filter results with many conditions' do
528
+ subject.
529
+ should_receive(:run_diskpart_script).
530
+ with(volumes_script, String).
531
+ and_return(
532
+ <<EOF
533
+ Volume ### Ltr Label Fs Type Size Status Info
534
+ ---------- --- ----------- ----- ---------- ------- --------- --------
535
+ Volume 0 C 2008Boot NTFS Partition 80 GB Healthy System
536
+ * Volume 1 D NTFS Partition 4094 MB Healthy
537
+ Volume 2 NTFS Partition 4094 MB Healthy
538
+ EOF
539
+ ).once
540
+ expected_volumes = [
541
+ {:index => 1, :device => 'D:', :label => nil, :filesystem => 'NTFS', :type => 'Partition', :total_size => 4292870144, :status => 'Healthy', :info => nil}
542
+ ]
543
+ conditions = { :device => 'D:', :filesystem => 'NTFS', :type => 'Partition' }
544
+ subject.volumes(conditions).should == expected_volumes
545
+ end
546
+ end
547
+
548
+ context :assign_device do
549
+ it 'assigns a device to a drive letter when a drive letter is specified' do
550
+ assign_device_script = <<EOF
551
+ rescan
552
+ list volume
553
+ select volume "0"
554
+ attribute volume clear readonly noerr
555
+
556
+ assign letter=S
557
+ EOF
558
+
559
+ subject.
560
+ should_receive(:run_diskpart_script).
561
+ with(assign_device_script, String).
562
+ and_return('').
563
+ once
564
+ subject.assign_device(0, 'S:')
565
+ end
566
+
567
+ it 'assigns a device to a path when a mount point is specified' do
568
+ assign_device_script = <<EOF
569
+ rescan
570
+ list volume
571
+ select volume "2"
572
+ attribute volume clear readonly noerr
573
+
574
+ assign mount="C:\\Program Files\\RightScale\\Mount\\Softlayer"
575
+ EOF
576
+ subject.
577
+ should_receive(:run_diskpart_script).
578
+ with(assign_device_script, String).
579
+ and_return('').
580
+ once
581
+ subject.assign_device(2, "C:\\Program Files\\RightScale\\Mount\\Softlayer")
582
+ end
583
+
584
+ it 'raises an exception when an invalid drive letter is specified' do
585
+ expect { subject.assign_device(0, 'C:') }.
586
+ to raise_error(RightScale::Platform::VolumeManager::ArgumentError)
587
+ end
588
+
589
+ it 'raises an exception when an invalid path is specified' do
590
+ expect { subject.assign_device(0, 'This is not a path') }.
591
+ to raise_error(RightScale::Platform::VolumeManager::ArgumentError)
592
+ end
593
+
594
+ it 'raises an exception when a mount path is specified and OS is pre 2008' do
595
+ subject.should_receive(:os_version).and_return(win2003_version)
596
+ expect { subject.assign_device(0, "C:\\Somepath") }.
597
+ to raise_error(RightScale::Platform::VolumeManager::ArgumentError)
598
+ end
599
+
600
+ it 'does not assign when already assigned by index' do
601
+ subject.should_receive(:run_diskpart_script).never
602
+ subject.
603
+ should_receive(:volumes).
604
+ and_return([{:index => '0', :device => "C:\\Program Files\\RightScale\\Mount\\Softlayer"}]).
605
+ once
606
+ subject.assign_device(0, "C:\\Program Files\\RightScale\\Mount\\Softlayer", :idempotent => true)
607
+ end
608
+
609
+ it 'does not assign when already assigned by device' do
610
+ subject.should_receive(:run_diskpart_script).never
611
+ subject.
612
+ should_receive(:volumes).
613
+ and_return([{:index => '0', :device => 'Z:'}]).
614
+ once
615
+ subject.assign_device('Z:', 'Z:', :idempotent => true)
616
+ end
617
+
618
+ it 'does not clear readonly flag if :clear_readonly option is set to false' do
619
+ assign_device_script = <<EOF
620
+ rescan
621
+ list volume
622
+ select volume "0"
623
+
624
+
625
+ assign mount="C:\\Program Files\\RightScale\\Mount\\Softlayer"
626
+ EOF
627
+ subject.
628
+ should_receive(:run_diskpart_script).
629
+ with(assign_device_script, String).
630
+ and_return('').
631
+ once
632
+ subject.assign_device(0, "C:\\Program Files\\RightScale\\Mount\\Softlayer", :clear_readonly => false)
633
+ end
634
+
635
+ it 'removes all previous assignments if :remove_all option is set to true' do
636
+ assign_device_script = <<EOF
637
+ rescan
638
+ list volume
639
+ select volume "0"
640
+ attribute volume clear readonly noerr
641
+ remove all noerr
642
+ assign mount="C:\\Program Files\\RightScale\\Mount\\Softlayer"
643
+ EOF
644
+ subject.
645
+ should_receive(:run_diskpart_script).
646
+ with(assign_device_script, String).
647
+ and_return('').
648
+ once
649
+ subject.assign_device(0, "C:\\Program Files\\RightScale\\Mount\\Softlayer", :remove_all => true)
650
+ end
651
+ end
652
+
653
+ context :format_disk do
654
+ it 'formats and assigns a drive to a drive letter when a drive letter is specified' do
655
+ assign_device_script = <<EOF
656
+ rescan
657
+ list disk
658
+ select disk 0
659
+ attribute disk clear readonly noerr
660
+ online disk noerr
661
+ clean
662
+ create partition primary
663
+ assign letter=S
664
+ format FS=NTFS quick
665
+ EOF
666
+ subject.
667
+ should_receive(:run_diskpart_script).
668
+ with(assign_device_script, String).
669
+ and_return('').
670
+ once
671
+ subject.format_disk(0, 'S:')
672
+ end
673
+
674
+ it 'formats and assigns a drive to a path when a mount point is specified' do
675
+ assign_device_script = <<EOF
676
+ rescan
677
+ list disk
678
+ select disk 0
679
+ attribute disk clear readonly noerr
680
+ online disk noerr
681
+ clean
682
+ create partition primary
683
+ assign mount="C:\\Somepath"
684
+ format FS=NTFS quick
685
+ EOF
686
+ subject.
687
+ should_receive(:run_diskpart_script).
688
+ with(assign_device_script, String).
689
+ and_return('').
690
+ once
691
+ subject.format_disk(0, 'C:\\Somepath')
692
+ end
693
+
694
+ it 'raises an exception when a mount path is specified and OS is pre 2008' do
695
+ subject.should_receive(:os_version).and_return(win2003_version)
696
+ expect { subject.format_disk(0, "C:\\Somepath") }.
697
+ to raise_error(RightScale::Platform::VolumeManager::ArgumentError)
698
+ end
699
+ end # format_disk
700
+
701
+ context :online_disk do
702
+ it 'does not online the disk if the disk is already online' do
703
+ online_disk_script = <<EOF
704
+ rescan
705
+ list disk
706
+ select disk 0
707
+ attribute disk clear readonly noerr
708
+ online disk noerr
709
+ EOF
710
+ subject.
711
+ should_receive(:run_diskpart_script).
712
+ with(online_disk_script, String).
713
+ and_return('').
714
+ once
715
+ subject.online_disk(0)
716
+ subject.should_receive(:disks).and_return([{:index => 0, :status => 'Online'}]).once
717
+ subject.online_disk(0, :idempotent => true)
718
+ end
719
+ end
720
+ end # supports windows platform volume manager