right_agent 2.0.7-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +82 -0
  3. data/Rakefile +113 -0
  4. data/lib/right_agent.rb +59 -0
  5. data/lib/right_agent/actor.rb +182 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +232 -0
  8. data/lib/right_agent/agent.rb +1149 -0
  9. data/lib/right_agent/agent_config.rb +480 -0
  10. data/lib/right_agent/agent_identity.rb +210 -0
  11. data/lib/right_agent/agent_tag_manager.rb +237 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/clients.rb +31 -0
  14. data/lib/right_agent/clients/api_client.rb +383 -0
  15. data/lib/right_agent/clients/auth_client.rb +247 -0
  16. data/lib/right_agent/clients/balanced_http_client.rb +369 -0
  17. data/lib/right_agent/clients/base_retry_client.rb +495 -0
  18. data/lib/right_agent/clients/right_http_client.rb +279 -0
  19. data/lib/right_agent/clients/router_client.rb +493 -0
  20. data/lib/right_agent/command.rb +30 -0
  21. data/lib/right_agent/command/agent_manager_commands.rb +150 -0
  22. data/lib/right_agent/command/command_client.rb +136 -0
  23. data/lib/right_agent/command/command_constants.rb +33 -0
  24. data/lib/right_agent/command/command_io.rb +126 -0
  25. data/lib/right_agent/command/command_parser.rb +87 -0
  26. data/lib/right_agent/command/command_runner.rb +118 -0
  27. data/lib/right_agent/command/command_serializer.rb +63 -0
  28. data/lib/right_agent/connectivity_checker.rb +179 -0
  29. data/lib/right_agent/console.rb +65 -0
  30. data/lib/right_agent/core_payload_types.rb +44 -0
  31. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  32. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  33. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  34. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  35. data/lib/right_agent/core_payload_types/dev_repositories.rb +100 -0
  36. data/lib/right_agent/core_payload_types/dev_repository.rb +76 -0
  37. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  38. data/lib/right_agent/core_payload_types/executable_bundle.rb +130 -0
  39. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  40. data/lib/right_agent/core_payload_types/login_user.rb +79 -0
  41. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  42. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +73 -0
  43. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  44. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  45. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +94 -0
  46. data/lib/right_agent/core_payload_types/runlist_policy.rb +44 -0
  47. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  48. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  49. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  50. data/lib/right_agent/daemonize.rb +35 -0
  51. data/lib/right_agent/dispatched_cache.rb +109 -0
  52. data/lib/right_agent/dispatcher.rb +272 -0
  53. data/lib/right_agent/enrollment_result.rb +221 -0
  54. data/lib/right_agent/exceptions.rb +87 -0
  55. data/lib/right_agent/history.rb +145 -0
  56. data/lib/right_agent/log.rb +460 -0
  57. data/lib/right_agent/minimal.rb +46 -0
  58. data/lib/right_agent/monkey_patches.rb +30 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch.rb +55 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  64. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  65. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  66. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +60 -0
  67. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  68. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  69. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  70. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  71. data/lib/right_agent/multiplexer.rb +102 -0
  72. data/lib/right_agent/offline_handler.rb +270 -0
  73. data/lib/right_agent/operation_result.rb +300 -0
  74. data/lib/right_agent/packets.rb +673 -0
  75. data/lib/right_agent/payload_formatter.rb +104 -0
  76. data/lib/right_agent/pending_requests.rb +128 -0
  77. data/lib/right_agent/pid_file.rb +159 -0
  78. data/lib/right_agent/platform.rb +770 -0
  79. data/lib/right_agent/platform/unix/darwin/platform.rb +102 -0
  80. data/lib/right_agent/platform/unix/linux/platform.rb +305 -0
  81. data/lib/right_agent/platform/unix/platform.rb +226 -0
  82. data/lib/right_agent/platform/windows/mingw/platform.rb +447 -0
  83. data/lib/right_agent/platform/windows/mswin/platform.rb +236 -0
  84. data/lib/right_agent/platform/windows/platform.rb +1808 -0
  85. data/lib/right_agent/protocol_version_mixin.rb +69 -0
  86. data/lib/right_agent/retryable_request.rb +195 -0
  87. data/lib/right_agent/scripts/agent_controller.rb +543 -0
  88. data/lib/right_agent/scripts/agent_deployer.rb +400 -0
  89. data/lib/right_agent/scripts/common_parser.rb +160 -0
  90. data/lib/right_agent/scripts/log_level_manager.rb +192 -0
  91. data/lib/right_agent/scripts/stats_manager.rb +268 -0
  92. data/lib/right_agent/scripts/usage.rb +58 -0
  93. data/lib/right_agent/secure_identity.rb +92 -0
  94. data/lib/right_agent/security.rb +32 -0
  95. data/lib/right_agent/security/cached_certificate_store_proxy.rb +77 -0
  96. data/lib/right_agent/security/certificate.rb +102 -0
  97. data/lib/right_agent/security/certificate_cache.rb +89 -0
  98. data/lib/right_agent/security/distinguished_name.rb +56 -0
  99. data/lib/right_agent/security/encrypted_document.rb +83 -0
  100. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  101. data/lib/right_agent/security/signature.rb +86 -0
  102. data/lib/right_agent/security/static_certificate_store.rb +85 -0
  103. data/lib/right_agent/sender.rb +792 -0
  104. data/lib/right_agent/serialize.rb +29 -0
  105. data/lib/right_agent/serialize/message_pack.rb +107 -0
  106. data/lib/right_agent/serialize/secure_serializer.rb +151 -0
  107. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  108. data/lib/right_agent/serialize/serializable.rb +151 -0
  109. data/lib/right_agent/serialize/serializer.rb +159 -0
  110. data/lib/right_agent/subprocess.rb +38 -0
  111. data/lib/right_agent/tracer.rb +124 -0
  112. data/right_agent.gemspec +101 -0
  113. data/spec/actor_registry_spec.rb +80 -0
  114. data/spec/actor_spec.rb +162 -0
  115. data/spec/agent_config_spec.rb +235 -0
  116. data/spec/agent_identity_spec.rb +78 -0
  117. data/spec/agent_spec.rb +734 -0
  118. data/spec/agent_tag_manager_spec.rb +319 -0
  119. data/spec/clients/api_client_spec.rb +423 -0
  120. data/spec/clients/auth_client_spec.rb +272 -0
  121. data/spec/clients/balanced_http_client_spec.rb +576 -0
  122. data/spec/clients/base_retry_client_spec.rb +635 -0
  123. data/spec/clients/router_client_spec.rb +594 -0
  124. data/spec/clients/spec_helper.rb +111 -0
  125. data/spec/command/agent_manager_commands_spec.rb +51 -0
  126. data/spec/command/command_io_spec.rb +93 -0
  127. data/spec/command/command_parser_spec.rb +79 -0
  128. data/spec/command/command_runner_spec.rb +107 -0
  129. data/spec/command/command_serializer_spec.rb +51 -0
  130. data/spec/connectivity_checker_spec.rb +83 -0
  131. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  132. data/spec/core_payload_types/dev_repository_spec.rb +33 -0
  133. data/spec/core_payload_types/executable_bundle_spec.rb +67 -0
  134. data/spec/core_payload_types/login_user_spec.rb +102 -0
  135. data/spec/core_payload_types/recipe_instantiation_spec.rb +81 -0
  136. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  137. data/spec/core_payload_types/right_script_instantiation_spec.rb +79 -0
  138. data/spec/core_payload_types/spec_helper.rb +23 -0
  139. data/spec/dispatched_cache_spec.rb +136 -0
  140. data/spec/dispatcher_spec.rb +324 -0
  141. data/spec/enrollment_result_spec.rb +53 -0
  142. data/spec/history_spec.rb +246 -0
  143. data/spec/log_spec.rb +192 -0
  144. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  145. data/spec/multiplexer_spec.rb +48 -0
  146. data/spec/offline_handler_spec.rb +340 -0
  147. data/spec/operation_result_spec.rb +208 -0
  148. data/spec/packets_spec.rb +461 -0
  149. data/spec/pending_requests_spec.rb +136 -0
  150. data/spec/platform/spec_helper.rb +216 -0
  151. data/spec/platform/unix/darwin/platform_spec.rb +181 -0
  152. data/spec/platform/unix/linux/platform_spec.rb +540 -0
  153. data/spec/platform/unix/spec_helper.rb +149 -0
  154. data/spec/platform/windows/mingw/platform_spec.rb +222 -0
  155. data/spec/platform/windows/mswin/platform_spec.rb +259 -0
  156. data/spec/platform/windows/spec_helper.rb +720 -0
  157. data/spec/retryable_request_spec.rb +306 -0
  158. data/spec/secure_identity_spec.rb +50 -0
  159. data/spec/security/cached_certificate_store_proxy_spec.rb +62 -0
  160. data/spec/security/certificate_cache_spec.rb +71 -0
  161. data/spec/security/certificate_spec.rb +49 -0
  162. data/spec/security/distinguished_name_spec.rb +46 -0
  163. data/spec/security/encrypted_document_spec.rb +55 -0
  164. data/spec/security/rsa_key_pair_spec.rb +55 -0
  165. data/spec/security/signature_spec.rb +66 -0
  166. data/spec/security/static_certificate_store_spec.rb +58 -0
  167. data/spec/sender_spec.rb +1045 -0
  168. data/spec/serialize/message_pack_spec.rb +131 -0
  169. data/spec/serialize/secure_serializer_spec.rb +132 -0
  170. data/spec/serialize/serializable_spec.rb +90 -0
  171. data/spec/serialize/serializer_spec.rb +197 -0
  172. data/spec/spec.opts +2 -0
  173. data/spec/spec.win32.opts +1 -0
  174. data/spec/spec_helper.rb +130 -0
  175. data/spec/tracer_spec.rb +114 -0
  176. metadata +447 -0
@@ -0,0 +1,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