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,300 @@
1
+ #
2
+ # Copyright (c) 2009-2011 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
+
24
+ module RightScale
25
+
26
+ # Container for status and result of an operation
27
+ class OperationResult
28
+
29
+ include Serializable
30
+
31
+ # Result status code
32
+ SUCCESS = 0
33
+ ERROR = 1
34
+ CONTINUE = 2
35
+ RETRY = 3
36
+ NON_DELIVERY = 4
37
+ MULTICAST = 5 # Deprecated for agents at version 13 or above
38
+ CANCEL = 6
39
+
40
+ # Non-delivery reasons
41
+ NON_DELIVERY_REASONS = [
42
+ NO_TARGET = "no target",
43
+ UNKNOWN_TARGET = "unknown target",
44
+ NO_ROUTE_TO_TARGET = "no route to target",
45
+ TARGET_NOT_CONNECTED = "target not connected",
46
+ TTL_EXPIRATION = "TTL expiration",
47
+ RETRY_TIMEOUT = "retry timeout"
48
+ ]
49
+
50
+ # Maximum characters included in display of error
51
+ MAX_ERROR_SIZE = 60
52
+
53
+ # (Integer) Status code
54
+ attr_accessor :status_code
55
+
56
+ # (Object) Result data, if any
57
+ attr_accessor :content
58
+
59
+ def initialize(*args)
60
+ @status_code = args[0]
61
+ @content = args[1] if args.size > 1
62
+ end
63
+
64
+ # User friendly result
65
+ # Does not include content except in the case of error or non-delivery
66
+ #
67
+ # === Return
68
+ # (String):: Name of result code
69
+ def to_s
70
+ status(reason = true)
71
+ end
72
+
73
+ # User friendly result status
74
+ #
75
+ # === Parameters
76
+ # reason(Boolean):: Whether to include failure reason information, default to false
77
+ #
78
+ # === Return
79
+ # (String):: Name of result code
80
+ def status(reason = false)
81
+ case @status_code
82
+ when SUCCESS then 'success'
83
+ when ERROR then 'error' + (reason ? " (#{truncated_error})" : "")
84
+ when CONTINUE then 'continue'
85
+ when RETRY then 'retry' + (reason ? " (#{@content})" : "")
86
+ when NON_DELIVERY then 'non-delivery' + (reason ? " (#{@content})" : "")
87
+ when MULTICAST then 'multicast'
88
+ when CANCEL then 'cancel' + (reason ? " (#{@content})" : "")
89
+ end
90
+ end
91
+
92
+ # Limited length error string
93
+ #
94
+ # === Return
95
+ # e(String):: String of no more than MAX_ERROR_SIZE characters
96
+ def truncated_error
97
+ e = @content.is_a?(String) ? @content : @content.inspect
98
+ e = e[0, MAX_ERROR_SIZE - 3] + "..." if e.size > (MAX_ERROR_SIZE - 3)
99
+ e
100
+ end
101
+
102
+ # Instantiate from request result
103
+ # Ignore all but first result if result is a hash
104
+ #
105
+ # === Parameters
106
+ # result(Result|Hash|OperationResult|nil):: Result or the Result "results" field
107
+ #
108
+ # === Return
109
+ # (RightScale::OperationResult):: Converted operation result
110
+ def self.from_results(result)
111
+ r = result.is_a?(Result) ? result.results : result
112
+ if r && r.respond_to?(:status_code) && r.respond_to?(:content)
113
+ new(r.status_code, r.content)
114
+ elsif r && r.is_a?(Hash) && r.values.size > 0
115
+ r = r.values[0]
116
+ if r.respond_to?(:status_code) && r.respond_to?(:content)
117
+ new(r.status_code, r.content)
118
+ else
119
+ error("Invalid operation result content: #{r.inspect}")
120
+ end
121
+ elsif r && r.is_a?(String)
122
+ # This is not a supported return value but older RightLink versions can incorrectly
123
+ # return a String rather than an OperationResult#error in situations where the actor
124
+ # raises an exception when processing a request
125
+ error(r)
126
+ elsif r.nil?
127
+ error("No results")
128
+ elsif result.is_a?(Result)
129
+ error("Invalid results in Result from #{result.from}: #{result.results.inspect}")
130
+ else
131
+ error("Invalid operation result type: #{result.inspect}")
132
+ end
133
+ end
134
+
135
+ # Create new success status
136
+ #
137
+ # === Parameters
138
+ # content(Object):: Any data associated with successful results, defaults to nil
139
+ #
140
+ # === Return
141
+ # (OperationResult):: Corresponding result
142
+ def self.success(content = nil)
143
+ OperationResult.new(SUCCESS, content)
144
+ end
145
+
146
+ # Create new error status
147
+ #
148
+ # === Parameters
149
+ # message(String):: Error description
150
+ # exception(Exception|String):: Associated exception or other parenthetical error information
151
+ # backtrace(Symbol):: Exception backtrace extent: :no_trace, :caller, or :trace,
152
+ # defaults to :caller
153
+ #
154
+ # === Return
155
+ # (OperationResult):: Corresponding result
156
+ def self.error(message, exception = nil, backtrace = :caller)
157
+ OperationResult.new(ERROR, Log.format(message, exception, backtrace))
158
+ end
159
+
160
+ # Create new continue status
161
+ #
162
+ # === Parameters
163
+ # content(Object):: Any data associated with continue, defaults to nil
164
+ #
165
+ # === Return
166
+ # (OperationResult):: Corresponding result
167
+ def self.continue(content = nil)
168
+ OperationResult.new(CONTINUE, content)
169
+ end
170
+
171
+ # Create new retry status
172
+ #
173
+ # === Parameters
174
+ # content(Object):: Any data associated with retry, defaults to nil
175
+ #
176
+ # === Return
177
+ # (OperationResult):: Corresponding result
178
+ def self.retry(content = nil)
179
+ OperationResult.new(RETRY, content)
180
+ end
181
+
182
+ # Create new non-delivery status
183
+ #
184
+ # === Parameters
185
+ # reason(String):: Non-delivery reason from NON_DELIVERY_REASONS
186
+ #
187
+ # === Return
188
+ # (OperationResult):: Corresponding result
189
+ def self.non_delivery(reason)
190
+ OperationResult.new(NON_DELIVERY, reason)
191
+ end
192
+
193
+ # Create new multicast status
194
+ # Deprecated for agents at version 13 or above
195
+ #
196
+ # === Parameters
197
+ # targets(Array):: Identity of targets to which request was published
198
+ #
199
+ # === Return
200
+ # (OperationResult):: Corresponding result
201
+ def self.multicast(targets)
202
+ OperationResult.new(MULTICAST, targets)
203
+ end
204
+
205
+ # Cancel request and never retry
206
+ #
207
+ # === Parameters
208
+ # content(Object):: Any data associated with cancel, defaults to nil
209
+ #
210
+ # === Return
211
+ # (OperationResult):: Corresponding result
212
+ def self.cancel(content = nil)
213
+ OperationResult.new(CANCEL, content)
214
+ end
215
+
216
+ # Was last operation successful?
217
+ #
218
+ # === Return
219
+ # true:: If status is SUCCESS or CONTINUE
220
+ # false:: Otherwise
221
+ def success?
222
+ status_code == SUCCESS || status_code == CONTINUE
223
+ end
224
+
225
+ # Was last operation unsuccessful?
226
+ #
227
+ # === Return
228
+ # true:: If status is ERROR or NON_DELIVERY
229
+ # false:: Otherwise
230
+ def error?
231
+ status_code == ERROR || status_code == NON_DELIVERY
232
+ end
233
+
234
+ # Was last operation status CONTINUE?
235
+ #
236
+ # === Return
237
+ # true:: If status is CONTINUE
238
+ # false:: Otherwise
239
+ def continue?
240
+ status_code == CONTINUE
241
+ end
242
+
243
+ # Was last operation status RETRY?
244
+ #
245
+ # === Return
246
+ # true:: If status is RETRY
247
+ # false:: Otherwise
248
+ def retry?
249
+ status_code == RETRY
250
+ end
251
+
252
+ # Was last operation status NON_DELIVERY?
253
+ #
254
+ # === Return
255
+ # true:: If status is NON_DELIVERY
256
+ # false:: Otherwise
257
+ def non_delivery?
258
+ status_code == NON_DELIVERY
259
+ end
260
+
261
+ # Was last operation status MULTICAST?
262
+ # Deprecated for agents at version 13 or above
263
+ #
264
+ # === Return
265
+ # true:: If status is MULTICAST
266
+ # false:: Otherwise
267
+ def multicast?
268
+ status_code == MULTICAST
269
+ end
270
+
271
+ # Was last operation status CANCEL?
272
+ #
273
+ # === Return
274
+ # true:: If status is CANCEL
275
+ # false:: Otherwise
276
+ def cancel?
277
+ status_code == CANCEL
278
+ end
279
+
280
+ # Array of serialized fields given to constructor
281
+ def serialized_members
282
+ [@status_code, @content]
283
+ end
284
+
285
+ end # OperationResult
286
+
287
+ # Helper module to simplify result construction
288
+ module OperationResultHelper
289
+
290
+ def success_result(*args) OperationResult.success(*args) end
291
+ def error_result(*args) OperationResult.error(*args) end
292
+ def continue_result(*args) OperationResult.continue(*args) end
293
+ def retry_result(*args) OperationResult.retry(*args) end
294
+ def non_delivery_result(*args) OperationResult.non_delivery(*args) end
295
+ def cancel_result(*args) OperationResult.cancel(*args) end
296
+ def result_from(*args) OperationResult.from_results(*args) end
297
+
298
+ end # OperationResultHelper
299
+
300
+ end # RightScale
@@ -0,0 +1,673 @@
1
+ # Copyright (c) 2009-2012 RightScale Inc
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+
23
+ # Hack to replace the Nanite namespace from downrev agents with the RightScale namespace
24
+ module JSON
25
+ class << self
26
+ def parse(source, opts = {})
27
+ # In gem version this options is set to true by default
28
+ # but in ruby native json library is set to false by default
29
+ # Explicitly set it to true so both json libraries act the same
30
+ opts[:create_additions] = true
31
+ if source =~ /(.*)json_class":"Nanite::(.*)/
32
+ JSON.parser.new( Regexp.last_match(1) + 'json_class":"RightScale::' + Regexp.last_match(2), opts).parse
33
+ else
34
+ JSON.parser.new(source, opts).parse
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+
41
+ module RightScale
42
+
43
+ # Base class for all packets flowing through the RightNet routers
44
+ # Knows how to dump itself to MessagePack or JSON
45
+ class Packet
46
+
47
+ # Current version of protocol
48
+ VERSION = AgentConfig.protocol_version
49
+
50
+ # Default version for packet senders unaware of this versioning
51
+ DEFAULT_VERSION = 0
52
+
53
+ # Shard scope value meaning restrict sending request only to agents with no shard id
54
+ GLOBAL = 0
55
+
56
+ # Instance variables that are not serialized because they are only used locally
57
+ NOT_SERIALIZED = ["received_at"]
58
+
59
+ # (Float) Time in seconds in Unix-epoch when message was received
60
+ attr_accessor :received_at
61
+
62
+ # (Integer) Size of packet in bytes
63
+ attr_accessor :size
64
+
65
+ def initialize
66
+ raise NotImplementedError.new("#{self.class.name} is an abstract class.")
67
+ end
68
+
69
+ # Create packet from unmarshalled MessagePack data
70
+ #
71
+ # === Parameters
72
+ # o(Hash):: MessagePack data
73
+ #
74
+ # === Return
75
+ # (Packet):: New packet
76
+ def self.msgpack_create(o)
77
+ create(o)
78
+ end
79
+
80
+ # Create packet from unmarshalled JSON data
81
+ #
82
+ # === Parameters
83
+ # o(Hash):: MessagePack data
84
+ #
85
+ # === Return
86
+ # (Packet):: New packet
87
+ def self.json_create(o)
88
+ create(o)
89
+ end
90
+
91
+ # Marshal packet into MessagePack format
92
+ #
93
+ # === Parameters
94
+ # a(Array):: Arguments
95
+ #
96
+ # === Return
97
+ # msg(String):: Marshalled packet
98
+ def to_msgpack(*a)
99
+ msg = {
100
+ 'msgpack_class' => self.class.name,
101
+ 'data' => instance_variables.inject({}) do |m, ivar|
102
+ name = ivar.to_s.sub(/@/, '')
103
+ m[name] = instance_variable_get(ivar) unless NOT_SERIALIZED.include?(name)
104
+ m
105
+ end,
106
+ 'size' => nil
107
+ }.to_msgpack(*a)
108
+ @size = msg.size
109
+ # For ruby 1.9 size attribute moves from front to back of packet
110
+ re = RUBY_VERSION < "1.9.0" ? /size\xC0/ : /size\xC0$/
111
+ # For msgpack 0.5.1 the to_msgpack result is a MessagePack::Packer so need to convert to string
112
+ msg = msg.to_s.sub!(re) { |m| "size" + @size.to_msgpack }
113
+ msg
114
+ end
115
+
116
+ # Marshal packet into JSON format
117
+ #
118
+ # === Parameters
119
+ # a(Array):: Arguments
120
+ #
121
+ # === Return
122
+ # js(String):: Marshalled packet
123
+ def to_json(*a)
124
+ # Hack to override RightScale namespace with Nanite for downward compatibility
125
+ class_name = self.class.name
126
+ if class_name =~ /^RightScale::(.*)/
127
+ class_name = "Nanite::" + Regexp.last_match(1)
128
+ end
129
+
130
+ js = {
131
+ 'json_class' => class_name,
132
+ 'data' => instance_variables.inject({}) do |m, ivar|
133
+ name = ivar.to_s.sub(/@/, '')
134
+ m[name] = instance_variable_get(ivar) unless NOT_SERIALIZED.include?(name)
135
+ m
136
+ end
137
+ }.to_json(*a)
138
+ @size = js.size
139
+ js = js.chop + ",\"size\":#{@size}}"
140
+ end
141
+
142
+ # Name of packet in lower snake case
143
+ #
144
+ # === Return
145
+ # (String):: Packet name
146
+ def name
147
+ self.class.to_s.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
148
+ end
149
+
150
+ # Generate log representation
151
+ #
152
+ # === Parameters
153
+ # filter(Array(Symbol)):: Attributes to be included in output
154
+ # version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
155
+ #
156
+ # === Return
157
+ # log_msg(String):: Log representation
158
+ def to_s(filter = nil, version = nil)
159
+ v = send(version) if version
160
+ v = (v && v != DEFAULT_VERSION) ? " v#{v}" : ""
161
+ log_msg = "[#{name}#{v}]"
162
+ duration = if @duration && (filter.nil? || filter.include?(:duration))
163
+ ", #{enough_precision(@duration)} sec"
164
+ elsif @received_at && (filter.nil? || filter.include?(:local_duration))
165
+ ", #{enough_precision(Time.now.to_f - @received_at)} sec"
166
+ end
167
+ log_msg += " (#{@size.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")} bytes#{duration})" if @size && !@size.to_s.empty?
168
+ log_msg
169
+ end
170
+
171
+ # Determine enough precision for floating point value to give at least two significant
172
+ # digits and then convert the value to a decimal digit string of that precision
173
+ #
174
+ # === Parameters
175
+ # value(Float):: Value to be converted
176
+ #
177
+ # === Return
178
+ # (String):: Floating point digit string
179
+ def enough_precision(value)
180
+ scale = [1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0]
181
+ enough = lambda { |v| (v >= 10.0 ? 0 :
182
+ (v >= 1.0 ? 1 :
183
+ (v >= 0.1 ? 2 :
184
+ (v >= 0.01 ? 3 :
185
+ (v > 0.001 ? 4 :
186
+ (v > 0.0 ? 5 : 0)))))) }
187
+ digit_str = lambda { |p, v| sprintf("%.#{p}f", (v * scale[p]).round / scale[p])}
188
+ digit_str.call(enough.call(value), value)
189
+ end
190
+
191
+ # Generate log friendly serialized identity
192
+ # Result marked with leading '*' if not same as original identity
193
+ #
194
+ # === Parameters
195
+ # id(String):: Serialized identity
196
+ #
197
+ # === Return
198
+ # (String):: Log friendly serialized identity
199
+ def id_to_s(id)
200
+ modified_id = AgentIdentity.compatible_serialized(id)
201
+ if id == modified_id then modified_id else "*#{modified_id}" end
202
+ end
203
+
204
+ # Generate log friendly serialized identity for one or more ids
205
+ # Limit to 1000 bytes
206
+ #
207
+ # === Parameters
208
+ # ids(Array|String):: Serialized identity or array of serialized identities
209
+ #
210
+ # === Return
211
+ # (String):: Log friendly serialized identity
212
+ def ids_to_s(ids)
213
+ if ids.is_a?(Array)
214
+ s = ids.each { |i| id_to_s(i) }.join(', ')
215
+ s.size > 1000 ? "[#{s[0, 1000]}...]" : "[#{s}]"
216
+ else
217
+ id_to_s(ids)
218
+ end
219
+ end
220
+
221
+ # Convert serialized AgentIdentity to compatible format
222
+ #
223
+ # === Parameters
224
+ # id(String):: Serialized identity
225
+ #
226
+ # === Return
227
+ # (String):: Compatible serialized identity
228
+ def self.compatible(id)
229
+ AgentIdentity.compatible_serialized(id)
230
+ end
231
+
232
+ # Get target to be used for encrypting the packet
233
+ #
234
+ # === Return
235
+ # (String):: Target
236
+ def target_for_encryption
237
+ nil
238
+ end
239
+
240
+ # Whether the packet is one that does not have an associated response
241
+ #
242
+ # === Return
243
+ # (Boolean):: Defaults to true
244
+ def one_way
245
+ true
246
+ end
247
+
248
+ # Generate token used to trace execution of operation across multiple packets
249
+ #
250
+ # === Return
251
+ # tr(String):: Trace token, may be empty
252
+ def trace
253
+ audit_id = self.respond_to?(:payload) && payload.is_a?(Hash) && (payload['audit_id'] || payload[:audit_id])
254
+ tok = self.respond_to?(:token) && token
255
+ tr = "<#{audit_id || nil}> <#{tok}>"
256
+ end
257
+
258
+ # Retrieve protocol version of original creator of packet
259
+ #
260
+ # === Return
261
+ # (Integer) Received protocol version
262
+ def recv_version
263
+ @version[0]
264
+ end
265
+
266
+ # Retrieve protocol version of packet for use when sending packet
267
+ #
268
+ # === Return
269
+ # (Integer) Send protocol version
270
+ def send_version
271
+ @version[1]
272
+ end
273
+
274
+ # Set protocol version of packet for use when sending packet
275
+ def send_version=(value)
276
+ @version[1] = value
277
+ end
278
+
279
+ end # Packet
280
+
281
+
282
+ # Packet for a work request for an actor node that has an expected result
283
+ class Request < Packet
284
+
285
+ attr_accessor :from, :scope, :payload, :type, :token, :reply_to, :selector, :target, :persistent, :expires_at,
286
+ :tags, :tries
287
+
288
+ DEFAULT_OPTIONS = {:selector => :any}
289
+
290
+ # Create packet
291
+ #
292
+ # === Parameters
293
+ # type(String):: Dispatch route for the request
294
+ # payload(Any):: Arbitrary data that is transferred to actor
295
+ # opts(Hash):: Optional settings:
296
+ # :from(String):: Sender identity
297
+ # :scope(Hash):: Define behavior that should be used to resolve tag based routing
298
+ # :token(String):: Generated request id that a router uses to identify replies
299
+ # :reply_to(String):: Identity of the node that actor replies to, usually a router itself
300
+ # :selector(Symbol):: Selector used to route the request: :any or :all, defaults to :any,
301
+ # :all deprecated for version 13 and above
302
+ # :target(String|Array):: Target recipient(s)
303
+ # :persistent(Boolean):: Indicates if this request should be saved to persistent storage
304
+ # by the AMQP broker
305
+ # :expires_at(Integer|nil):: Time in seconds in Unix-epoch when this request expires and
306
+ # is to be ignored by the receiver; value 0 means never expire; defaults to 0
307
+ # :tags(Array(Symbol)):: List of tags to be used for selecting target for this request
308
+ # :tries(Array):: List of tokens for previous attempts to send this request
309
+ # version(Array):: Protocol version of the original creator of the packet followed by the
310
+ # protocol version of the packet contents to be used when sending
311
+ # size(Integer):: Size of request in bytes used only for marshalling
312
+ def initialize(type, payload, opts = {}, version = [VERSION, VERSION], size = nil)
313
+ opts = DEFAULT_OPTIONS.merge(opts)
314
+ @type = type
315
+ @payload = payload
316
+ @from = opts[:from]
317
+ @scope = opts[:scope]
318
+ @token = opts[:token]
319
+ @reply_to = opts[:reply_to]
320
+ @selector = opts[:selector]
321
+ @selector = :any if ["least_loaded", "random"].include?(@selector.to_s)
322
+ @target = opts[:target]
323
+ @persistent = opts[:persistent]
324
+ @expires_at = opts[:expires_at] || 0
325
+ @tags = opts[:tags] || []
326
+ @tries = opts[:tries] || []
327
+ @version = version
328
+ @size = size
329
+ end
330
+
331
+ # Test whether the request is being fanned out to multiple targets
332
+ #
333
+ # === Return
334
+ # (Boolean):: true if is multicast, otherwise false
335
+ def fanout?
336
+ @selector.to_s == 'all'
337
+ end
338
+
339
+ # Create packet from unmarshalled data
340
+ #
341
+ # === Parameters
342
+ # o(Hash):: Unmarshalled data
343
+ #
344
+ # === Return
345
+ # (Request):: New packet
346
+ def self.create(o)
347
+ i = o['data']
348
+ expires_at = if i.has_key?('created_at')
349
+ created_at = i['created_at'].to_i
350
+ created_at > 0 ? created_at + (15 * 60) : 0
351
+ else
352
+ i['expires_at']
353
+ end
354
+ new(i['type'], i['payload'], { :from => self.compatible(i['from']), :scope => i['scope'],
355
+ :token => i['token'], :reply_to => self.compatible(i['reply_to']),
356
+ :selector => i['selector'], :target => self.compatible(i['target']),
357
+ :persistent => i['persistent'], :tags => i['tags'],
358
+ :expires_at => expires_at, :tries => i['tries'] },
359
+ i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
360
+ end
361
+
362
+ # Generate log representation
363
+ #
364
+ # === Parameters
365
+ # filter(Array(Symbol)):: Attributes to be included in output
366
+ # version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
367
+ #
368
+ # === Return
369
+ # log_msg(String):: Log representation
370
+ def to_s(filter = nil, version = nil)
371
+ payload = PayloadFormatter.log(@type, @payload)
372
+ log_msg = "#{super(filter, version)} #{trace} #{@type}"
373
+ log_msg += " #{payload}" if payload
374
+ log_msg += " from #{id_to_s(@from)}" if filter.nil? || filter.include?(:from)
375
+ log_msg += ", target #{ids_to_s(@target)}" if @target && (filter.nil? || filter.include?(:target))
376
+ log_msg += ", scope #{@scope.inspect}" if @scope && (filter.nil? || filter.include?(:scope))
377
+ log_msg += ", fanout" if (filter.nil? || filter.include?(:fanout)) && fanout?
378
+ log_msg += ", reply_to #{id_to_s(@reply_to)}" if @reply_to && (filter.nil? || filter.include?(:reply_to))
379
+ log_msg += ", tags #{@tags.inspect}" if @tags && !@tags.empty? && (filter.nil? || filter.include?(:tags))
380
+ log_msg += ", persistent" if @persistent && (filter.nil? || filter.include?(:persistent))
381
+ log_msg += ", tries #{tries_to_s}" if @tries && !@tries.empty? && (filter.nil? || filter.include?(:tries))
382
+ log_msg += ", payload #{@payload.inspect}" if filter && filter.include?(:payload)
383
+ log_msg
384
+ end
385
+
386
+ # Convert tries list to string representation
387
+ #
388
+ # === Return
389
+ # log_msg(String):: Tries list
390
+ def tries_to_s
391
+ @tries.map { |t| "<#{t}>" }.join(", ")
392
+ end
393
+
394
+ # Get target to be used for encrypting the packet
395
+ #
396
+ # === Return
397
+ # (String):: Target
398
+ def target_for_encryption
399
+ @target
400
+ end
401
+
402
+ # Whether the packet is one that does not have an associated response
403
+ #
404
+ # === Return
405
+ # false:: Always return false
406
+ def one_way
407
+ false
408
+ end
409
+
410
+ end # Request
411
+
412
+
413
+ # Packet for a work request for an actor node that has no result, i.e., one-way request
414
+ class Push < Packet
415
+
416
+ attr_accessor :from, :scope, :payload, :type, :token, :selector, :target, :persistent, :confirm,
417
+ :expires_at, :tags
418
+
419
+ DEFAULT_OPTIONS = {:selector => :any}
420
+
421
+ # Create packet
422
+ #
423
+ # === Parameters
424
+ # type(String):: Dispatch route for the request
425
+ # payload(Any):: Arbitrary data that is transferred to actor
426
+ # opts(Hash):: Optional settings:
427
+ # :from(String):: Sender identity
428
+ # :scope(Hash):: Define behavior that should be used to resolve tag based routing
429
+ # :token(String):: Generated request id that a router uses to identify replies
430
+ # :selector(Symbol):: Selector used to route the request: :any or :all, defaults to :any
431
+ # :target(String|Array):: Target recipient(s)
432
+ # :persistent(Boolean):: Indicates if this request should be saved to persistent storage
433
+ # by the AMQP broker
434
+ # :confirm(Boolean):: Whether require confirmation response from router containing targets
435
+ # to which request was published but not necessarily delivered
436
+ # :expires_at(Integer|nil):: Time in seconds in Unix-epoch when this request expires and
437
+ # is to be ignored by the receiver; value 0 means never expire; defaults to 0
438
+ # :tags(Array(Symbol)):: List of tags to be used for selecting target for this request
439
+ # version(Array):: Protocol version of the original creator of the packet followed by the
440
+ # protocol version of the packet contents to be used when sending
441
+ # size(Integer):: Size of request in bytes used only for marshalling
442
+ def initialize(type, payload, opts = {}, version = [VERSION, VERSION], size = nil)
443
+ opts = DEFAULT_OPTIONS.merge(opts)
444
+ @type = type
445
+ @payload = payload
446
+ @from = opts[:from]
447
+ @scope = opts[:scope]
448
+ @token = opts[:token]
449
+ @selector = opts[:selector]
450
+ @selector = :any if ["least_loaded", "random"].include?(@selector.to_s)
451
+ @target = opts[:target]
452
+ @persistent = opts[:persistent]
453
+ @confirm = opts[:confirm]
454
+ @expires_at = opts[:expires_at] || 0
455
+ @tags = opts[:tags] || []
456
+ @version = version
457
+ @size = size
458
+ end
459
+
460
+ # Test whether the request is being fanned out to multiple targets
461
+ #
462
+ # === Return
463
+ # (Boolean):: true if is fanout, otherwise false
464
+ def fanout?
465
+ @selector.to_s == 'all'
466
+ end
467
+
468
+ # Keep interface consistent with Request packets
469
+ # A push never gets retried
470
+ #
471
+ # === Return
472
+ # []:: Always return empty array
473
+ def tries
474
+ []
475
+ end
476
+
477
+ # Create packet from unmarshalled data
478
+ #
479
+ # === Parameters
480
+ # o(Hash):: Unmarshalled data
481
+ #
482
+ # === Return
483
+ # (Push):: New packet
484
+ def self.create(o)
485
+ i = o['data']
486
+ new(i['type'], i['payload'], { :from => self.compatible(i['from']), :scope => i['scope'],
487
+ :token => i['token'], :selector => i['selector'],
488
+ :target => self.compatible(i['target']), :persistent => i['persistent'],
489
+ :confirm => i['confirm'], :expires_at => i['expires_at'],
490
+ :tags => i['tags']},
491
+ i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
492
+ end
493
+
494
+ # Generate log representation
495
+ #
496
+ # === Parameters
497
+ # filter(Array(Symbol)):: Attributes to be included in output
498
+ # version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
499
+ #
500
+ # === Return
501
+ # log_msg(String):: Log representation
502
+ def to_s(filter = nil, version = nil)
503
+ payload = PayloadFormatter.log(@type, @payload)
504
+ log_msg = "#{super(filter, version)} #{trace} #{@type}"
505
+ log_msg += " #{payload}" if payload
506
+ log_msg += " from #{id_to_s(@from)}" if filter.nil? || filter.include?(:from)
507
+ log_msg += ", target #{ids_to_s(@target)}" if @target && (filter.nil? || filter.include?(:target))
508
+ log_msg += ", scope #{@scope.inspect}" if @scope && (filter.nil? || filter.include?(:scope))
509
+ log_msg += ", fanout" if (filter.nil? || filter.include?(:fanout)) && fanout?
510
+ log_msg += ", tags #{@tags.inspect}" if @tags && !@tags.empty? && (filter.nil? || filter.include?(:tags))
511
+ log_msg += ", persistent" if @persistent && (filter.nil? || filter.include?(:persistent))
512
+ log_msg += ", payload #{@payload.inspect}" if filter && filter.include?(:payload)
513
+ log_msg
514
+ end
515
+
516
+ # Get target to be used for encrypting the packet
517
+ #
518
+ # === Return
519
+ # (String):: Target
520
+ def target_for_encryption
521
+ @target
522
+ end
523
+
524
+ end # Push
525
+
526
+
527
+ # Packet for a work result notification sent from actor node
528
+ class Result < Packet
529
+
530
+ attr_accessor :token, :results, :to, :from, :request_from, :tries, :persistent, :duration
531
+
532
+ # Create packet
533
+ #
534
+ # === Parameters
535
+ # token(String):: Generated request id that a router uses to identify replies
536
+ # to(String):: Identity of the node to which result should be delivered
537
+ # results(Any):: Arbitrary data that is transferred from actor, a result of actor's work
538
+ # from(String):: Sender identity
539
+ # request_from(String):: Identity of the agent that sent the original request
540
+ # tries(Array):: List of tokens for previous attempts to send associated request
541
+ # persistent(Boolean):: Indicates if this result should be saved to persistent storage
542
+ # by the AMQP broker
543
+ # duration(Float):: Number of seconds required to produce the result
544
+ # version(Array):: Protocol version of the original creator of the packet followed by the
545
+ # protocol version of the packet contents to be used when sending
546
+ # size(Integer):: Size of request in bytes used only for marshalling
547
+ def initialize(token, to, results, from, request_from = nil, tries = nil, persistent = nil, duration = nil,
548
+ version = [VERSION, VERSION], size = nil)
549
+ @token = token
550
+ @to = to
551
+ @results = results
552
+ @from = from
553
+ @request_from = request_from
554
+ @tries = tries || []
555
+ @persistent = persistent
556
+ @duration = duration
557
+ @version = version
558
+ @size = size
559
+ end
560
+
561
+ # Create packet from unmarshalled data
562
+ #
563
+ # === Parameters
564
+ # o(Hash):: Unmarshalled data
565
+ #
566
+ # === Return
567
+ # (Result):: New packet
568
+ def self.create(o)
569
+ i = o['data']
570
+ new(i['token'], self.compatible(i['to']), i['results'], self.compatible(i['from']),
571
+ self.compatible(i['request_from']), i['tries'], i['persistent'], i['duration'],
572
+ i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
573
+ end
574
+
575
+ # Generate log representation
576
+ #
577
+ # === Parameters
578
+ # filter(Array(Symbol)):: Attributes to be included in output
579
+ # version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
580
+ #
581
+ # === Return
582
+ # log_msg(String):: Log representation
583
+ def to_s(filter = nil, version = nil)
584
+ log_msg = "#{super(filter, version)} #{trace}"
585
+ log_msg += " from #{id_to_s(@from)}" if filter.nil? || filter.include?(:from)
586
+ log_msg += " to #{id_to_s(@to)}" if filter.nil? || filter.include?(:to)
587
+ log_msg += ", request_from #{id_to_s(@request_from)}" if @request_from && (filter.nil? || filter.include?(:request_from))
588
+ log_msg += ", persistent" if @persistent && (filter.nil? || filter.include?(:persistent))
589
+ log_msg += ", tries #{tries_to_s}" if @tries && !@tries.empty? && (filter.nil? || filter.include?(:tries))
590
+ if filter.nil? || !filter.include?(:results)
591
+ if !@results.nil?
592
+ if @results.is_a?(RightScale::OperationResult) # Will be true when logging a 'SEND'
593
+ res = @results
594
+ elsif @results.is_a?(Hash) && @results.size == 1 # Will be true when logging a 'RECV' for version 9 or below
595
+ res = @results.values.first
596
+ end
597
+ log_msg += " #{res.to_s}" if res
598
+ end
599
+ else
600
+ log_msg += " results #{@results.inspect}"
601
+ end
602
+ log_msg
603
+ end
604
+
605
+ # Convert tries list to string representation
606
+ #
607
+ # === Return
608
+ # log_msg(String):: Tries list
609
+ def tries_to_s
610
+ log_msg = ""
611
+ @tries.each { |r| log_msg += "<#{r}>, " }
612
+ log_msg = log_msg[0..-3] if log_msg.size > 1
613
+ end
614
+
615
+ # Get target to be used for encrypting the packet
616
+ #
617
+ # === Return
618
+ # (String):: Target
619
+ def target_for_encryption
620
+ @to
621
+ end
622
+
623
+ end # Result
624
+
625
+
626
+ # Packet for carrying statistics
627
+ class Stats < Packet
628
+
629
+ attr_accessor :data, :token, :from
630
+
631
+ # Create packet
632
+ #
633
+ # === Parameters
634
+ # data(Object):: Data
635
+ # from(String):: Identity of sender
636
+ # version(Array):: Protocol version of the original creator of the packet followed by the
637
+ # protocol version of the packet contents to be used when sending
638
+ # size(Integer):: Size of request in bytes used only for marshalling
639
+ def initialize(data, from, version = [VERSION, VERSION], size = nil)
640
+ @data = data
641
+ @from = from
642
+ @version = version
643
+ @size = size
644
+ end
645
+
646
+ # Create packet from unmarshalled data
647
+ #
648
+ # === Parameters
649
+ # o(Hash):: Unmarshalled data
650
+ #
651
+ # === Return
652
+ # (Result):: New packet
653
+ def self.create(o)
654
+ i = o['data']
655
+ new(i['data'], self.compatible(i['from']), i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
656
+ end
657
+
658
+ # Generate log representation
659
+ #
660
+ # === Parameters
661
+ # filter(Array(Symbol)):: Attributes to be included in output
662
+ # version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
663
+ #
664
+ # === Return
665
+ # log_msg(String):: Log representation
666
+ def to_s(filter = nil, version = nil)
667
+ log_msg = "#{super(filter, version)} #{id_to_s(@from)}"
668
+ end
669
+
670
+ end # Stats
671
+
672
+ end # RightScale
673
+