right_agent 0.5.1
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.
- data/LICENSE +20 -0
- data/README.rdoc +78 -0
- data/Rakefile +86 -0
- data/lib/right_agent.rb +66 -0
- data/lib/right_agent/actor.rb +163 -0
- data/lib/right_agent/actor_registry.rb +76 -0
- data/lib/right_agent/actors/agent_manager.rb +189 -0
- data/lib/right_agent/agent.rb +735 -0
- data/lib/right_agent/agent_config.rb +403 -0
- data/lib/right_agent/agent_identity.rb +209 -0
- data/lib/right_agent/agent_tags_manager.rb +213 -0
- data/lib/right_agent/audit_formatter.rb +107 -0
- data/lib/right_agent/broker_client.rb +683 -0
- data/lib/right_agent/command.rb +30 -0
- data/lib/right_agent/command/agent_manager_commands.rb +134 -0
- data/lib/right_agent/command/command_client.rb +136 -0
- data/lib/right_agent/command/command_constants.rb +42 -0
- data/lib/right_agent/command/command_io.rb +128 -0
- data/lib/right_agent/command/command_parser.rb +87 -0
- data/lib/right_agent/command/command_runner.rb +105 -0
- data/lib/right_agent/command/command_serializer.rb +63 -0
- data/lib/right_agent/console.rb +65 -0
- data/lib/right_agent/core_payload_types.rb +42 -0
- data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
- data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
- data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
- data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
- data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
- data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
- data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
- data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
- data/lib/right_agent/core_payload_types/login_user.rb +62 -0
- data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
- data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
- data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
- data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
- data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
- data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
- data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
- data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
- data/lib/right_agent/daemonize.rb +35 -0
- data/lib/right_agent/dispatcher.rb +348 -0
- data/lib/right_agent/enrollment_result.rb +217 -0
- data/lib/right_agent/exceptions.rb +30 -0
- data/lib/right_agent/ha_broker_client.rb +1278 -0
- data/lib/right_agent/idempotent_request.rb +140 -0
- data/lib/right_agent/log.rb +418 -0
- data/lib/right_agent/monkey_patches.rb +29 -0
- data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
- data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
- data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
- data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
- data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
- data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
- data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
- data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
- data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
- data/lib/right_agent/multiplexer.rb +91 -0
- data/lib/right_agent/operation_result.rb +270 -0
- data/lib/right_agent/packets.rb +637 -0
- data/lib/right_agent/payload_formatter.rb +104 -0
- data/lib/right_agent/pid_file.rb +159 -0
- data/lib/right_agent/platform.rb +319 -0
- data/lib/right_agent/platform/darwin.rb +227 -0
- data/lib/right_agent/platform/linux.rb +268 -0
- data/lib/right_agent/platform/windows.rb +1204 -0
- data/lib/right_agent/scripts/agent_controller.rb +522 -0
- data/lib/right_agent/scripts/agent_deployer.rb +379 -0
- data/lib/right_agent/scripts/common_parser.rb +153 -0
- data/lib/right_agent/scripts/log_level_manager.rb +193 -0
- data/lib/right_agent/scripts/stats_manager.rb +256 -0
- data/lib/right_agent/scripts/usage.rb +58 -0
- data/lib/right_agent/secure_identity.rb +92 -0
- data/lib/right_agent/security.rb +32 -0
- data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
- data/lib/right_agent/security/certificate.rb +102 -0
- data/lib/right_agent/security/certificate_cache.rb +89 -0
- data/lib/right_agent/security/distinguished_name.rb +56 -0
- data/lib/right_agent/security/encrypted_document.rb +84 -0
- data/lib/right_agent/security/rsa_key_pair.rb +76 -0
- data/lib/right_agent/security/signature.rb +86 -0
- data/lib/right_agent/security/static_certificate_store.rb +69 -0
- data/lib/right_agent/sender.rb +937 -0
- data/lib/right_agent/serialize.rb +29 -0
- data/lib/right_agent/serialize/message_pack.rb +102 -0
- data/lib/right_agent/serialize/secure_serializer.rb +131 -0
- data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
- data/lib/right_agent/serialize/serializable.rb +135 -0
- data/lib/right_agent/serialize/serializer.rb +149 -0
- data/lib/right_agent/stats_helper.rb +731 -0
- data/lib/right_agent/subprocess.rb +38 -0
- data/lib/right_agent/tracer.rb +124 -0
- data/right_agent.gemspec +60 -0
- data/spec/actor_registry_spec.rb +81 -0
- data/spec/actor_spec.rb +99 -0
- data/spec/agent_config_spec.rb +226 -0
- data/spec/agent_identity_spec.rb +75 -0
- data/spec/agent_spec.rb +571 -0
- data/spec/broker_client_spec.rb +961 -0
- data/spec/command/agent_manager_commands_spec.rb +51 -0
- data/spec/command/command_io_spec.rb +93 -0
- data/spec/command/command_parser_spec.rb +79 -0
- data/spec/command/command_runner_spec.rb +72 -0
- data/spec/command/command_serializer_spec.rb +51 -0
- data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
- data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
- data/spec/core_payload_types/login_user_spec.rb +98 -0
- data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
- data/spec/core_payload_types/spec_helper.rb +23 -0
- data/spec/dispatcher_spec.rb +372 -0
- data/spec/enrollment_result_spec.rb +53 -0
- data/spec/ha_broker_client_spec.rb +1673 -0
- data/spec/idempotent_request_spec.rb +136 -0
- data/spec/log_spec.rb +177 -0
- data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
- data/spec/monkey_patches/eventmachine_spec.rb +62 -0
- data/spec/monkey_patches/string_patch_spec.rb +99 -0
- data/spec/multiplexer_spec.rb +48 -0
- data/spec/operation_result_spec.rb +171 -0
- data/spec/packets_spec.rb +418 -0
- data/spec/platform/platform_spec.rb +60 -0
- data/spec/results_mock.rb +45 -0
- data/spec/secure_identity_spec.rb +50 -0
- data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
- data/spec/security/certificate_cache_spec.rb +71 -0
- data/spec/security/certificate_spec.rb +49 -0
- data/spec/security/distinguished_name_spec.rb +46 -0
- data/spec/security/encrypted_document_spec.rb +55 -0
- data/spec/security/rsa_key_pair_spec.rb +55 -0
- data/spec/security/signature_spec.rb +66 -0
- data/spec/security/static_certificate_store_spec.rb +52 -0
- data/spec/sender_spec.rb +887 -0
- data/spec/serialize/message_pack_spec.rb +131 -0
- data/spec/serialize/secure_serializer_spec.rb +102 -0
- data/spec/serialize/serializable_spec.rb +90 -0
- data/spec/serialize/serializer_spec.rb +174 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/stats_helper_spec.rb +681 -0
- data/spec/tracer_spec.rb +114 -0
- metadata +320 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 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
|
+
require 'rubygems'
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
require 'win32ole'
|
|
27
|
+
|
|
28
|
+
# ohai 0.3.6 has a bug which causes WMI data to be imported using the default
|
|
29
|
+
# Windows code page. the workaround is to set the win32ole gem's code page to
|
|
30
|
+
# UTF-8, which is probably a good general Ruby on Windows practice in any case.
|
|
31
|
+
WIN32OLE.codepage = WIN32OLE::CP_UTF8
|
|
32
|
+
rescue LoadError
|
|
33
|
+
# ignore load error and skip monkey-patch if gems are not yet installed.
|
|
34
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
module RightScale
|
|
24
|
+
|
|
25
|
+
# Apply each method call to all registered targets
|
|
26
|
+
class Multiplexer
|
|
27
|
+
|
|
28
|
+
# Access to underlying multiplexed objects
|
|
29
|
+
attr_reader :targets
|
|
30
|
+
|
|
31
|
+
# Undefine warn to prevent Kernel#warn from being called
|
|
32
|
+
undef warn rescue nil
|
|
33
|
+
|
|
34
|
+
# Initialize multiplexer targets
|
|
35
|
+
#
|
|
36
|
+
# === Parameters
|
|
37
|
+
# targets(Object):: Targets that should receive the method calls
|
|
38
|
+
def initialize(*targets)
|
|
39
|
+
@targets = targets || []
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Add object to list of multiplexed targets
|
|
43
|
+
#
|
|
44
|
+
# === Parameters
|
|
45
|
+
# target(Object):: Add target to list of multiplexed targets
|
|
46
|
+
#
|
|
47
|
+
# === Return
|
|
48
|
+
# self(RightScale::Multiplexer):: self so operation can be chained
|
|
49
|
+
def add(target)
|
|
50
|
+
@targets << target unless @targets.include?(target)
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Remove object from list of multiplexed targets
|
|
55
|
+
#
|
|
56
|
+
# === Parameters
|
|
57
|
+
# target(Object):: Remove target from list of multiplexed targets
|
|
58
|
+
#
|
|
59
|
+
# === Return
|
|
60
|
+
# self(RightScale::Multiplexer):: self so operation can be chained
|
|
61
|
+
def remove(target)
|
|
62
|
+
@targets.delete_if { |t| t == target }
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Access target at given index
|
|
67
|
+
#
|
|
68
|
+
# === Parameters
|
|
69
|
+
# index(Integer):: Target index
|
|
70
|
+
#
|
|
71
|
+
# === Return
|
|
72
|
+
# target(Object):: Target at index 'index' or nil if none
|
|
73
|
+
def [](index)
|
|
74
|
+
target = @targets[index]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Forward any method invocation to targets
|
|
78
|
+
#
|
|
79
|
+
# === Parameters
|
|
80
|
+
# m(Symbol):: Method that should be multiplexed
|
|
81
|
+
# args(Array):: Arguments
|
|
82
|
+
#
|
|
83
|
+
# === Return
|
|
84
|
+
# res(Object):: Result of first target in list
|
|
85
|
+
def method_missing(m, *args)
|
|
86
|
+
res = @targets.inject([]) { |res, t| res << t.__send__(m, *args) }
|
|
87
|
+
res[0]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,270 @@
|
|
|
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
|
+
|
|
39
|
+
# Non-delivery reasons
|
|
40
|
+
NON_DELIVERY_REASONS = [
|
|
41
|
+
NO_TARGET = "no target",
|
|
42
|
+
UNKNOWN_TARGET = "unknown target",
|
|
43
|
+
NO_ROUTE_TO_TARGET = "no route to target",
|
|
44
|
+
TARGET_NOT_CONNECTED = "target not connected",
|
|
45
|
+
TTL_EXPIRATION = "TTL expiration",
|
|
46
|
+
RETRY_TIMEOUT = "retry timeout"
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
# Maximum characters included in display of error
|
|
50
|
+
MAX_ERROR_SIZE = 60
|
|
51
|
+
|
|
52
|
+
# (Integer) Status code
|
|
53
|
+
attr_accessor :status_code
|
|
54
|
+
|
|
55
|
+
# (Object) Result data, if any
|
|
56
|
+
attr_accessor :content
|
|
57
|
+
|
|
58
|
+
def initialize(*args)
|
|
59
|
+
@status_code = args[0]
|
|
60
|
+
@content = args[1] if args.size > 1
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# User friendly result
|
|
64
|
+
# Does not include content except in the case of error or non-delivery
|
|
65
|
+
#
|
|
66
|
+
# === Return
|
|
67
|
+
# (String):: Name of result code
|
|
68
|
+
def to_s
|
|
69
|
+
status(reason = true)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# User friendly result status
|
|
73
|
+
#
|
|
74
|
+
# === Parameters
|
|
75
|
+
# reason(Boolean):: Whether to include failure reason information, default to false
|
|
76
|
+
#
|
|
77
|
+
# === Return
|
|
78
|
+
# (String):: Name of result code
|
|
79
|
+
def status(reason = false)
|
|
80
|
+
case @status_code
|
|
81
|
+
when SUCCESS then 'success'
|
|
82
|
+
when ERROR then 'error' + (reason ? " (#{truncated_error})" : "")
|
|
83
|
+
when CONTINUE then 'continue'
|
|
84
|
+
when RETRY then 'retry'
|
|
85
|
+
when NON_DELIVERY then 'non-delivery' + (reason ? " (#{@content})" : "")
|
|
86
|
+
when MULTICAST then 'multicast'
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Limited length error string
|
|
91
|
+
#
|
|
92
|
+
# === Return
|
|
93
|
+
# e(String):: String of no more than MAX_ERROR_SIZE characters
|
|
94
|
+
def truncated_error
|
|
95
|
+
e = @content.is_a?(String) ? @content : @content.inspect
|
|
96
|
+
e = e[0, MAX_ERROR_SIZE - 3] + "..." if e.size > (MAX_ERROR_SIZE - 3)
|
|
97
|
+
e
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Instantiate from request results
|
|
101
|
+
# Ignore all but first result if results is a hash
|
|
102
|
+
#
|
|
103
|
+
# === Parameters
|
|
104
|
+
# results(Result|Hash|OperationResult|nil):: Result or the Result "results" field
|
|
105
|
+
#
|
|
106
|
+
# === Return
|
|
107
|
+
# (RightScale::OperationResult):: Converted operation result
|
|
108
|
+
def self.from_results(results)
|
|
109
|
+
r = results.kind_of?(Result) ? results.results : results
|
|
110
|
+
if r && r.respond_to?(:status_code) && r.respond_to?(:content)
|
|
111
|
+
new(r.status_code, r.content)
|
|
112
|
+
elsif r && r.kind_of?(Hash) && r.values.size > 0
|
|
113
|
+
r = r.values[0]
|
|
114
|
+
if r.respond_to?(:status_code) && r.respond_to?(:content)
|
|
115
|
+
new(r.status_code, r.content)
|
|
116
|
+
else
|
|
117
|
+
error("Invalid operation result content: #{r.inspect}")
|
|
118
|
+
end
|
|
119
|
+
elsif r.nil?
|
|
120
|
+
error("No results")
|
|
121
|
+
else
|
|
122
|
+
error("Invalid operation result type: #{results.inspect}")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Create new success status
|
|
127
|
+
#
|
|
128
|
+
# === Parameters
|
|
129
|
+
# content(Object):: Any data associated with successful results - defaults to nil
|
|
130
|
+
#
|
|
131
|
+
# === Return
|
|
132
|
+
# (OperationResult):: Corresponding result
|
|
133
|
+
def self.success(content = nil)
|
|
134
|
+
OperationResult.new(SUCCESS, content)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Create new error status
|
|
138
|
+
#
|
|
139
|
+
# === Parameters
|
|
140
|
+
# message(String):: Error description
|
|
141
|
+
# exception(Exception|String):: Associated exception or other parenthetical error information
|
|
142
|
+
# backtrace(Symbol):: Exception backtrace extent: :no_trace, :caller, or :trace,
|
|
143
|
+
# defaults to :caller
|
|
144
|
+
#
|
|
145
|
+
# === Return
|
|
146
|
+
# (OperationResult):: Corresponding result
|
|
147
|
+
def self.error(message, exception = nil, backtrace = :caller)
|
|
148
|
+
OperationResult.new(ERROR, Log.format(message, exception, backtrace))
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Create new continue status
|
|
152
|
+
#
|
|
153
|
+
# === Parameters
|
|
154
|
+
# content(Object):: Any data associated with continue - defaults to nil
|
|
155
|
+
#
|
|
156
|
+
# === Return
|
|
157
|
+
# (OperationResult):: Corresponding result
|
|
158
|
+
def self.continue(content = nil)
|
|
159
|
+
OperationResult.new(CONTINUE, content)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Create new retry status
|
|
163
|
+
#
|
|
164
|
+
# === Parameters
|
|
165
|
+
# content(Object):: Any data associated with retry - defaults to nil
|
|
166
|
+
#
|
|
167
|
+
# === Return
|
|
168
|
+
# (OperationResult):: Corresponding result
|
|
169
|
+
def self.retry(content = nil)
|
|
170
|
+
OperationResult.new(RETRY, content)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Create new non-delivery status
|
|
174
|
+
#
|
|
175
|
+
# === Parameters
|
|
176
|
+
# reason(String):: Non-delivery reason from NON_DELIVERY_REASONS
|
|
177
|
+
#
|
|
178
|
+
# === Return
|
|
179
|
+
# (OperationResult):: Corresponding result
|
|
180
|
+
def self.non_delivery(reason)
|
|
181
|
+
OperationResult.new(NON_DELIVERY, reason)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Create new multicast status
|
|
185
|
+
# Deprecated for agents at version 13 or above
|
|
186
|
+
#
|
|
187
|
+
# === Parameters
|
|
188
|
+
# targets(Array):: Identity of targets to which request was published
|
|
189
|
+
#
|
|
190
|
+
# === Return
|
|
191
|
+
# (OperationResult):: Corresponding result
|
|
192
|
+
def self.multicast(targets)
|
|
193
|
+
OperationResult.new(MULTICAST, targets)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Was last operation successful?
|
|
197
|
+
#
|
|
198
|
+
# === Return
|
|
199
|
+
# true:: If status is SUCCESS or CONTINUE
|
|
200
|
+
# false:: Otherwise
|
|
201
|
+
def success?
|
|
202
|
+
status_code == SUCCESS || status_code == CONTINUE
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Was last operation unsuccessful?
|
|
206
|
+
#
|
|
207
|
+
# === Return
|
|
208
|
+
# true:: If status is ERROR or NON_DELIVERY
|
|
209
|
+
# false:: Otherwise
|
|
210
|
+
def error?
|
|
211
|
+
status_code == ERROR || status_code == NON_DELIVERY
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Was last operation status CONTINUE?
|
|
215
|
+
#
|
|
216
|
+
# === Return
|
|
217
|
+
# true:: If status is CONTINUE
|
|
218
|
+
# false:: Otherwise
|
|
219
|
+
def continue?
|
|
220
|
+
status_code == CONTINUE
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Was last operation status RETRY?
|
|
224
|
+
#
|
|
225
|
+
# === Return
|
|
226
|
+
# true:: If status is RETRY
|
|
227
|
+
# false:: Otherwise
|
|
228
|
+
def retry?
|
|
229
|
+
status_code == RETRY
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Was last operation status NON_DELIVERY?
|
|
233
|
+
#
|
|
234
|
+
# === Return
|
|
235
|
+
# true:: If status is NON_DELIVERY
|
|
236
|
+
# false:: Otherwise
|
|
237
|
+
def non_delivery?
|
|
238
|
+
status_code == NON_DELIVERY
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Was last operation status MULTICAST?
|
|
242
|
+
# Deprecated for agents at version 13 or above
|
|
243
|
+
#
|
|
244
|
+
# === Return
|
|
245
|
+
# true:: If status is MULTICAST
|
|
246
|
+
# false:: Otherwise
|
|
247
|
+
def multicast?
|
|
248
|
+
status_code == MULTICAST
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Array of serialized fields given to constructor
|
|
252
|
+
def serialized_members
|
|
253
|
+
[@status_code, @content]
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
end # OperationResult
|
|
257
|
+
|
|
258
|
+
# Helper module to simplify result construction
|
|
259
|
+
module OperationResultHelper
|
|
260
|
+
|
|
261
|
+
def success_result(*args) OperationResult.success(*args) end
|
|
262
|
+
def error_result(*args) OperationResult.error(*args) end
|
|
263
|
+
def continue_result(*args) OperationResult.continue(*args) end
|
|
264
|
+
def retry_result(*args) OperationResult.retry(*args) end
|
|
265
|
+
def non_delivery_result(*args) OperationResult.non_delivery(*args) end
|
|
266
|
+
def result_from(*args) OperationResult.from_results(*args) end
|
|
267
|
+
|
|
268
|
+
end # OperationResultHelper
|
|
269
|
+
|
|
270
|
+
end # RightScale
|
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
# Copyright (c) 2009-2011 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
|
+
if source =~ /(.*)json_class":"Nanite::(.*)/
|
|
28
|
+
JSON.parser.new( Regexp.last_match(1) + 'json_class":"RightScale::' + Regexp.last_match(2), opts).parse
|
|
29
|
+
else
|
|
30
|
+
JSON.parser.new(source, opts).parse
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
module RightScale
|
|
38
|
+
|
|
39
|
+
# Base class for all packets flowing through the mappers
|
|
40
|
+
# Knows how to dump itself to MessagePack or JSON
|
|
41
|
+
class Packet
|
|
42
|
+
|
|
43
|
+
# Current version of protocol
|
|
44
|
+
VERSION = AgentConfig.protocol_version
|
|
45
|
+
|
|
46
|
+
# Default version for packet senders unaware of this versioning
|
|
47
|
+
DEFAULT_VERSION = 0
|
|
48
|
+
|
|
49
|
+
# Shard scope value meaning restrict sending request only to agents with no shard id
|
|
50
|
+
GLOBAL = 0
|
|
51
|
+
|
|
52
|
+
attr_accessor :size
|
|
53
|
+
|
|
54
|
+
def initialize
|
|
55
|
+
raise NotImplementedError.new("#{self.class.name} is an abstract class.")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Create packet from unmarshalled MessagePack data
|
|
59
|
+
#
|
|
60
|
+
# === Parameters
|
|
61
|
+
# o(Hash):: MessagePack data
|
|
62
|
+
#
|
|
63
|
+
# === Return
|
|
64
|
+
# (Packet):: New packet
|
|
65
|
+
def self.msgpack_create(o)
|
|
66
|
+
create(o)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Create packet from unmarshalled JSON data
|
|
70
|
+
#
|
|
71
|
+
# === Parameters
|
|
72
|
+
# o(Hash):: MessagePack data
|
|
73
|
+
#
|
|
74
|
+
# === Return
|
|
75
|
+
# (Packet):: New packet
|
|
76
|
+
def self.json_create(o)
|
|
77
|
+
create(o)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Marshal packet into MessagePack format
|
|
81
|
+
#
|
|
82
|
+
# === Parameters
|
|
83
|
+
# a(Array):: Arguments
|
|
84
|
+
#
|
|
85
|
+
# === Return
|
|
86
|
+
# msg(String):: Marshalled packet
|
|
87
|
+
def to_msgpack(*a)
|
|
88
|
+
msg = {
|
|
89
|
+
'msgpack_class' => self.class.name,
|
|
90
|
+
'data' => instance_variables.inject({}) { |m, ivar| m[ivar.to_s.sub(/@/,'')] = instance_variable_get(ivar); m },
|
|
91
|
+
'size' => nil
|
|
92
|
+
}.to_msgpack(*a)
|
|
93
|
+
@size = msg.size
|
|
94
|
+
msg.sub!(/size\300/) { |m| "size" + @size.to_msgpack }
|
|
95
|
+
msg
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Marshal packet into JSON format
|
|
99
|
+
#
|
|
100
|
+
# === Parameters
|
|
101
|
+
# a(Array):: Arguments
|
|
102
|
+
#
|
|
103
|
+
# === Return
|
|
104
|
+
# js(String):: Marshalled packet
|
|
105
|
+
def to_json(*a)
|
|
106
|
+
# Hack to override RightScale namespace with Nanite for downward compatibility
|
|
107
|
+
class_name = self.class.name
|
|
108
|
+
if class_name =~ /^RightScale::(.*)/
|
|
109
|
+
class_name = "Nanite::" + Regexp.last_match(1)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
js = {
|
|
113
|
+
'json_class' => class_name,
|
|
114
|
+
'data' => instance_variables.inject({}) { |m, ivar| m[ivar.to_s.sub(/@/,'')] = instance_variable_get(ivar); m }
|
|
115
|
+
}.to_json(*a)
|
|
116
|
+
@size = js.size
|
|
117
|
+
js = js.chop + ",\"size\":#{@size}}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Name of packet in lower snake case
|
|
121
|
+
#
|
|
122
|
+
# === Return
|
|
123
|
+
# (String):: Packet name
|
|
124
|
+
def name
|
|
125
|
+
self.class.to_s.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Generate log representation
|
|
129
|
+
#
|
|
130
|
+
# === Parameters
|
|
131
|
+
# filter(Array(Symbol)):: Attributes to be included in output
|
|
132
|
+
# version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
|
|
133
|
+
#
|
|
134
|
+
# === Return
|
|
135
|
+
# log_msg(String):: Log representation
|
|
136
|
+
def to_s(filter = nil, version = nil)
|
|
137
|
+
v = __send__(version) if version
|
|
138
|
+
v = (v && v != DEFAULT_VERSION) ? " v#{v}" : ""
|
|
139
|
+
log_msg = "[#{name}#{v}]"
|
|
140
|
+
duration = ", #{enough_precision(@duration)} sec" if @duration && (filter.nil? || filter.include?(:duration))
|
|
141
|
+
log_msg += " (#{@size.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")} bytes#{duration})" if @size && !@size.to_s.empty?
|
|
142
|
+
log_msg
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Determine enough precision for floating point value to give at least two significant
|
|
146
|
+
# digits and then convert the value to a decimal digit string of that precision
|
|
147
|
+
#
|
|
148
|
+
# === Parameters
|
|
149
|
+
# value(Float):: Value to be converted
|
|
150
|
+
#
|
|
151
|
+
# === Return
|
|
152
|
+
# (String):: Floating point digit string
|
|
153
|
+
def enough_precision(value)
|
|
154
|
+
scale = [1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0]
|
|
155
|
+
enough = lambda { |v| (v >= 10.0 ? 0 :
|
|
156
|
+
(v >= 1.0 ? 1 :
|
|
157
|
+
(v >= 0.1 ? 2 :
|
|
158
|
+
(v >= 0.01 ? 3 :
|
|
159
|
+
(v > 0.001 ? 4 :
|
|
160
|
+
(v > 0.0 ? 5 : 0)))))) }
|
|
161
|
+
digit_str = lambda { |p, v| sprintf("%.#{p}f", (v * scale[p]).round / scale[p])}
|
|
162
|
+
digit_str.call(enough.call(value), value)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Generate log friendly serialized identity
|
|
166
|
+
# Result marked with leading '*' if not same as original identity
|
|
167
|
+
#
|
|
168
|
+
# === Parameters
|
|
169
|
+
# id(String):: Serialized identity
|
|
170
|
+
#
|
|
171
|
+
# === Return
|
|
172
|
+
# (String):: Log friendly serialized identity
|
|
173
|
+
def id_to_s(id)
|
|
174
|
+
modified_id = AgentIdentity.compatible_serialized(id)
|
|
175
|
+
if id == modified_id then modified_id else "*#{modified_id}" end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Convert serialized AgentIdentity to compatible format
|
|
179
|
+
#
|
|
180
|
+
# === Parameters
|
|
181
|
+
# id(String):: Serialized identity
|
|
182
|
+
#
|
|
183
|
+
# === Return
|
|
184
|
+
# (String):: Compatible serialized identity
|
|
185
|
+
def self.compatible(id)
|
|
186
|
+
AgentIdentity.compatible_serialized(id)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Get target to be used for encrypting the packet
|
|
190
|
+
#
|
|
191
|
+
# === Return
|
|
192
|
+
# (String):: Target
|
|
193
|
+
def target_for_encryption
|
|
194
|
+
nil
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Whether the packet is one that does not have an associated response
|
|
198
|
+
#
|
|
199
|
+
# === Return
|
|
200
|
+
# (Boolean):: Defaults to true
|
|
201
|
+
def one_way
|
|
202
|
+
true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Generate token used to trace execution of operation across multiple packets
|
|
206
|
+
#
|
|
207
|
+
# === Return
|
|
208
|
+
# tr(String):: Trace token, may be empty
|
|
209
|
+
def trace
|
|
210
|
+
audit_id = self.respond_to?(:payload) && payload.is_a?(Hash) && (payload['audit_id'] || payload[:audit_id])
|
|
211
|
+
tok = self.respond_to?(:token) && token
|
|
212
|
+
tr = ''
|
|
213
|
+
if audit_id || tok
|
|
214
|
+
tr = '<'
|
|
215
|
+
if audit_id
|
|
216
|
+
tr += audit_id.to_s
|
|
217
|
+
tr += ':' if tok
|
|
218
|
+
end
|
|
219
|
+
tr += tok if tok
|
|
220
|
+
tr += '>'
|
|
221
|
+
end
|
|
222
|
+
tr
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Retrieve protocol version of original creator of packet
|
|
226
|
+
#
|
|
227
|
+
# === Return
|
|
228
|
+
# (Integer) Received protocol version
|
|
229
|
+
def recv_version
|
|
230
|
+
@version[0]
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Retrieve protocol version of packet for use when sending packet
|
|
234
|
+
#
|
|
235
|
+
# === Return
|
|
236
|
+
# (Integer) Send protocol version
|
|
237
|
+
def send_version
|
|
238
|
+
@version[1]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Set protocol version of packet for use when sending packet
|
|
242
|
+
def send_version=(value)
|
|
243
|
+
@version[1] = value
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
end # Packet
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# Packet for a work request for an actor node that has an expected result
|
|
250
|
+
class Request < Packet
|
|
251
|
+
|
|
252
|
+
attr_accessor :from, :scope, :payload, :type, :token, :reply_to, :selector, :target, :persistent, :expires_at,
|
|
253
|
+
:tags, :tries
|
|
254
|
+
|
|
255
|
+
DEFAULT_OPTIONS = {:selector => :any}
|
|
256
|
+
|
|
257
|
+
# Create packet
|
|
258
|
+
#
|
|
259
|
+
# === Parameters
|
|
260
|
+
# type(String):: Dispatch route for the request
|
|
261
|
+
# payload(Any):: Arbitrary data that is transferred to actor
|
|
262
|
+
# opts(Hash):: Optional settings:
|
|
263
|
+
# :from(String):: Sender identity
|
|
264
|
+
# :scope(Hash):: Define behavior that should be used to resolve tag based routing
|
|
265
|
+
# :token(String):: Generated request id that a mapper uses to identify replies
|
|
266
|
+
# :reply_to(String):: Identity of the node that actor replies to, usually a mapper itself
|
|
267
|
+
# :selector(Symbol):: Selector used to route the request: :any or :all, defaults to :any,
|
|
268
|
+
# :all deprecated for version 13 and above
|
|
269
|
+
# :target(String):: Target recipient
|
|
270
|
+
# :persistent(Boolean):: Indicates if this request should be saved to persistent storage
|
|
271
|
+
# by the AMQP broker
|
|
272
|
+
# :expires_at(Integer|nil):: Time in seconds in Unix-epoch when this request expires and
|
|
273
|
+
# is to be ignored by the receiver; value 0 means never expire; defaults to 0
|
|
274
|
+
# :tags(Array(Symbol)):: List of tags to be used for selecting target for this request
|
|
275
|
+
# :tries(Array):: List of tokens for previous attempts to send this request
|
|
276
|
+
# version(Array):: Protocol version of the original creator of the packet followed by the
|
|
277
|
+
# protocol version of the packet contents to be used when sending
|
|
278
|
+
# size(Integer):: Size of request in bytes used only for marshalling
|
|
279
|
+
def initialize(type, payload, opts = {}, version = [VERSION, VERSION], size = nil)
|
|
280
|
+
opts = DEFAULT_OPTIONS.merge(opts)
|
|
281
|
+
@type = type
|
|
282
|
+
@payload = payload
|
|
283
|
+
@from = opts[:from]
|
|
284
|
+
@scope = opts[:scope]
|
|
285
|
+
@token = opts[:token]
|
|
286
|
+
@reply_to = opts[:reply_to]
|
|
287
|
+
@selector = opts[:selector]
|
|
288
|
+
@selector = :any if ["least_loaded", "random"].include?(@selector.to_s)
|
|
289
|
+
@target = opts[:target]
|
|
290
|
+
@persistent = opts[:persistent]
|
|
291
|
+
@expires_at = opts[:expires_at] || 0
|
|
292
|
+
@tags = opts[:tags] || []
|
|
293
|
+
@tries = opts[:tries] || []
|
|
294
|
+
@version = version
|
|
295
|
+
@size = size
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Test whether the request is being fanned out to multiple targets
|
|
299
|
+
#
|
|
300
|
+
# === Return
|
|
301
|
+
# (Boolean):: true if is multicast, otherwise false
|
|
302
|
+
def fanout?
|
|
303
|
+
@selector.to_s == 'all'
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Create packet from unmarshalled data
|
|
307
|
+
#
|
|
308
|
+
# === Parameters
|
|
309
|
+
# o(Hash):: Unmarshalled data
|
|
310
|
+
#
|
|
311
|
+
# === Return
|
|
312
|
+
# (Request):: New packet
|
|
313
|
+
def self.create(o)
|
|
314
|
+
i = o['data']
|
|
315
|
+
expires_at = if i.has_key?('created_at')
|
|
316
|
+
created_at = i['created_at'].to_i
|
|
317
|
+
created_at > 0 ? created_at + (15 * 60) : 0
|
|
318
|
+
else
|
|
319
|
+
i['expires_at']
|
|
320
|
+
end
|
|
321
|
+
new(i['type'], i['payload'], { :from => self.compatible(i['from']), :scope => i['scope'],
|
|
322
|
+
:token => i['token'], :reply_to => self.compatible(i['reply_to']),
|
|
323
|
+
:selector => i['selector'], :target => self.compatible(i['target']),
|
|
324
|
+
:persistent => i['persistent'], :tags => i['tags'],
|
|
325
|
+
:expires_at => expires_at, :tries => i['tries'] },
|
|
326
|
+
i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Generate log representation
|
|
330
|
+
#
|
|
331
|
+
# === Parameters
|
|
332
|
+
# filter(Array(Symbol)):: Attributes to be included in output
|
|
333
|
+
# version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
|
|
334
|
+
#
|
|
335
|
+
# === Return
|
|
336
|
+
# log_msg(String):: Log representation
|
|
337
|
+
def to_s(filter = nil, version = nil)
|
|
338
|
+
payload = PayloadFormatter.log(@type, @payload)
|
|
339
|
+
log_msg = "#{super(filter, version)} #{trace} #{@type}"
|
|
340
|
+
log_msg += " #{payload}" if payload
|
|
341
|
+
log_msg += " from #{id_to_s(@from)}" if filter.nil? || filter.include?(:from)
|
|
342
|
+
log_msg += ", target #{id_to_s(@target)}" if @target && (filter.nil? || filter.include?(:target))
|
|
343
|
+
log_msg += ", scope #{@scope.inspect}" if @scope && (filter.nil? || filter.include?(:scope))
|
|
344
|
+
log_msg += ", fanout" if (filter.nil? || filter.include?(:fanout)) && fanout?
|
|
345
|
+
log_msg += ", reply_to #{id_to_s(@reply_to)}" if @reply_to && (filter.nil? || filter.include?(:reply_to))
|
|
346
|
+
log_msg += ", tags #{@tags.inspect}" if @tags && !@tags.empty? && (filter.nil? || filter.include?(:tags))
|
|
347
|
+
log_msg += ", persistent" if @persistent && (filter.nil? || filter.include?(:persistent))
|
|
348
|
+
log_msg += ", tries #{tries_to_s}" if @tries && !@tries.empty? && (filter.nil? || filter.include?(:tries))
|
|
349
|
+
log_msg += ", payload #{@payload.inspect}" if filter.nil? || filter.include?(:payload)
|
|
350
|
+
log_msg
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Convert tries list to string representation
|
|
354
|
+
#
|
|
355
|
+
# === Return
|
|
356
|
+
# log_msg(String):: Tries list
|
|
357
|
+
def tries_to_s
|
|
358
|
+
@tries.map { |t| "<#{t}>" }.join(", ")
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Get target to be used for encrypting the packet
|
|
362
|
+
#
|
|
363
|
+
# === Return
|
|
364
|
+
# (String):: Target
|
|
365
|
+
def target_for_encryption
|
|
366
|
+
@target
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Whether the packet is one that does not have an associated response
|
|
370
|
+
#
|
|
371
|
+
# === Return
|
|
372
|
+
# false:: Always return false
|
|
373
|
+
def one_way
|
|
374
|
+
false
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
end # Request
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# Packet for a work request for an actor node that has no result, i.e., one-way request
|
|
381
|
+
class Push < Packet
|
|
382
|
+
|
|
383
|
+
attr_accessor :from, :scope, :payload, :type, :token, :selector, :target, :persistent, :expires_at, :tags
|
|
384
|
+
|
|
385
|
+
DEFAULT_OPTIONS = {:selector => :any}
|
|
386
|
+
|
|
387
|
+
# Create packet
|
|
388
|
+
#
|
|
389
|
+
# === Parameters
|
|
390
|
+
# type(String):: Dispatch route for the request
|
|
391
|
+
# payload(Any):: Arbitrary data that is transferred to actor
|
|
392
|
+
# opts(Hash):: Optional settings:
|
|
393
|
+
# :from(String):: Sender identity
|
|
394
|
+
# :scope(Hash):: Define behavior that should be used to resolve tag based routing
|
|
395
|
+
# :token(String):: Generated request id that a mapper uses to identify replies
|
|
396
|
+
# :selector(Symbol):: Selector used to route the request: :any or :all, defaults to :any
|
|
397
|
+
# :target(String):: Target recipient
|
|
398
|
+
# :persistent(Boolean):: Indicates if this request should be saved to persistent storage
|
|
399
|
+
# by the AMQP broker
|
|
400
|
+
# :expires_at(Integer|nil):: Time in seconds in Unix-epoch when this request expires and
|
|
401
|
+
# is to be ignored by the receiver; value 0 means never expire; defaults to 0
|
|
402
|
+
# :tags(Array(Symbol)):: List of tags to be used for selecting target for this request
|
|
403
|
+
# :tries(Array):: List of tokens for previous attempts to send this request (only here
|
|
404
|
+
# for consistency with Request)
|
|
405
|
+
# version(Array):: Protocol version of the original creator of the packet followed by the
|
|
406
|
+
# protocol version of the packet contents to be used when sending
|
|
407
|
+
# size(Integer):: Size of request in bytes used only for marshalling
|
|
408
|
+
def initialize(type, payload, opts = {}, version = [VERSION, VERSION], size = nil)
|
|
409
|
+
opts = DEFAULT_OPTIONS.merge(opts)
|
|
410
|
+
@type = type
|
|
411
|
+
@payload = payload
|
|
412
|
+
@from = opts[:from]
|
|
413
|
+
@scope = opts[:scope]
|
|
414
|
+
@token = opts[:token]
|
|
415
|
+
@selector = opts[:selector]
|
|
416
|
+
@selector = :any if ["least_loaded", "random"].include?(@selector.to_s)
|
|
417
|
+
@target = opts[:target]
|
|
418
|
+
@persistent = opts[:persistent]
|
|
419
|
+
@expires_at = opts[:expires_at] || 0
|
|
420
|
+
@tags = opts[:tags] || []
|
|
421
|
+
@version = version
|
|
422
|
+
@size = size
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Test whether the request is being fanned out to multiple targets
|
|
426
|
+
#
|
|
427
|
+
# === Return
|
|
428
|
+
# (Boolean):: true if is fanout, otherwise false
|
|
429
|
+
def fanout?
|
|
430
|
+
@selector.to_s == 'all'
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# Keep interface consistent with Request packets
|
|
434
|
+
# A push never gets retried
|
|
435
|
+
#
|
|
436
|
+
# === Return
|
|
437
|
+
# []:: Always return empty array
|
|
438
|
+
def tries
|
|
439
|
+
[]
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Create packet from unmarshalled data
|
|
443
|
+
#
|
|
444
|
+
# === Parameters
|
|
445
|
+
# o(Hash):: Unmarshalled data
|
|
446
|
+
#
|
|
447
|
+
# === Return
|
|
448
|
+
# (Push):: New packet
|
|
449
|
+
def self.create(o)
|
|
450
|
+
i = o['data']
|
|
451
|
+
new(i['type'], i['payload'], { :from => self.compatible(i['from']), :scope => i['scope'],
|
|
452
|
+
:token => i['token'], :selector => i['selector'],
|
|
453
|
+
:target => self.compatible(i['target']), :persistent => i['persistent'],
|
|
454
|
+
:tags => i['tags'], :expires_at => i['expires_at'] },
|
|
455
|
+
i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Generate log representation
|
|
459
|
+
#
|
|
460
|
+
# === Parameters
|
|
461
|
+
# filter(Array(Symbol)):: Attributes to be included in output
|
|
462
|
+
# version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
|
|
463
|
+
#
|
|
464
|
+
# === Return
|
|
465
|
+
# log_msg(String):: Log representation
|
|
466
|
+
def to_s(filter = nil, version = nil)
|
|
467
|
+
payload = PayloadFormatter.log(@type, @payload)
|
|
468
|
+
log_msg = "#{super(filter, version)} #{trace} #{@type}"
|
|
469
|
+
log_msg += " #{payload}" if payload
|
|
470
|
+
log_msg += " from #{id_to_s(@from)}" if filter.nil? || filter.include?(:from)
|
|
471
|
+
log_msg += ", target #{id_to_s(@target)}" if @target && (filter.nil? || filter.include?(:target))
|
|
472
|
+
log_msg += ", scope #{@scope.inspect}" if @scope && (filter.nil? || filter.include?(:scope))
|
|
473
|
+
log_msg += ", fanout" if (filter.nil? || filter.include?(:fanout)) && fanout?
|
|
474
|
+
log_msg += ", tags #{@tags.inspect}" if @tags && !@tags.empty? && (filter.nil? || filter.include?(:tags))
|
|
475
|
+
log_msg += ", persistent" if @persistent && (filter.nil? || filter.include?(:persistent))
|
|
476
|
+
log_msg += ", payload #{@payload.inspect}" if filter.nil? || filter.include?(:payload)
|
|
477
|
+
log_msg
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
# Get target to be used for encrypting the packet
|
|
481
|
+
#
|
|
482
|
+
# === Return
|
|
483
|
+
# (String):: Target
|
|
484
|
+
def target_for_encryption
|
|
485
|
+
@target
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
end # Push
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
# Packet for a work result notification sent from actor node
|
|
492
|
+
class Result < Packet
|
|
493
|
+
|
|
494
|
+
attr_accessor :token, :results, :to, :from, :request_from, :tries, :persistent, :duration
|
|
495
|
+
|
|
496
|
+
# Create packet
|
|
497
|
+
#
|
|
498
|
+
# === Parameters
|
|
499
|
+
# token(String):: Generated request id that a mapper uses to identify replies
|
|
500
|
+
# to(String):: Identity of the node to which result should be delivered
|
|
501
|
+
# results(Any):: Arbitrary data that is transferred from actor, a result of actor's work
|
|
502
|
+
# from(String):: Sender identity
|
|
503
|
+
# request_from(String):: Identity of the agent that sent the original request
|
|
504
|
+
# tries(Array):: List of tokens for previous attempts to send associated request
|
|
505
|
+
# persistent(Boolean):: Indicates if this result should be saved to persistent storage
|
|
506
|
+
# by the AMQP broker
|
|
507
|
+
# duration(Float):: Number of seconds required to produce the result
|
|
508
|
+
# version(Array):: Protocol version of the original creator of the packet followed by the
|
|
509
|
+
# protocol version of the packet contents to be used when sending
|
|
510
|
+
# size(Integer):: Size of request in bytes used only for marshalling
|
|
511
|
+
def initialize(token, to, results, from, request_from = nil, tries = nil, persistent = nil, duration = nil,
|
|
512
|
+
version = [VERSION, VERSION], size = nil)
|
|
513
|
+
@token = token
|
|
514
|
+
@to = to
|
|
515
|
+
@results = results
|
|
516
|
+
@from = from
|
|
517
|
+
@request_from = request_from
|
|
518
|
+
@tries = tries || []
|
|
519
|
+
@persistent = persistent
|
|
520
|
+
@duration = duration
|
|
521
|
+
@version = version
|
|
522
|
+
@size = size
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
# Create packet from unmarshalled data
|
|
526
|
+
#
|
|
527
|
+
# === Parameters
|
|
528
|
+
# o(Hash):: Unmarshalled data
|
|
529
|
+
#
|
|
530
|
+
# === Return
|
|
531
|
+
# (Result):: New packet
|
|
532
|
+
def self.create(o)
|
|
533
|
+
i = o['data']
|
|
534
|
+
new(i['token'], self.compatible(i['to']), i['results'], self.compatible(i['from']),
|
|
535
|
+
self.compatible(i['request_from']), i['tries'], i['persistent'], i['duration'],
|
|
536
|
+
i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
# Generate log representation
|
|
540
|
+
#
|
|
541
|
+
# === Parameters
|
|
542
|
+
# filter(Array(Symbol)):: Attributes to be included in output
|
|
543
|
+
# version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
|
|
544
|
+
#
|
|
545
|
+
# === Return
|
|
546
|
+
# log_msg(String):: Log representation
|
|
547
|
+
def to_s(filter = nil, version = nil)
|
|
548
|
+
log_msg = "#{super(filter, version)} #{trace}"
|
|
549
|
+
log_msg += " from #{id_to_s(@from)}" if filter.nil? || filter.include?(:from)
|
|
550
|
+
log_msg += " to #{id_to_s(@to)}" if filter.nil? || filter.include?(:to)
|
|
551
|
+
log_msg += ", request_from #{id_to_s(@request_from)}" if @request_from && (filter.nil? || filter.include?(:request_from))
|
|
552
|
+
log_msg += ", persistent" if @persistent && (filter.nil? || filter.include?(:persistent))
|
|
553
|
+
log_msg += ", tries #{tries_to_s}" if @tries && !@tries.empty? && (filter.nil? || filter.include?(:tries))
|
|
554
|
+
if filter.nil? || !filter.include?(:results)
|
|
555
|
+
if !@results.nil?
|
|
556
|
+
if @results.is_a?(RightScale::OperationResult) # Will be true when logging a 'SEND'
|
|
557
|
+
res = @results
|
|
558
|
+
elsif @results.is_a?(Hash) && @results.size == 1 # Will be true when logging a 'RECV' for version 9 or below
|
|
559
|
+
res = @results.values.first
|
|
560
|
+
end
|
|
561
|
+
log_msg += " #{res.to_s}" if res
|
|
562
|
+
end
|
|
563
|
+
else
|
|
564
|
+
log_msg += " results #{@results.inspect}"
|
|
565
|
+
end
|
|
566
|
+
log_msg
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# Convert tries list to string representation
|
|
570
|
+
#
|
|
571
|
+
# === Return
|
|
572
|
+
# log_msg(String):: Tries list
|
|
573
|
+
def tries_to_s
|
|
574
|
+
log_msg = ""
|
|
575
|
+
@tries.each { |r| log_msg += "<#{r}>, " }
|
|
576
|
+
log_msg = log_msg[0..-3] if log_msg.size > 1
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
# Get target to be used for encrypting the packet
|
|
580
|
+
#
|
|
581
|
+
# === Return
|
|
582
|
+
# (String):: Target
|
|
583
|
+
def target_for_encryption
|
|
584
|
+
@to
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
end # Result
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
# Packet for carrying statistics
|
|
591
|
+
class Stats < Packet
|
|
592
|
+
|
|
593
|
+
attr_accessor :data, :token, :from
|
|
594
|
+
|
|
595
|
+
# Create packet
|
|
596
|
+
#
|
|
597
|
+
# === Parameters
|
|
598
|
+
# data(Object):: Data
|
|
599
|
+
# from(String):: Identity of sender
|
|
600
|
+
# version(Array):: Protocol version of the original creator of the packet followed by the
|
|
601
|
+
# protocol version of the packet contents to be used when sending
|
|
602
|
+
# size(Integer):: Size of request in bytes used only for marshalling
|
|
603
|
+
def initialize(data, from, version = [VERSION, VERSION], size = nil)
|
|
604
|
+
@data = data
|
|
605
|
+
@from = from
|
|
606
|
+
@version = version
|
|
607
|
+
@size = size
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
# Create packet from unmarshalled data
|
|
611
|
+
#
|
|
612
|
+
# === Parameters
|
|
613
|
+
# o(Hash):: Unmarshalled data
|
|
614
|
+
#
|
|
615
|
+
# === Return
|
|
616
|
+
# (Result):: New packet
|
|
617
|
+
def self.create(o)
|
|
618
|
+
i = o['data']
|
|
619
|
+
new(i['data'], self.compatible(i['from']), i['version'] || [DEFAULT_VERSION, DEFAULT_VERSION], o['size'])
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
# Generate log representation
|
|
623
|
+
#
|
|
624
|
+
# === Parameters
|
|
625
|
+
# filter(Array(Symbol)):: Attributes to be included in output
|
|
626
|
+
# version(Symbol|nil):: Version to display: :recv_version, :send_version, or nil meaning none
|
|
627
|
+
#
|
|
628
|
+
# === Return
|
|
629
|
+
# log_msg(String):: Log representation
|
|
630
|
+
def to_s(filter = nil, version = nil)
|
|
631
|
+
log_msg = "#{super(filter, version)} #{id_to_s(@from)}"
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
end # Stats
|
|
635
|
+
|
|
636
|
+
end # RightScale
|
|
637
|
+
|