right_agent 2.0.7-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +82 -0
- data/Rakefile +113 -0
- data/lib/right_agent.rb +59 -0
- data/lib/right_agent/actor.rb +182 -0
- data/lib/right_agent/actor_registry.rb +76 -0
- data/lib/right_agent/actors/agent_manager.rb +232 -0
- data/lib/right_agent/agent.rb +1149 -0
- data/lib/right_agent/agent_config.rb +480 -0
- data/lib/right_agent/agent_identity.rb +210 -0
- data/lib/right_agent/agent_tag_manager.rb +237 -0
- data/lib/right_agent/audit_formatter.rb +107 -0
- data/lib/right_agent/clients.rb +31 -0
- data/lib/right_agent/clients/api_client.rb +383 -0
- data/lib/right_agent/clients/auth_client.rb +247 -0
- data/lib/right_agent/clients/balanced_http_client.rb +369 -0
- data/lib/right_agent/clients/base_retry_client.rb +495 -0
- data/lib/right_agent/clients/right_http_client.rb +279 -0
- data/lib/right_agent/clients/router_client.rb +493 -0
- data/lib/right_agent/command.rb +30 -0
- data/lib/right_agent/command/agent_manager_commands.rb +150 -0
- data/lib/right_agent/command/command_client.rb +136 -0
- data/lib/right_agent/command/command_constants.rb +33 -0
- data/lib/right_agent/command/command_io.rb +126 -0
- data/lib/right_agent/command/command_parser.rb +87 -0
- data/lib/right_agent/command/command_runner.rb +118 -0
- data/lib/right_agent/command/command_serializer.rb +63 -0
- data/lib/right_agent/connectivity_checker.rb +179 -0
- data/lib/right_agent/console.rb +65 -0
- data/lib/right_agent/core_payload_types.rb +44 -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 +100 -0
- data/lib/right_agent/core_payload_types/dev_repository.rb +76 -0
- data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
- data/lib/right_agent/core_payload_types/executable_bundle.rb +130 -0
- data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
- data/lib/right_agent/core_payload_types/login_user.rb +79 -0
- data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
- data/lib/right_agent/core_payload_types/recipe_instantiation.rb +73 -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 +94 -0
- data/lib/right_agent/core_payload_types/runlist_policy.rb +44 -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/dispatched_cache.rb +109 -0
- data/lib/right_agent/dispatcher.rb +272 -0
- data/lib/right_agent/enrollment_result.rb +221 -0
- data/lib/right_agent/exceptions.rb +87 -0
- data/lib/right_agent/history.rb +145 -0
- data/lib/right_agent/log.rb +460 -0
- data/lib/right_agent/minimal.rb +46 -0
- data/lib/right_agent/monkey_patches.rb +30 -0
- data/lib/right_agent/monkey_patches/ruby_patch.rb +55 -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/windows_patch.rb +32 -0
- data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +60 -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 +102 -0
- data/lib/right_agent/offline_handler.rb +270 -0
- data/lib/right_agent/operation_result.rb +300 -0
- data/lib/right_agent/packets.rb +673 -0
- data/lib/right_agent/payload_formatter.rb +104 -0
- data/lib/right_agent/pending_requests.rb +128 -0
- data/lib/right_agent/pid_file.rb +159 -0
- data/lib/right_agent/platform.rb +770 -0
- data/lib/right_agent/platform/unix/darwin/platform.rb +102 -0
- data/lib/right_agent/platform/unix/linux/platform.rb +305 -0
- data/lib/right_agent/platform/unix/platform.rb +226 -0
- data/lib/right_agent/platform/windows/mingw/platform.rb +447 -0
- data/lib/right_agent/platform/windows/mswin/platform.rb +236 -0
- data/lib/right_agent/platform/windows/platform.rb +1808 -0
- data/lib/right_agent/protocol_version_mixin.rb +69 -0
- data/lib/right_agent/retryable_request.rb +195 -0
- data/lib/right_agent/scripts/agent_controller.rb +543 -0
- data/lib/right_agent/scripts/agent_deployer.rb +400 -0
- data/lib/right_agent/scripts/common_parser.rb +160 -0
- data/lib/right_agent/scripts/log_level_manager.rb +192 -0
- data/lib/right_agent/scripts/stats_manager.rb +268 -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 +77 -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 +83 -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 +85 -0
- data/lib/right_agent/sender.rb +792 -0
- data/lib/right_agent/serialize.rb +29 -0
- data/lib/right_agent/serialize/message_pack.rb +107 -0
- data/lib/right_agent/serialize/secure_serializer.rb +151 -0
- data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
- data/lib/right_agent/serialize/serializable.rb +151 -0
- data/lib/right_agent/serialize/serializer.rb +159 -0
- data/lib/right_agent/subprocess.rb +38 -0
- data/lib/right_agent/tracer.rb +124 -0
- data/right_agent.gemspec +101 -0
- data/spec/actor_registry_spec.rb +80 -0
- data/spec/actor_spec.rb +162 -0
- data/spec/agent_config_spec.rb +235 -0
- data/spec/agent_identity_spec.rb +78 -0
- data/spec/agent_spec.rb +734 -0
- data/spec/agent_tag_manager_spec.rb +319 -0
- data/spec/clients/api_client_spec.rb +423 -0
- data/spec/clients/auth_client_spec.rb +272 -0
- data/spec/clients/balanced_http_client_spec.rb +576 -0
- data/spec/clients/base_retry_client_spec.rb +635 -0
- data/spec/clients/router_client_spec.rb +594 -0
- data/spec/clients/spec_helper.rb +111 -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 +107 -0
- data/spec/command/command_serializer_spec.rb +51 -0
- data/spec/connectivity_checker_spec.rb +83 -0
- data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
- data/spec/core_payload_types/dev_repository_spec.rb +33 -0
- data/spec/core_payload_types/executable_bundle_spec.rb +67 -0
- data/spec/core_payload_types/login_user_spec.rb +102 -0
- data/spec/core_payload_types/recipe_instantiation_spec.rb +81 -0
- data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
- data/spec/core_payload_types/right_script_instantiation_spec.rb +79 -0
- data/spec/core_payload_types/spec_helper.rb +23 -0
- data/spec/dispatched_cache_spec.rb +136 -0
- data/spec/dispatcher_spec.rb +324 -0
- data/spec/enrollment_result_spec.rb +53 -0
- data/spec/history_spec.rb +246 -0
- data/spec/log_spec.rb +192 -0
- data/spec/monkey_patches/eventmachine_spec.rb +62 -0
- data/spec/multiplexer_spec.rb +48 -0
- data/spec/offline_handler_spec.rb +340 -0
- data/spec/operation_result_spec.rb +208 -0
- data/spec/packets_spec.rb +461 -0
- data/spec/pending_requests_spec.rb +136 -0
- data/spec/platform/spec_helper.rb +216 -0
- data/spec/platform/unix/darwin/platform_spec.rb +181 -0
- data/spec/platform/unix/linux/platform_spec.rb +540 -0
- data/spec/platform/unix/spec_helper.rb +149 -0
- data/spec/platform/windows/mingw/platform_spec.rb +222 -0
- data/spec/platform/windows/mswin/platform_spec.rb +259 -0
- data/spec/platform/windows/spec_helper.rb +720 -0
- data/spec/retryable_request_spec.rb +306 -0
- data/spec/secure_identity_spec.rb +50 -0
- data/spec/security/cached_certificate_store_proxy_spec.rb +62 -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 +58 -0
- data/spec/sender_spec.rb +1045 -0
- data/spec/serialize/message_pack_spec.rb +131 -0
- data/spec/serialize/secure_serializer_spec.rb +132 -0
- data/spec/serialize/serializable_spec.rb +90 -0
- data/spec/serialize/serializer_spec.rb +197 -0
- data/spec/spec.opts +2 -0
- data/spec/spec.win32.opts +1 -0
- data/spec/spec_helper.rb +130 -0
- data/spec/tracer_spec.rb +114 -0
- metadata +447 -0
@@ -0,0 +1,210 @@
|
|
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
|
+
# Agent identity management
|
26
|
+
class AgentIdentity
|
27
|
+
|
28
|
+
include ProtocolVersionMixin
|
29
|
+
|
30
|
+
# Cutover time at which agents began using new separator
|
31
|
+
SEPARATOR_EPOCH = Time.at(1256702400) unless defined?(SEPARATOR_EPOCH) # Tue Oct 27 21:00:00 -0700 2009
|
32
|
+
|
33
|
+
# Separator used to differentiate between identity components when serialized
|
34
|
+
ID_SEPARATOR = '-' unless defined?(ID_SEPARATOR)
|
35
|
+
|
36
|
+
# Separator used to differentiate between identity components prior to release 3.4
|
37
|
+
ID_SEPARATOR_OLD = '*' unless defined?(ID_SEPARATOR_OLD)
|
38
|
+
|
39
|
+
# Identity components
|
40
|
+
attr_reader :prefix, :agent_type, :token, :base_id
|
41
|
+
|
42
|
+
# Generate new id
|
43
|
+
#
|
44
|
+
# === Parameters
|
45
|
+
# prefix(String):: Prefix used to scope identity
|
46
|
+
# agent_type(String):: Agent type (e.g. 'core', 'instance')
|
47
|
+
# base_id(Integer):: Unique integer value
|
48
|
+
# token(String):: Unique identity token, will be generated randomly if not provided
|
49
|
+
# separator(String):: Character used to separate identity components, defaults to ID_SEPARATOR
|
50
|
+
#
|
51
|
+
# === Raise
|
52
|
+
# ArgumentError:: Invalid argument
|
53
|
+
def initialize(prefix, agent_type, base_id, token = nil, separator = nil)
|
54
|
+
err = "Prefix cannot contain '#{ID_SEPARATOR}'" if prefix && prefix.include?(ID_SEPARATOR)
|
55
|
+
err = "Prefix cannot contain '#{ID_SEPARATOR_OLD}'" if prefix && prefix.include?(ID_SEPARATOR_OLD)
|
56
|
+
err = "Agent type cannot contain '#{ID_SEPARATOR}'" if agent_type.include?(ID_SEPARATOR)
|
57
|
+
err = "Agent type cannot contain '#{ID_SEPARATOR_OLD}'" if agent_type.include?(ID_SEPARATOR_OLD)
|
58
|
+
err = "Agent type cannot be nil" if agent_type.nil?
|
59
|
+
err = "Agent type cannot be empty" if agent_type.size == 0
|
60
|
+
err = "Base ID must be a positive integer" unless base_id.kind_of?(Integer) && base_id >= 0
|
61
|
+
err = "Token cannot contain '#{ID_SEPARATOR}'" if token && token.include?(ID_SEPARATOR)
|
62
|
+
err = "Token cannot contain '#{ID_SEPARATOR_OLD}'" if token && token.include?(ID_SEPARATOR_OLD)
|
63
|
+
raise ArgumentError, err if err
|
64
|
+
|
65
|
+
@separator = separator || ID_SEPARATOR
|
66
|
+
@prefix = prefix
|
67
|
+
@agent_type = agent_type
|
68
|
+
@token = token || self.class.generate
|
69
|
+
@base_id = base_id
|
70
|
+
end
|
71
|
+
|
72
|
+
# Generate unique identity
|
73
|
+
#
|
74
|
+
# === Return
|
75
|
+
# id(String):: Random 128-bit hexadecimal string
|
76
|
+
def self.generate
|
77
|
+
bytes = Platform.rng.pseudorandom_bytes(16)
|
78
|
+
#Transform into hex string
|
79
|
+
id = bytes.unpack('H*')[0]
|
80
|
+
end
|
81
|
+
|
82
|
+
# Check validity of given serialized identity
|
83
|
+
#
|
84
|
+
# === Parameters
|
85
|
+
# serialized_id(String):: Serialized identity to be tested
|
86
|
+
#
|
87
|
+
# === Return
|
88
|
+
# (Boolean):: true if serialized identity is a valid, otherwise false
|
89
|
+
def self.valid?(serialized_id)
|
90
|
+
valid_parts?(self.compatible_serialized(serialized_id)) if serialized_id
|
91
|
+
end
|
92
|
+
|
93
|
+
# Instantiate by parsing given token
|
94
|
+
#
|
95
|
+
# === Parameters
|
96
|
+
# serialized_id(String):: Valid serialized agent identity (use 'valid?' to check first)
|
97
|
+
#
|
98
|
+
# === Return
|
99
|
+
# (AgentIdentity):: Corresponding agent identity
|
100
|
+
#
|
101
|
+
# === Raise
|
102
|
+
# (ArgumentError):: Serialized agent identity is invalid
|
103
|
+
def self.parse(serialized_id)
|
104
|
+
prefix, agent_type, token, bid, separator = parts(self.compatible_serialized(serialized_id))
|
105
|
+
raise ArgumentError, "Invalid agent identity: #{serialized_id.inspect}" unless prefix && agent_type && token && bid
|
106
|
+
base_id = bid.to_i
|
107
|
+
raise ArgumentError, "Invalid agent identity base ID: #{bid ? bid : bid.inspect}" unless base_id.to_s == bid
|
108
|
+
|
109
|
+
AgentIdentity.new(prefix, agent_type, base_id, token, separator)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Convert serialized agent identity to format valid for given protocol version
|
113
|
+
# Ignore identity that is not in serialized AgentIdentity format
|
114
|
+
#
|
115
|
+
# === Parameters
|
116
|
+
# serialized_id(String):: Serialized agent identity to be converted
|
117
|
+
# version(Integer):: Target protocol version
|
118
|
+
#
|
119
|
+
# === Return
|
120
|
+
# serialized_id(String):: Compatible serialized agent identity
|
121
|
+
def self.compatible_serialized(serialized_id, version = nil)
|
122
|
+
if version.nil? || ProtocolVersionMixin.can_handle_non_nanite_ids?(version)
|
123
|
+
serialized_id = serialized_id[7..-1] if serialized_id =~ /^nanite-|^mapper-|^router-/
|
124
|
+
else
|
125
|
+
serialized_id = "nanite-#{serialized_id}" if self.valid_parts?(serialized_id)
|
126
|
+
end
|
127
|
+
serialized_id
|
128
|
+
end
|
129
|
+
|
130
|
+
# Check whether identity corresponds to an instance agent
|
131
|
+
#
|
132
|
+
# === Return
|
133
|
+
# (Boolean):: true if id corresponds to an instance agent, otherwise false
|
134
|
+
def instance_agent?
|
135
|
+
agent_type == 'instance'
|
136
|
+
end
|
137
|
+
|
138
|
+
# Check whether identity corresponds to an instance agent
|
139
|
+
#
|
140
|
+
# === Parameters
|
141
|
+
# serialized_id(String):: Valid serialized agent identity (use 'valid?' to check first)
|
142
|
+
#
|
143
|
+
# === Return
|
144
|
+
# (Boolean):: true if id corresponds to an instance agent, otherwise false
|
145
|
+
def self.instance_agent?(serialized_id)
|
146
|
+
parts(serialized_id)[1] == 'instance'
|
147
|
+
end
|
148
|
+
|
149
|
+
# String representation of identity
|
150
|
+
#
|
151
|
+
# === Return
|
152
|
+
# (String):: Serialized identity
|
153
|
+
def to_s
|
154
|
+
"#{@prefix}#{@separator}#{@agent_type}#{@separator}#{@token}#{@separator}#{@base_id}"
|
155
|
+
end
|
156
|
+
|
157
|
+
# Comparison operator
|
158
|
+
#
|
159
|
+
# === Parameters
|
160
|
+
# other(AgentIdentity):: Other agent identity
|
161
|
+
#
|
162
|
+
# === Return
|
163
|
+
# (Boolean):: true if other is identical to self, otherwise false
|
164
|
+
def ==(other)
|
165
|
+
other.kind_of?(::RightScale::AgentIdentity) &&
|
166
|
+
prefix == other.prefix &&
|
167
|
+
agent_type == other.agent_type &&
|
168
|
+
token == other.token &&
|
169
|
+
base_id == other.base_id
|
170
|
+
end
|
171
|
+
|
172
|
+
protected
|
173
|
+
|
174
|
+
# Split given serialized id into its parts
|
175
|
+
#
|
176
|
+
# === Parameters
|
177
|
+
# serialized_id(String):: Valid serialized agent identity (use 'valid?' to check first)
|
178
|
+
#
|
179
|
+
# === Return
|
180
|
+
# (Array):: Array of parts: prefix, agent type, token, base id and separator
|
181
|
+
def self.parts(serialized_id)
|
182
|
+
prefix = agent_type = token = bid = separator = nil
|
183
|
+
if serialized_id.include?(ID_SEPARATOR)
|
184
|
+
prefix, agent_type, token, bid = serialized_id.split(ID_SEPARATOR)
|
185
|
+
separator = ID_SEPARATOR
|
186
|
+
elsif serialized_id.include?(ID_SEPARATOR_OLD)
|
187
|
+
prefix, agent_type, token, bid = serialized_id.split(ID_SEPARATOR_OLD)
|
188
|
+
separator = ID_SEPARATOR_OLD
|
189
|
+
end
|
190
|
+
[ prefix, agent_type, token, bid, separator ]
|
191
|
+
end
|
192
|
+
|
193
|
+
# Check that given serialized identity has valid parts
|
194
|
+
#
|
195
|
+
# === Parameters
|
196
|
+
# serialized_id(String):: Serialized identity to be tested
|
197
|
+
#
|
198
|
+
# === Return
|
199
|
+
# (Boolean):: true if serialized identity is a valid identity token, otherwise false
|
200
|
+
def self.valid_parts?(serialized_id)
|
201
|
+
p = parts(serialized_id)
|
202
|
+
res = p.size == 5 &&
|
203
|
+
p[1] && p[1].size > 0 &&
|
204
|
+
p[2] && p[2].size > 0 &&
|
205
|
+
p[3] && p[3].to_i.to_s == p[3]
|
206
|
+
end
|
207
|
+
|
208
|
+
end # AgentIdentity
|
209
|
+
|
210
|
+
end # RightScale
|
@@ -0,0 +1,237 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2013 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
module RightScale
|
24
|
+
|
25
|
+
# Agent tags management
|
26
|
+
class AgentTagManager
|
27
|
+
|
28
|
+
include RightSupport::Ruby::EasySingleton
|
29
|
+
|
30
|
+
# (Agent) Agent being managed
|
31
|
+
attr_accessor :agent
|
32
|
+
|
33
|
+
# Retrieve current agent tags and give result to block
|
34
|
+
#
|
35
|
+
# === Parameters
|
36
|
+
# options(Hash):: Request options
|
37
|
+
# :raw(Boolean):: true to yield raw tag response instead of deserialized tags
|
38
|
+
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
39
|
+
#
|
40
|
+
# === Block
|
41
|
+
# Given block should take one argument which will be set with an array
|
42
|
+
# initialized with the tags of this instance
|
43
|
+
#
|
44
|
+
# === Return
|
45
|
+
# true:: Always return true
|
46
|
+
def tags(options = {})
|
47
|
+
# TODO remove use of agent identity when fully drop AMQP
|
48
|
+
do_query(nil, @agent.self_href || @agent.identity, options) do |result|
|
49
|
+
if result.kind_of?(Hash)
|
50
|
+
yield(result.size == 1 ? result.values.first['tags'] : [])
|
51
|
+
else
|
52
|
+
yield result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Queries a list of servers in the current deployment which have one or more
|
58
|
+
# of the given tags.
|
59
|
+
#
|
60
|
+
# === Parameters
|
61
|
+
# tags(String, Array):: Tag or tags to query or empty
|
62
|
+
# options(Hash):: Request options
|
63
|
+
# :raw(Boolean):: true to yield raw tag response instead of deserialized tags
|
64
|
+
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
65
|
+
#
|
66
|
+
# === Block
|
67
|
+
# Given block should take one argument which will be set with an array
|
68
|
+
# initialized with the tags of this instance
|
69
|
+
#
|
70
|
+
# === Return
|
71
|
+
# true:: Always return true
|
72
|
+
def query_tags(tags, options = {})
|
73
|
+
tags = ensure_flat_array_value(tags) unless tags.nil? || tags.empty?
|
74
|
+
do_query(tags, nil, options) { |result| yield result }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Queries a list of servers in the current deployment which have one or more
|
78
|
+
# of the given tags. Yields the raw response (for responding locally).
|
79
|
+
#
|
80
|
+
# === Parameters
|
81
|
+
# tags(String, Array):: Tag or tags to query or empty
|
82
|
+
# hrefs(Array):: hrefs of resources to query with empty or nil meaning all instances in deployment
|
83
|
+
# options(Hash):: Request options
|
84
|
+
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
85
|
+
#
|
86
|
+
# === Block
|
87
|
+
# Given block should take one argument which will be set with the raw response
|
88
|
+
#
|
89
|
+
# === Return
|
90
|
+
# true:: Always return true
|
91
|
+
def query_tags_raw(tags, hrefs = nil, options = {})
|
92
|
+
tags = ensure_flat_array_value(tags) unless tags.nil? || tags.empty?
|
93
|
+
options = options.merge(:raw => true)
|
94
|
+
do_query(tags, hrefs, options) { |raw_response| yield raw_response }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Add given tags to agent
|
98
|
+
#
|
99
|
+
# === Parameters
|
100
|
+
# new_tags(String, Array):: Tag or tags to be added
|
101
|
+
#
|
102
|
+
# === Block
|
103
|
+
# A block is optional. If provided, should take one argument which will be set with the
|
104
|
+
# raw response
|
105
|
+
#
|
106
|
+
# === Return
|
107
|
+
# true always return true
|
108
|
+
def add_tags(new_tags)
|
109
|
+
new_tags = ensure_flat_array_value(new_tags) unless new_tags.nil? || new_tags.empty?
|
110
|
+
do_update(new_tags, []) { |raw_response| yield raw_response if block_given? }
|
111
|
+
end
|
112
|
+
|
113
|
+
# Remove given tags from agent
|
114
|
+
#
|
115
|
+
# === Parameters
|
116
|
+
# old_tags(String, Array):: Tag or tags to be removed
|
117
|
+
#
|
118
|
+
# === Block
|
119
|
+
# A block is optional. If provided, should take one argument which will be set with the
|
120
|
+
# raw response
|
121
|
+
#
|
122
|
+
# === Return
|
123
|
+
# true always return true
|
124
|
+
def remove_tags(old_tags)
|
125
|
+
old_tags = ensure_flat_array_value(old_tags) unless old_tags.nil? || old_tags.empty?
|
126
|
+
do_update([], old_tags) { |raw_response| yield raw_response if block_given? }
|
127
|
+
end
|
128
|
+
|
129
|
+
# Clear all agent tags
|
130
|
+
#
|
131
|
+
# === Block
|
132
|
+
# Given block should take one argument which will be set with the raw response
|
133
|
+
#
|
134
|
+
# === Return
|
135
|
+
# true::Always return true
|
136
|
+
def clear
|
137
|
+
do_update([], @agent.tags) { |raw_response| yield raw_response }
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def agent_check
|
143
|
+
raise ArgumentError.new("Must set agent= before using tag manager") unless @agent
|
144
|
+
end
|
145
|
+
|
146
|
+
# Runs a tag query with an optional list of tags.
|
147
|
+
#
|
148
|
+
# === Parameters
|
149
|
+
# tags(Array):: Tags to query or empty or nil
|
150
|
+
# hrefs(Array):: hrefs of resources to query with empty or nil meaning all instances in deployment
|
151
|
+
# options(Hash):: Request options
|
152
|
+
# :raw(Boolean):: true to yield raw tag response instead of unserialized tags
|
153
|
+
# :timeout(Integer):: timeout in seconds before giving up and yielding an error message
|
154
|
+
#
|
155
|
+
# === Block
|
156
|
+
# Given block should take one argument which will be set with an array
|
157
|
+
# initialized with the tags of this instance
|
158
|
+
#
|
159
|
+
# === Return
|
160
|
+
# true:: Always return true
|
161
|
+
def do_query(tags = nil, hrefs = nil, options = {})
|
162
|
+
raw = options[:raw]
|
163
|
+
timeout = options[:timeout]
|
164
|
+
|
165
|
+
request_options = {}
|
166
|
+
request_options[:timeout] = timeout if timeout
|
167
|
+
|
168
|
+
agent_check
|
169
|
+
payload = {:agent_identity => @agent.identity}
|
170
|
+
payload[:tags] = ensure_flat_array_value(tags) unless tags.nil? || tags.empty?
|
171
|
+
payload[:hrefs] = ensure_flat_array_value(hrefs) unless hrefs.nil? || hrefs.empty?
|
172
|
+
request = RightScale::RetryableRequest.new("/router/query_tags", payload, request_options)
|
173
|
+
request.callback { |result| yield raw ? request.raw_response : result }
|
174
|
+
request.errback do |message|
|
175
|
+
Log.error("Failed to query tags (#{message})")
|
176
|
+
yield((raw ? request.raw_response : nil) || message)
|
177
|
+
end
|
178
|
+
request.run
|
179
|
+
true
|
180
|
+
end
|
181
|
+
|
182
|
+
# Runs a tag update with a list of new or old tags
|
183
|
+
#
|
184
|
+
# === Parameters
|
185
|
+
# new_tags(Array):: new tags to add or empty
|
186
|
+
# old_tags(Array):: old tags to remove or empty
|
187
|
+
# block(Block):: optional callback for update response
|
188
|
+
#
|
189
|
+
# === Block
|
190
|
+
# A block is optional. If provided, should take one argument which will be set with the
|
191
|
+
# raw response
|
192
|
+
#
|
193
|
+
# === Return
|
194
|
+
# true:: Always return true
|
195
|
+
def do_update(new_tags, old_tags, &block)
|
196
|
+
agent_check
|
197
|
+
raise ArgumentError.new("Cannot add and remove tags in same update") if new_tags.any? && old_tags.any?
|
198
|
+
tags = @agent.tags
|
199
|
+
tags += new_tags
|
200
|
+
tags -= old_tags
|
201
|
+
tags.uniq!
|
202
|
+
|
203
|
+
if new_tags.any?
|
204
|
+
request = RightScale::RetryableRequest.new("/router/add_tags", {:tags => new_tags})
|
205
|
+
elsif old_tags.any?
|
206
|
+
request = RightScale::RetryableRequest.new("/router/delete_tags", {:tags => old_tags})
|
207
|
+
else
|
208
|
+
return
|
209
|
+
end
|
210
|
+
|
211
|
+
if block
|
212
|
+
# Always yield raw response
|
213
|
+
request.callback do |_|
|
214
|
+
# Refresh agent's copy of tags on successful update
|
215
|
+
@agent.tags = tags
|
216
|
+
block.call(request.raw_response)
|
217
|
+
end
|
218
|
+
request.errback { |message| block.call(request.raw_response || message) }
|
219
|
+
end
|
220
|
+
request.run
|
221
|
+
true
|
222
|
+
end
|
223
|
+
|
224
|
+
# Ensures value is a flat array, making an array from the single value if necessary
|
225
|
+
#
|
226
|
+
# === Parameters
|
227
|
+
# value(Object):: any kind of value
|
228
|
+
#
|
229
|
+
# === Return
|
230
|
+
# result(Array):: flat array value
|
231
|
+
def ensure_flat_array_value(value)
|
232
|
+
value = Array(value).flatten.compact
|
233
|
+
end
|
234
|
+
|
235
|
+
end # AgentTagManager
|
236
|
+
|
237
|
+
end # RightScale
|
@@ -0,0 +1,107 @@
|
|
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
|
+
# Standard formatter for audit entries
|
26
|
+
# Each method return a hash of two elements:
|
27
|
+
# - :summary contains the updated summary of the audit entry
|
28
|
+
# - :detail contains the details to be appended to the audit entry
|
29
|
+
class AuditFormatter
|
30
|
+
|
31
|
+
# Start new audit section
|
32
|
+
#
|
33
|
+
# === Parameters
|
34
|
+
# title(String):: New section title
|
35
|
+
#
|
36
|
+
# === Return
|
37
|
+
# entry(Hash):: Hash containing new audit entry summary and detail
|
38
|
+
def self.new_section(title)
|
39
|
+
title = '' unless title
|
40
|
+
entry = { :summary => title, :detail => "#{ '****' * 20 }\n*RS>#{ title.center(72) }****\n" }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Update audit summary
|
44
|
+
#
|
45
|
+
# === Parameters
|
46
|
+
# status(String):: Updated audit status
|
47
|
+
#
|
48
|
+
# === Return
|
49
|
+
# entry(Hash):: Hash containing new audit entry summary and detail
|
50
|
+
def self.status(status)
|
51
|
+
entry = { :summary => status, :detail => wrap_text(status) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Append output to current audit section
|
55
|
+
#
|
56
|
+
# === Parameters
|
57
|
+
# text(String):: Output to be appended
|
58
|
+
#
|
59
|
+
# === Return
|
60
|
+
# entry(Hash):: Hash containing new audit entry detail
|
61
|
+
def self.output(text)
|
62
|
+
text += "\n" unless text[-1, 1] == "\n"
|
63
|
+
entry = { :detail => text }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Append info text to current audit section
|
67
|
+
#
|
68
|
+
# === Parameters
|
69
|
+
# info(String):: Information to be appended
|
70
|
+
#
|
71
|
+
# === Return
|
72
|
+
# entry(Hash):: Hash containing new audit entry detail
|
73
|
+
def self.info(text)
|
74
|
+
entry = { :detail => wrap_text(text) }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Append error text to current audit section
|
78
|
+
#
|
79
|
+
# === Parameters
|
80
|
+
# text(String):: Error message to be appended
|
81
|
+
#
|
82
|
+
# === Return
|
83
|
+
# entry(Hash):: Hash containing new audit entry detail
|
84
|
+
def self.error(text)
|
85
|
+
entry = { :detail => "*ERROR> #{text}\n" }
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
|
90
|
+
# Wrap text to given number of columns
|
91
|
+
# Tries to be smart and only wrap when there is a space
|
92
|
+
#
|
93
|
+
# === Parameters
|
94
|
+
# txt(String):: Text to be wrapped
|
95
|
+
# prefix(String>:: Prefix for each wrapped line, default to '*RS) '
|
96
|
+
# col(Integer):: Maximum number of columns for each line, default to 80
|
97
|
+
#
|
98
|
+
# === Return
|
99
|
+
# wrapped_text(String):: Wrapped text
|
100
|
+
def self.wrap_text(txt, prefix = '*RS> ', col = 80)
|
101
|
+
txt = '' unless txt
|
102
|
+
wrapped_text = txt.gsub(/(.{1,#{col - prefix.size}})( +|$\n?)|(.{1,#{col - prefix.size}})/, "#{prefix}\\1\\3\n").rstrip + "\n"
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|