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,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
+