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,319 @@
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(File.join(File.dirname(__FILE__), 'spec_helper'))
24
+
25
+ describe RightScale::AgentTagManager do
26
+
27
+ include FlexMock::ArgumentTypes
28
+
29
+ before(:each) do
30
+ @log = flexmock(RightScale::Log)
31
+ @log.should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
32
+ @identity = "rs-agent-1-1"
33
+ @agent_href = "/api/clouds/1/instances/1"
34
+ @agent_href2 = "/api/clouds/2/instances/2"
35
+ @agent = flexmock("agent", :self_href => @agent_href, :identity => @identity)
36
+ @hrefs = [@agent_href, @agent_href2]
37
+ @manager = RightScale::AgentTagManager.instance
38
+ @manager.agent = @agent
39
+ @request = flexmock("request", :run => true)
40
+ @request.should_receive(:callback).and_yield("result").by_default
41
+ @request.should_receive(:errback).by_default
42
+ @request.should_receive(:raw_response).and_return("raw response").by_default
43
+ @retryable_request = flexmock(RightScale::RetryableRequest)
44
+ @tag = "some:tag=value"
45
+ @tag1 = "other:tag=value"
46
+ @tags = [@tag, @tag1]
47
+ @result = nil
48
+ end
49
+
50
+ context :tags do
51
+
52
+ before(:each) do
53
+ @retryable_request.should_receive(:new).with("/router/query_tags",
54
+ {:agent_identity => @identity, :hrefs => [@agent_href]}, {}).and_return(@request).once.by_default
55
+ end
56
+
57
+ it "retrieves current agent tags" do
58
+ @request.should_receive(:callback).and_yield({@agent_href => {"tags" => [@tag]}}).once
59
+ @manager.tags { |r| @result = r }
60
+ @result.should == [@tag]
61
+ end
62
+
63
+ it "returns empty array when there is no results hash" do
64
+ @request.should_receive(:callback).and_yield({}).once
65
+ @manager.tags { |r| @result = r }
66
+ @result.should == []
67
+ end
68
+
69
+ it "returns the raw result when result is not a hash" do
70
+ @request.should_receive(:callback).and_yield("result").once
71
+ @manager.tags { |r| @result = r }
72
+ @result.should == "result"
73
+ end
74
+
75
+ it "returns raw result when :raw option specified" do
76
+ @request.should_receive(:callback).and_yield("result").once
77
+ @request.should_receive(:raw_response).and_return("raw response").once
78
+ @manager.tags(:raw => true) { |r| @result = r }
79
+ @result.should == "raw response"
80
+ end
81
+
82
+ it "forwards timeout option" do
83
+ @retryable_request.should_receive(:new).with("/router/query_tags",
84
+ {:agent_identity => @identity, :hrefs => [@agent_href]}, {:timeout => 9}).and_return(@request).once
85
+ @request.should_receive(:callback).and_yield({@agent_href => {"tags" => [@tag]}}).once
86
+ @manager.tags(:timeout => 9) { |r| @result = r }
87
+ @result.should == [@tag]
88
+ end
89
+
90
+ it "yields error result and logs error" do
91
+ @log.should_receive(:error).with(/Failed to query tags/).once
92
+ @request.should_receive(:errback).and_yield("error").once
93
+ @request.should_receive(:callback).once
94
+ @manager.tags { |r| @result = r }
95
+ @result.should == "error"
96
+ end
97
+ end
98
+
99
+ context :query_tags do
100
+
101
+ it "queries for agents having individual tag" do
102
+ @retryable_request.should_receive(:new).with("/router/query_tags",
103
+ {:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
104
+ @request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}).once
105
+ @manager.query_tags(@tag) { |r| @result = r }
106
+ @result.should == {@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}
107
+ end
108
+
109
+ it "queries for agents having multiple tags" do
110
+ @retryable_request.should_receive(:new).with("/router/query_tags",
111
+ {:agent_identity => @identity, :tags => @tags}, {}).and_return(@request).once
112
+ @request.should_receive(:callback).and_yield({@agent_href => {"tags" => @tags}}).once
113
+ @manager.query_tags(@tags) { |r| @result = r }
114
+ @result.should == {@agent_href => {"tags" => @tags}}
115
+ end
116
+
117
+ it "forwards options" do
118
+ @retryable_request.should_receive(:new).with("/router/query_tags",
119
+ {:agent_identity => @identity, :tags => @tags}, {:timeout => 9}).and_return(@request).once
120
+ @request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}}).once
121
+ @request.should_receive(:raw_response).and_return("raw response").once
122
+ @manager.query_tags(@tags, :raw => true, :timeout => 9) { |r| @result = r }
123
+ @result.should == "raw response"
124
+ end
125
+
126
+ it "yields error result and logs error" do
127
+ @retryable_request.should_receive(:new).with("/router/query_tags",
128
+ {:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
129
+ @log.should_receive(:error).with(/Failed to query tags/).once
130
+ @request.should_receive(:errback).and_yield("error").once
131
+ @request.should_receive(:callback).once
132
+ @manager.query_tags(@tag) { |r| @result = r }
133
+ @result.should == "error"
134
+ end
135
+ end
136
+
137
+ context :query_tags_raw do
138
+
139
+ before(:each) do
140
+ @request.should_receive(:raw_response).and_return("raw response").once
141
+ end
142
+
143
+ it "always yields raw response" do
144
+ @retryable_request.should_receive(:new).with("/router/query_tags",
145
+ {:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
146
+ @request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}).once
147
+ @manager.query_tags_raw(@tag) { |r| @result = r }
148
+ @result.should == "raw response"
149
+ end
150
+
151
+ it "queries for agents having individual tag and always yields raw response" do
152
+ @retryable_request.should_receive(:new).with("/router/query_tags",
153
+ {:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
154
+ @request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}).once
155
+ @manager.query_tags_raw(@tag) { |r| @result = r }
156
+ @result.should == "raw response"
157
+ end
158
+
159
+ it "queries for agents having multiple tags always yields raw response" do
160
+ @retryable_request.should_receive(:new).with("/router/query_tags",
161
+ {:agent_identity => @identity, :tags => @tags}, {}).and_return(@request).once
162
+ @request.should_receive(:callback).and_yield({@agent_href => {"tags" => @tags}}).once
163
+ @manager.query_tags_raw(@tags) { |r| @result = r }
164
+ @result.should == "raw response"
165
+ end
166
+
167
+ it "queries for selected agents" do
168
+ @retryable_request.should_receive(:new).with("/router/query_tags",
169
+ {:agent_identity => @identity, :hrefs => @hrefs, :tags => @tags}, {}).and_return(@request).once
170
+ @request.should_receive(:callback).and_yield({@agent_href => {"tags" => @tags}}).once
171
+ @manager.query_tags_raw(@tags, @hrefs) { |r| @result = r }
172
+ @result.should == "raw response"
173
+ end
174
+
175
+ it "forwards timeout option" do
176
+ @retryable_request.should_receive(:new).with("/router/query_tags",
177
+ {:agent_identity => @identity, :tags => @tags}, {:timeout => 9}).and_return(@request).once
178
+ @request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}}).once
179
+ @manager.query_tags_raw(@tags, nil, :timeout => 9) { |r| @result = r }
180
+ @result.should == "raw response"
181
+ end
182
+ end
183
+
184
+ context :add_tags do
185
+
186
+ before(:each) do
187
+ @request.should_receive(:raw_response).and_return("raw response").once
188
+ @agent.should_receive(:tags).and_return([]).once.by_default
189
+ @agent.should_receive(:tags=).once.by_default
190
+ end
191
+
192
+ it "adds individual tag to agent" do
193
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
194
+ @manager.add_tags(@tag).should be_true
195
+ end
196
+
197
+ it "adds multiple tags to agent" do
198
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => @tags}).and_return(@request).once
199
+ @manager.add_tags(@tags).should be_true
200
+ end
201
+
202
+ it "optionally yields raw response" do
203
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => @tags}).and_return(@request).once
204
+ @request.should_receive(:callback).and_yield("result").once
205
+ @manager.add_tags(@tags) { |r| @result = r }
206
+ @result.should == "raw response"
207
+ end
208
+
209
+ it "updates local tags" do
210
+ @agent.should_receive(:tags).and_return([@tag1]).once
211
+ @agent.should_receive(:tags=).should_receive([@tag]).once
212
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
213
+ @manager.add_tags(@tag).should be_true
214
+ end
215
+ end
216
+
217
+ context :remove_tags do
218
+
219
+ before(:each) do
220
+ @request.should_receive(:raw_response).and_return("raw response").once
221
+ @agent.should_receive(:tags).and_return([@tag]).once.by_default
222
+ @agent.should_receive(:tags=).once.by_default
223
+ end
224
+
225
+ it "removes individual tag to agent" do
226
+ @retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => [@tag]}).and_return(@request).once
227
+ @manager.remove_tags(@tag).should be_true
228
+ end
229
+
230
+ it "removes multiple tags to agent" do
231
+ @retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => @tags}).and_return(@request).once
232
+ @manager.remove_tags(@tags).should be_true
233
+ end
234
+
235
+ it "optionally yields raw response" do
236
+ @retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => @tags}).and_return(@request).once
237
+ @request.should_receive(:callback).and_yield("result").once
238
+ @manager.remove_tags(@tags) { |r| @result = r }
239
+ @result.should == "raw response"
240
+ end
241
+
242
+ it "updates local tags" do
243
+ @agent.should_receive(:tags).and_return([]).once
244
+ @agent.should_receive(:tags=).should_receive([@tag]).once
245
+ @retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => [@tag]}).and_return(@request).once
246
+ @manager.remove_tags(@tag).should be_true
247
+ end
248
+ end
249
+
250
+ context :do_update do
251
+
252
+ before(:each) do
253
+ @agent.should_receive(:tags).and_return([]).once.by_default
254
+ end
255
+
256
+ it "checks that agent has been set" do
257
+ @manager.agent = nil
258
+ @agent.should_receive(:tags).never
259
+ lambda { @manager.send(:do_update, [@tag], []) }.should \
260
+ raise_error(ArgumentError, "Must set agent= before using tag manager")
261
+ end
262
+
263
+ it "does not allow both add and removal of tags in same request" do
264
+ @agent.should_receive(:tags).never
265
+ lambda { @manager.send(:do_update, [@tag], [@tag1]) }.should \
266
+ raise_error(ArgumentError, "Cannot add and remove tags in same update")
267
+ end
268
+
269
+ it "adds tags for agent" do
270
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
271
+ @agent.should_receive(:tags=).never
272
+ @manager.send(:do_update, [@tag], []).should be_true
273
+ end
274
+
275
+ it "removes tags for agent" do
276
+ @retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => [@tag1]}).and_return(@request).once
277
+ @agent.should_receive(:tags=).never
278
+ @manager.send(:do_update, [], [@tag1]).should be_true
279
+ end
280
+
281
+ it "yields raw response if block given" do
282
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
283
+ @request.should_receive(:raw_response).and_return("raw response").once
284
+ @agent.should_receive(:tags=).once
285
+ @manager.send(:do_update, [@tag], []) { |r| @result = r }
286
+ @result.should == "raw response"
287
+ end
288
+
289
+ it "updates local tags if block given and successful" do
290
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
291
+ @request.should_receive(:raw_response).and_return("raw response").once
292
+ @agent.should_receive(:tags=).with([@tag]).once
293
+ @manager.send(:do_update, [@tag], []) { |r| @result = r }
294
+ @result.should == "raw response"
295
+ end
296
+
297
+ it "yields error result and does not update local tags" do
298
+ @retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
299
+ @request.should_receive(:raw_response).and_return("error").once
300
+ @request.should_receive(:errback).and_yield("error").once
301
+ @request.should_receive(:callback).once
302
+ @agent.should_receive(:tags=).never
303
+ @manager.send(:do_update, [@tag], []) { |r| @result = r }
304
+ @result.should == "error"
305
+ end
306
+ end
307
+
308
+ context :clear do
309
+
310
+ it "clears all agent tags" do
311
+ @request.should_receive(:raw_response).and_return("raw response").once
312
+ @agent.should_receive(:tags).and_return(@tags).twice
313
+ @agent.should_receive(:tags=).with([]).once
314
+ @retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => @tags}).and_return(@request).once
315
+ @manager.clear { |r| @result = r }
316
+ @result.should == "raw response"
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,423 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright (c) 2013 RightScale Inc
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
27
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'right_agent', 'clients', 'api_client'))
28
+
29
+ describe RightScale::ApiClient do
30
+
31
+ include FlexMock::ArgumentTypes
32
+
33
+ before(:each) do
34
+ @log = flexmock(RightScale::Log)
35
+ @log.should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
36
+ @log.should_receive(:warning).by_default.and_return { |m| raise RightScale::Log.format(*m) }
37
+ @timer = flexmock("timer", :cancel => true, :interval= => 0).by_default
38
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield.by_default
39
+ @account_id = 123
40
+ @agent_id = "rs-instance-1-1"
41
+ @agent_href = "/api/clouds/1/instances/1"
42
+ @agent_href2 = "/api/clouds/2/instances/2"
43
+ @links = {"links" => [{"rel" => "self", "href" => @agent_href}]}
44
+ @http_client = flexmock("http client", :get => @links, :check_health => true).by_default
45
+ flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).by_default
46
+ @url = "http://test.com"
47
+ @auth_header = {"Authorization" => "Bearer <session>"}
48
+ @auth_client = AuthClientMock.new(@url, @auth_header, :authorized, @account_id, @agent_id)
49
+ @options = {}
50
+ @client = RightScale::ApiClient.new(@auth_client, @options)
51
+ @version = RightScale::AgentConfig.protocol_version
52
+ @payload = {:agent_identity => @agent_id}
53
+ @target = nil
54
+ @token = "random token"
55
+ end
56
+
57
+ context :initialize do
58
+ it "initializes options" do
59
+ @options = {
60
+ :open_timeout => 1,
61
+ :request_timeout => 2,
62
+ :listen_timeout => 3,
63
+ :retry_timeout => 4,
64
+ :retry_intervals => [1, 2, 3],
65
+ :reconnect_interval => 5 }
66
+ @client = RightScale::ApiClient.new(@auth_client, @options)
67
+ options = @client.instance_variable_get(:@options)
68
+ options[:server_name] = "RightApi"
69
+ options[:api_version] = "1.5"
70
+ options[:open_timeout] = 1
71
+ options[:request_timeout] = 2
72
+ options[:retry_timeout] = 3
73
+ options[:retry_intervals] = [1, 2, 3]
74
+ options[:reconnect_interval] = 4
75
+ end
76
+ end
77
+
78
+ context :push do
79
+ it "makes mapped request" do
80
+ flexmock(@client).should_receive(:make_request).with(:post, "/audit_entries/111/append", {:detail => "details"},
81
+ "update_entry", @token, Hash).and_return(nil).once
82
+ @client.push("/auditor/update_entry", @payload.merge(:audit_id => 111, :detail => "details"), @target, @token).should be_nil
83
+ end
84
+
85
+ it "does not require token" do
86
+ flexmock(@client).should_receive(:make_request).with(:post, "/audit_entries/111/append", {:detail => "details"},
87
+ "update_entry", nil, Hash).and_return(nil).once
88
+ @client.push("/auditor/update_entry", @payload.merge(:audit_id => 111, :detail => "details"), @target).should be_nil
89
+ end
90
+ end
91
+
92
+ context :request do
93
+ it "makes mapped request" do
94
+ flexmock(@client).should_receive(:make_request).with(:post, "/right_net/booter/declare", {:r_s_version => @version},
95
+ "declare", @token, Hash).and_return(nil).once
96
+ @client.push("/booter/declare", @payload.merge(:r_s_version => @version), @target, @token).should be_nil
97
+ end
98
+
99
+ it "maps query_tags request" do
100
+ flexmock(@client).should_receive(:map_query_tags).with(:post, {:tags => ["a:b=c"]}, "query_tags", @token, Hash).
101
+ and_return({}).once
102
+ @client.request("/router/query_tags", @payload.merge(:tags => ["a:b=c"]), @target, @token).should == {}
103
+ end
104
+
105
+ it "does not require token" do
106
+ flexmock(@client).should_receive(:make_request).with(:post, "/right_net/booter/declare", {:r_s_version => @version},
107
+ "declare", nil, Hash).and_return(nil).once
108
+ @client.push("/booter/declare", @payload.merge(:r_s_version => @version), @target).should be_nil
109
+ end
110
+ end
111
+
112
+ context :support? do
113
+ it "returns true if request type is supported" do
114
+ @client.support?("/booter/declare").should be_true
115
+ end
116
+
117
+ it "returns false if request type is not supported" do
118
+ @client.support?("/instance_scheduler/execute").should be_false
119
+ end
120
+ end
121
+
122
+ context :map_request do
123
+ it "raises if request type not supported" do
124
+ lambda { @client.send(:map_request, "/instance_scheduler/execute", @payload, @token) }.should \
125
+ raise_error(ArgumentError, "Unsupported request type: /instance_scheduler/execute")
126
+ end
127
+
128
+ it "makes request" do
129
+ flexmock(@client).should_receive(:make_request).with(:post, "/right_net/booter/declare", {:r_s_version => @version},
130
+ "declare", @token, Hash).and_return(nil).once
131
+ @client.send(:map_request, "/booter/declare", @payload.merge(:r_s_version => @version), @token).should be_nil
132
+ end
133
+
134
+ it "returns mapped response" do
135
+ flexmock(@client).should_receive(:make_request).with(:post, "/audit_entries",
136
+ {:audit_entry => {:auditee_href => @agent_href, :summary => "summary"}}, "create_entry", @token, Hash).
137
+ and_return("/api/audit_entries/111").once
138
+ @client.send(:map_request, "/auditor/create_entry", @payload.merge(:summary => "summary"), @token).should == "111"
139
+ end
140
+ end
141
+
142
+ context :map_response do
143
+ it "converts audit entry href in result to an audit ID" do
144
+ response = "/api/audit_entries/111"
145
+ @client.send(:map_response, response, "/audit_entries").should == "111"
146
+ end
147
+
148
+ it "converts tag query result to list of tags for resource" do
149
+ response = [
150
+ { "actions" => [],
151
+ "links" => [{"rel" => "resource", "href" => "/api/clouds/6/instances/CUPVAL7KUP7TF"}],
152
+ "tags" => [{"name" => "rs_agent_dev:log_level=debug"},
153
+ {"name" => "rs_login:state=restricted"},
154
+ {"name" => "rs_monitoring:state=active"}] },
155
+ { "actions" => [],
156
+ "links" => [{"rel" => "resource", "href" => "/api/servers/20"}],
157
+ "tags" => [{"name" => "server:ready=now"},
158
+ {"name" => "rs_agent_dev:log_level=debug"}] } ]
159
+ @client.send(:map_response, response, "/tags/by_resource").should ==
160
+ { "/api/clouds/6/instances/CUPVAL7KUP7TF" => { "tags" => ["rs_agent_dev:log_level=debug",
161
+ "rs_login:state=restricted",
162
+ "rs_monitoring:state=active"] } }
163
+ end
164
+ end
165
+
166
+ context "query tags" do
167
+ before(:each) do
168
+ @action = "query_tags"
169
+ @options = {}
170
+ @tags = ["a:b=c"]
171
+ @hrefs = [@agent_href2]
172
+ @response = [
173
+ { "actions" => [],
174
+ "links" => [{"rel" => "resource", "href" => @agent_href}],
175
+ "tags" => [{"name" => "a:b=c"}, {"name" => "x:y=z"}] } ]
176
+ end
177
+
178
+ context :map_query_tags do
179
+ it "retrieves resource hrefs for specified tags" do
180
+ params = {:tags => @tags}
181
+ params2 = params.merge(:match_all => false, :resource_type => "instances")
182
+ flexmock(@client).should_receive(:query_by_resource).never
183
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_tag", params2, @action, @token, @options).and_return({}).once
184
+ @client.send(:map_query_tags, :post, params, @action, @token, @options).should == {}
185
+ end
186
+
187
+ it "appends retrieved hrefs to any specified resource hrefs" do
188
+ params = {:tags => @tags, :resource_hrefs => @hrefs}
189
+ params2 = {:resource_hrefs => [@agent_href2, @agent_href]}
190
+ flexmock(@client).should_receive(:query_by_tag).with(:post, @tags, @action, @token, @options).and_return([@agent_href]).once
191
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_resource", params2, @action, @token, @options).and_return({}).once
192
+ @client.send(:map_query_tags, :post, params, @action, @token, @options).should == {}
193
+ end
194
+
195
+ it "queries for tags for each resource href" do
196
+ params = {:resource_hrefs => @hrefs}
197
+ flexmock(@client).should_receive(:query_by_tag).never
198
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_resource", params, @action, @token, @options).and_return(@response).once
199
+ @client.send(:map_query_tags, :post, params, @action, @token, @options).should == {@agent_href => {"tags" => ["a:b=c", "x:y=z"]}}
200
+ end
201
+ end
202
+
203
+ context :query_by_tag do
204
+ before(:each) do
205
+ @params = {:tags => @tags}
206
+ @params2 = @params.merge(:match_all => false, :resource_type => "instances")
207
+ end
208
+
209
+ it "queries for tags using specified tags" do
210
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_tag", @params2, @action, @token, @options).and_return({}).once
211
+ @client.send(:query_by_tag, :post, @tags, @action, @token, @options).should == []
212
+ end
213
+
214
+ it "maps response" do
215
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_tag", @params2, @action, @token, @options).and_return(@response).once
216
+ @client.send(:query_by_tag, :post, @tags, @action, @token, @options).should == [@agent_href]
217
+ end
218
+ end
219
+
220
+ context :query_by_resource do
221
+ before(:each) do
222
+ @params = {:resource_hrefs => @hrefs}
223
+ end
224
+
225
+ it "queries for tags using specified hrefs" do
226
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_resource", @params, @action, @token, @options).and_return({}).once
227
+ @client.send(:query_by_resource, :post, @hrefs, @action, @token, @options).should == {}
228
+ end
229
+
230
+ it "maps response" do
231
+ flexmock(@client).should_receive(:make_request).with(:post, "/tags/by_resource", @params, @action, @token, @options).and_return(@response).once
232
+ @client.send(:query_by_resource, :post, @hrefs, @action, @token, @options).should == {@agent_href => {"tags" => ["a:b=c", "x:y=z"]}}
233
+ end
234
+ end
235
+ end
236
+
237
+ context :parameterize do
238
+
239
+ context "for audits" do
240
+ before(:each) do
241
+ @path, @params, @options = @client.send(:parameterize, "auditor", "update_entry", @payload.merge(:audit_id => 111,
242
+ :detail => "details"), "/audit_entries/:id/append")
243
+ end
244
+
245
+ it "converts audit parameters" do
246
+ @params.should == {:detail => "details"}
247
+ end
248
+
249
+ it "substitutes audit ID into path" do
250
+ @path.should == "/audit_entries/111/append"
251
+ end
252
+
253
+ it "adds parameter filter to options" do
254
+ @options.should == {:filter_params => ["detail", "text"]}
255
+ end
256
+ end
257
+
258
+ context "for tags" do
259
+ before(:each) do
260
+ tags = ["a:b=c", nil, [nil, "x:y=z"]]
261
+ @path, @params, @options = @client.send(:parameterize, "router", "add_tags", @payload.merge(:tags => tags),
262
+ "/tags/multi_add")
263
+ end
264
+
265
+ it "adds default resource href to parameters" do
266
+ @params[:resource_hrefs].should == [@agent_href]
267
+ end
268
+
269
+ it "adds specified resource hrefs to parameters" do
270
+ hrefs = [@agent_href, @agent_href2]
271
+ _, @params, _ = @client.send(:parameterize, "router", "query_tags", @payload.merge(:hrefs => hrefs),
272
+ "/tags/by_resource")
273
+ @params[:resource_hrefs].should == hrefs
274
+ end
275
+
276
+ it "ensures that tags parameter is properly formed" do
277
+ @params[:tags].should == ["a:b=c", "x:y=z"]
278
+ end
279
+
280
+ it "does not add tags if not present" do
281
+ _, @params, _ = @client.send(:parameterize, "router", "query_tags", @payload, "/tags/multi_add")
282
+ @params.should_not have_key(:tags)
283
+ end
284
+ end
285
+
286
+ context "otherwise" do
287
+ before(:each) do
288
+ @path, @params, @options = @client.send(:parameterize, "booter", "declare", @payload.merge(:r_s_version => @version),
289
+ "/right_net/booter/declare")
290
+ end
291
+
292
+ it "removes :agent_identity parameter" do
293
+ @params[:agent_identity].should be_nil
294
+ end
295
+ end
296
+ end
297
+
298
+ context :parameterize_audit do
299
+
300
+ context "create_entry" do
301
+ it "stores instance href" do
302
+ @client.send(:parameterize_audit, "create_entry", @payload)[:audit_entry][:auditee_href].should == @agent_href
303
+ end
304
+
305
+ context "summary" do
306
+ it "stores summary if non-blank" do
307
+ @client.send(:parameterize_audit, "create_entry", :summary => "hello")[:audit_entry][:summary].should == "hello"
308
+ @client.send(:parameterize_audit, "create_entry", :summary => "")[:audit_entry].should_not have_key(:summary)
309
+ @client.send(:parameterize_audit, "create_entry", {})[:audit_entry].should_not have_key(:summary)
310
+ end
311
+
312
+ it "truncates summary if too long" do
313
+ @client.send(:parameterize_audit, "create_entry", :summary => "hello " * 50)[:audit_entry][:summary].size.should == 255
314
+ end
315
+ end
316
+
317
+ it "stores detail if non-blank" do
318
+ @client.send(:parameterize_audit, "create_entry", :detail => "details")[:audit_entry][:detail].should == "details"
319
+ @client.send(:parameterize_audit, "create_entry", :detail => "")[:audit_entry].should_not have_key(:detail)
320
+ @client.send(:parameterize_audit, "create_entry", {})[:audit_entry].should_not have_key(:detail)
321
+ end
322
+
323
+ it "stores user email if non-blank" do
324
+ @client.send(:parameterize_audit, "create_entry", :user_email => "email")[:user_email].should == "email"
325
+ @client.send(:parameterize_audit, "create_entry", :user_email => "").should_not have_key(:user_email)
326
+ @client.send(:parameterize_audit, "create_entry", {}).should_not have_key(:user_email)
327
+ end
328
+
329
+ it "stores notify category if present" do
330
+ @client.send(:parameterize_audit, "create_entry", :category => "Notification")[:notify].should == "Notification"
331
+ @client.send(:parameterize_audit, "create_entry", {}).should_not have_key(:notify)
332
+ end
333
+ end
334
+
335
+ context "update_entry" do
336
+ it "stores offset if present" do
337
+ @client.send(:parameterize_audit, "update_entry", :offset => 100)[:offset].should == 100
338
+ @client.send(:parameterize_audit, "update_entry", {}).should_not have_key(:offset)
339
+ end
340
+
341
+ context "summary" do
342
+ it "stores summary if non-blank" do
343
+ @client.send(:parameterize_audit, "update_entry", :summary => "hello")[:summary].should == "hello"
344
+ @client.send(:parameterize_audit, "update_entry", :summary => "").should_not have_key(:summary)
345
+ @client.send(:parameterize_audit, "update_entry", {}).should_not have_key(:summary)
346
+ end
347
+
348
+ it "truncates summary if too long" do
349
+ @client.send(:parameterize_audit, "update_entry", :summary => "hello " * 50)[:summary].size.should == 255
350
+ end
351
+
352
+ it "stores notify category if present and summary is non-blank" do
353
+ @client.send(:parameterize_audit, "update_entry", :summary => "hello", :category => "Notification")[:notify].should == "Notification"
354
+ @client.send(:parameterize_audit, "update_entry", :category => "Notification").should_not have_key(:notify)
355
+ end
356
+ end
357
+
358
+ it "stores detail if non-blank" do
359
+ @client.send(:parameterize_audit, "update_entry", :detail => "details")[:detail].should == "details"
360
+ @client.send(:parameterize_audit, "update_entry", :detail => "").should_not have_key(:detail)
361
+ @client.send(:parameterize_audit, "update_entry", {}).should_not have_key(:detail)
362
+ end
363
+ end
364
+
365
+ context "otherwise" do
366
+ it "raises unknown audit" do
367
+ lambda { @client.send(:parameterize_audit, "bogus", {}) }.should raise_error(ArgumentError)
368
+ end
369
+ end
370
+ end
371
+
372
+ context :truncate do
373
+ it "returns non-string as is" do
374
+ @client.send(:truncate, nil, 5).should == nil
375
+ end
376
+
377
+ it "returns strings shorter than limit as is" do
378
+ @client.send(:truncate, "hello", 5).should == "hello"
379
+ end
380
+
381
+ it "requires max length to be greater than 3" do
382
+ @client.send(:truncate, "hello", 4).should == "h..."
383
+ lambda { @client.send(:truncate, "hello", 3) }.should raise_error(ArgumentError)
384
+ end
385
+
386
+ it "truncates strings that are too long" do
387
+ @client.send(:truncate, "how you doing", 10).bytesize.should == 10
388
+ end
389
+
390
+ it "ends truncated string with an ellipsis" do
391
+ @client.send(:truncate, "how you doing", 10).should == "how you..."
392
+ end
393
+
394
+ it "accounts for multi-byte characters" do
395
+ @client.send(:truncate, "Schös Tägli wünschi", 20).should == "Schös Tägli wü..."
396
+ @client.send(:truncate, "Schös Tägli wünschi", 19).should == "Schös Tägli w..."
397
+ @client.send(:truncate, "Schös Tägli wünschi", 18).should == "Schös Tägli w..."
398
+ @client.send(:truncate, "Schös Tägli wünschi", 17).should == "Schös Tägli ..."
399
+ end
400
+ end
401
+
402
+ context :non_blank do
403
+ it "returns nil if value nil" do
404
+ @client.send(:non_blank, nil).should be_nil
405
+ end
406
+
407
+ it "returns nil if value is empty" do
408
+ @client.send(:non_blank, "").should be_nil
409
+ end
410
+
411
+ it "returns nil if value nil" do
412
+ @client.send(:non_blank, "hello").should == "hello"
413
+ end
414
+ end
415
+
416
+ context :enable_use do
417
+ it "makes API request to get links for setting instance href" do
418
+ flexmock(@client).should_receive(:make_request).with(:get, "/sessions/instance", {}, "instance").and_return(@links).once
419
+ @client.instance_variable_get(:@self_href).should == @agent_href
420
+ @client.send(:enable_use).should be_true
421
+ end
422
+ end
423
+ end