right_agent 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +78 -0
  3. data/Rakefile +86 -0
  4. data/lib/right_agent.rb +66 -0
  5. data/lib/right_agent/actor.rb +163 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +189 -0
  8. data/lib/right_agent/agent.rb +735 -0
  9. data/lib/right_agent/agent_config.rb +403 -0
  10. data/lib/right_agent/agent_identity.rb +209 -0
  11. data/lib/right_agent/agent_tags_manager.rb +213 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/broker_client.rb +683 -0
  14. data/lib/right_agent/command.rb +30 -0
  15. data/lib/right_agent/command/agent_manager_commands.rb +134 -0
  16. data/lib/right_agent/command/command_client.rb +136 -0
  17. data/lib/right_agent/command/command_constants.rb +42 -0
  18. data/lib/right_agent/command/command_io.rb +128 -0
  19. data/lib/right_agent/command/command_parser.rb +87 -0
  20. data/lib/right_agent/command/command_runner.rb +105 -0
  21. data/lib/right_agent/command/command_serializer.rb +63 -0
  22. data/lib/right_agent/console.rb +65 -0
  23. data/lib/right_agent/core_payload_types.rb +42 -0
  24. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  25. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  26. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  27. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  28. data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
  29. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  30. data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
  31. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  32. data/lib/right_agent/core_payload_types/login_user.rb +62 -0
  33. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  34. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
  35. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  36. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  37. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
  38. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  39. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  40. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  41. data/lib/right_agent/daemonize.rb +35 -0
  42. data/lib/right_agent/dispatcher.rb +348 -0
  43. data/lib/right_agent/enrollment_result.rb +217 -0
  44. data/lib/right_agent/exceptions.rb +30 -0
  45. data/lib/right_agent/ha_broker_client.rb +1278 -0
  46. data/lib/right_agent/idempotent_request.rb +140 -0
  47. data/lib/right_agent/log.rb +418 -0
  48. data/lib/right_agent/monkey_patches.rb +29 -0
  49. data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
  50. data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
  51. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  52. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  53. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  54. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  55. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  56. data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
  57. data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
  58. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  64. data/lib/right_agent/multiplexer.rb +91 -0
  65. data/lib/right_agent/operation_result.rb +270 -0
  66. data/lib/right_agent/packets.rb +637 -0
  67. data/lib/right_agent/payload_formatter.rb +104 -0
  68. data/lib/right_agent/pid_file.rb +159 -0
  69. data/lib/right_agent/platform.rb +319 -0
  70. data/lib/right_agent/platform/darwin.rb +227 -0
  71. data/lib/right_agent/platform/linux.rb +268 -0
  72. data/lib/right_agent/platform/windows.rb +1204 -0
  73. data/lib/right_agent/scripts/agent_controller.rb +522 -0
  74. data/lib/right_agent/scripts/agent_deployer.rb +379 -0
  75. data/lib/right_agent/scripts/common_parser.rb +153 -0
  76. data/lib/right_agent/scripts/log_level_manager.rb +193 -0
  77. data/lib/right_agent/scripts/stats_manager.rb +256 -0
  78. data/lib/right_agent/scripts/usage.rb +58 -0
  79. data/lib/right_agent/secure_identity.rb +92 -0
  80. data/lib/right_agent/security.rb +32 -0
  81. data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
  82. data/lib/right_agent/security/certificate.rb +102 -0
  83. data/lib/right_agent/security/certificate_cache.rb +89 -0
  84. data/lib/right_agent/security/distinguished_name.rb +56 -0
  85. data/lib/right_agent/security/encrypted_document.rb +84 -0
  86. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  87. data/lib/right_agent/security/signature.rb +86 -0
  88. data/lib/right_agent/security/static_certificate_store.rb +69 -0
  89. data/lib/right_agent/sender.rb +937 -0
  90. data/lib/right_agent/serialize.rb +29 -0
  91. data/lib/right_agent/serialize/message_pack.rb +102 -0
  92. data/lib/right_agent/serialize/secure_serializer.rb +131 -0
  93. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  94. data/lib/right_agent/serialize/serializable.rb +135 -0
  95. data/lib/right_agent/serialize/serializer.rb +149 -0
  96. data/lib/right_agent/stats_helper.rb +731 -0
  97. data/lib/right_agent/subprocess.rb +38 -0
  98. data/lib/right_agent/tracer.rb +124 -0
  99. data/right_agent.gemspec +60 -0
  100. data/spec/actor_registry_spec.rb +81 -0
  101. data/spec/actor_spec.rb +99 -0
  102. data/spec/agent_config_spec.rb +226 -0
  103. data/spec/agent_identity_spec.rb +75 -0
  104. data/spec/agent_spec.rb +571 -0
  105. data/spec/broker_client_spec.rb +961 -0
  106. data/spec/command/agent_manager_commands_spec.rb +51 -0
  107. data/spec/command/command_io_spec.rb +93 -0
  108. data/spec/command/command_parser_spec.rb +79 -0
  109. data/spec/command/command_runner_spec.rb +72 -0
  110. data/spec/command/command_serializer_spec.rb +51 -0
  111. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  112. data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
  113. data/spec/core_payload_types/login_user_spec.rb +98 -0
  114. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  115. data/spec/core_payload_types/spec_helper.rb +23 -0
  116. data/spec/dispatcher_spec.rb +372 -0
  117. data/spec/enrollment_result_spec.rb +53 -0
  118. data/spec/ha_broker_client_spec.rb +1673 -0
  119. data/spec/idempotent_request_spec.rb +136 -0
  120. data/spec/log_spec.rb +177 -0
  121. data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
  122. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  123. data/spec/monkey_patches/string_patch_spec.rb +99 -0
  124. data/spec/multiplexer_spec.rb +48 -0
  125. data/spec/operation_result_spec.rb +171 -0
  126. data/spec/packets_spec.rb +418 -0
  127. data/spec/platform/platform_spec.rb +60 -0
  128. data/spec/results_mock.rb +45 -0
  129. data/spec/secure_identity_spec.rb +50 -0
  130. data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
  131. data/spec/security/certificate_cache_spec.rb +71 -0
  132. data/spec/security/certificate_spec.rb +49 -0
  133. data/spec/security/distinguished_name_spec.rb +46 -0
  134. data/spec/security/encrypted_document_spec.rb +55 -0
  135. data/spec/security/rsa_key_pair_spec.rb +55 -0
  136. data/spec/security/signature_spec.rb +66 -0
  137. data/spec/security/static_certificate_store_spec.rb +52 -0
  138. data/spec/sender_spec.rb +887 -0
  139. data/spec/serialize/message_pack_spec.rb +131 -0
  140. data/spec/serialize/secure_serializer_spec.rb +102 -0
  141. data/spec/serialize/serializable_spec.rb +90 -0
  142. data/spec/serialize/serializer_spec.rb +174 -0
  143. data/spec/spec.opts +2 -0
  144. data/spec/spec_helper.rb +77 -0
  145. data/spec/stats_helper_spec.rb +681 -0
  146. data/spec/tracer_spec.rb +114 -0
  147. metadata +320 -0
@@ -0,0 +1,403 @@
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
+ # Helper methods for accessing RightAgent files, directories, and processes.
26
+ # Values returned are driven by root_dir, cfg_dir, and pid_dir, which may be set
27
+ # but have defaults, and secondarily by the contents of the associated agent
28
+ # configuration file generated by the 'rad' tool.
29
+ #
30
+ # The root_dir may be specified to be a list of root directories to be searched
31
+ # when looking for agent files. It defaults to the current working directory.
32
+ # A root directory is assumed to contain some or all of the following directories:
33
+ # init - initialization code
34
+ # actors - actor code
35
+ # certs - security certificates and keys
36
+ # lib - additional agent code
37
+ # scripts - tools code
38
+ #
39
+ # The init directory contains the following initialization code:
40
+ # config.yml - static configuration settings for the agent
41
+ # init.rb - code that registers the agent's actors and performs any other
42
+ # agent specific initialization such as initializing its
43
+ # secure serializer and its command protocol server
44
+ #
45
+ # The certs directory contains the x.509 public certificate and keys needed
46
+ # to sign and encrypt all outgoing messages as well as to check the signature
47
+ # and decrypt any incoming messages. This directory should contain at least:
48
+ # <agent name>.key - agent's' private key
49
+ # <agent name>.cert - agent's' public certificate
50
+ # mapper.cert - mapper's' public certificate
51
+ #
52
+ # The scripts directory at a minimum contains the following:
53
+ # install.sh - script for installing standard and agent specific tools in /usr/bin
54
+ #
55
+ # The cfg_dir is the path to the directory containing a directory for each agent
56
+ # configured on the local machine (e.g., core, core_2, core_3). Each agent directory
57
+ # in turn contains a config.yml file generated to contain that agent's current
58
+ # configuration. The cfg_dir defaults to the platform specific cfg_dir.
59
+ #
60
+ # The pid_dir is the path to the directory where agent process id files are stored.
61
+ # These files are typically named <agent identity>.pid. The pid_dir defaults to the
62
+ # current to the platform specific pid_dir.
63
+ module AgentConfig
64
+
65
+ # Current agent protocol version
66
+ PROTOCOL_VERSION = 17
67
+
68
+ # Current agent protocol version
69
+ #
70
+ # === Return
71
+ # (Integer):: Protocol version
72
+ def self.protocol_version
73
+ PROTOCOL_VERSION
74
+ end
75
+
76
+ # Initialize path to root directory of agent
77
+ #
78
+ # === Parameters
79
+ # dir(String|Array):: Directory path or ordered list of directory paths to be searched
80
+ #
81
+ # === Return
82
+ # (String):: Ordered list of directory paths to be searched
83
+ def self.root_dir=(dir)
84
+ @root_dirs = array(dir)
85
+ end
86
+
87
+ # Initialize path to directory containing generated agent configuration files
88
+ #
89
+ # === Parameters
90
+ # dir(String):: Directory path
91
+ #
92
+ # === Return
93
+ # (String):: Directory path
94
+ def self.cfg_dir=(dir)
95
+ @cfg_dir = dir
96
+ end
97
+
98
+ # Initialize path to directory containing agent process id files
99
+ #
100
+ # === Parameters
101
+ # dir(String):: Directory path
102
+ #
103
+ # === Return
104
+ # (String):: Directory path
105
+ def self.pid_dir=(dir)
106
+ @pid_dir = dir
107
+ end
108
+
109
+ # Root directory path(s)
110
+ #
111
+ # === Return
112
+ # (String|Array):: Individual directory path if only one, otherwise array of paths
113
+ def self.root_dir
114
+ (d = root_dirs).size > 1 ? d : d.first
115
+ end
116
+
117
+ # Path to agent init.rb file containing code that registers the agent's actors
118
+ # and performs any other agent specific initialization such as initializing its
119
+ # secure serializer and its command protocol server
120
+ #
121
+ # === Return
122
+ # (String|nil):: File path name, or nil if file does not exist
123
+ def self.init_file
124
+ first_file(:init_dir, "init.rb")
125
+ end
126
+
127
+ # Path to agent config.yml file containing static configuration settings
128
+ #
129
+ # === Return
130
+ # (String|nil):: File path name, or nil if file does not exist
131
+ def self.init_cfg_file
132
+ first_file(:init_dir, "config.yml")
133
+ end
134
+
135
+ # Ordered list of directory path names for searching for actors:
136
+ # - actors directory in each configured root directory
137
+ # - other directories produced by other_actors_dirs method, e.g., in other associated gems
138
+ # - actors directory in RightAgent gem
139
+ #
140
+ # === Return
141
+ # actors_dirs(Array):: List of directory path names
142
+ def self.actors_dirs
143
+ actors_dirs = all_dirs(:actors_dir)
144
+ actors_dirs += other_actors_dirs if self.respond_to?(:other_actors_dirs)
145
+ actors_dirs << File.normalize_path(File.join(File.dirname(__FILE__), 'actors'))
146
+ actors_dirs
147
+ end
148
+
149
+ # Path to directory containing certificates
150
+ #
151
+ # === Parameters
152
+ # root_dir(String|nil):: Specific root dir to use (must be in root_dirs),
153
+ # if nil use first dir in root_dirs
154
+ #
155
+ # === Return
156
+ # (String|nil):: Path to certs directory, or nil if cannot determine root_dir
157
+ def self.certs_dir(root_dir = nil)
158
+ if root_dir
159
+ root_dir = nil unless @root_dirs && @root_dirs.include?(root_dir)
160
+ else
161
+ root_dir = @root_dirs.first if @root_dirs
162
+ end
163
+ File.normalize_path(File.join(root_dir, "certs")) if root_dir
164
+ end
165
+
166
+ # Path to security file containing X.509 data
167
+ #
168
+ # === Parameters
169
+ # name(String):: Security file name
170
+ #
171
+ # === Return
172
+ # file(String|nil):: File path name, or nil if file does not exist
173
+ def self.certs_file(name)
174
+ first_file(:certs_dir, name)
175
+ end
176
+
177
+ # All security files matching pattern
178
+ #
179
+ # === Parameters
180
+ # pattern(String):: Pattern for security files of interest, e.g., '*.cert'
181
+ #
182
+ # === Return
183
+ # files(Array):: Path name of files found
184
+ def self.certs_files(pattern)
185
+ files = []
186
+ names = []
187
+ all_dirs(:certs_dir).each do |d|
188
+ certs = Dir.glob(File.join(d, pattern)).each do |f|
189
+ unless names.include?(b = File.basename(f))
190
+ files << f
191
+ names << b
192
+ end
193
+ end
194
+ end
195
+ files
196
+ end
197
+
198
+ # Path to first agent lib directory
199
+ #
200
+ # === Return
201
+ # dir(String):: Directory path name
202
+ def self.lib_dir
203
+ all_dirs(:lib_dir2).first
204
+ end
205
+
206
+ # Path to first agent scripts directory
207
+ #
208
+ # === Return
209
+ # dir(String):: Directory path name
210
+ def self.scripts_dir
211
+ all_dirs(:scripts_dir2).first
212
+ end
213
+
214
+ # Path to directory containing a directory for each agent configured on the local machine
215
+ #
216
+ # === Return
217
+ # (String):: Directory path name
218
+ def self.cfg_dir
219
+ @cfg_dir ||= Platform.filesystem.cfg_dir
220
+ end
221
+
222
+ # Path to generated agent configuration file
223
+ #
224
+ # === Parameters
225
+ # agent_name(String):: Agent name
226
+ # exists(Boolean):: Whether to return nil if does not exist
227
+ #
228
+ # === Return
229
+ # (String):: Configuration file path name, or nil if file does not exist
230
+ def self.cfg_file(agent_name, exists = false)
231
+ file = File.normalize_path(File.join(cfg_dir, agent_name, "config.yml"))
232
+ file = nil unless !exists || File.exist?(file)
233
+ file
234
+ end
235
+
236
+ # Configuration file path names for all agents configured locally
237
+ #
238
+ # === Return
239
+ # (Array):: Agent configuration file path names
240
+ def self.cfg_files
241
+ Dir.glob(File.join(cfg_dir, "**", "*.yml"))
242
+ end
243
+
244
+ # Configured agents i.e. agents that have a configuration file
245
+ #
246
+ # === Return
247
+ # (Array):: Name of configured agents
248
+ def self.cfg_agents
249
+ cfg_files.map { |c| File.basename(File.dirname(c)) }
250
+ end
251
+
252
+ # Agent name associated with given agent identity
253
+ #
254
+ # === Parameters
255
+ # agent_id(String):: Serialized agent identity
256
+ #
257
+ # === Return
258
+ # (String|nil):: Agent name, or nil if agent not found
259
+ def self.agent_name(agent_id)
260
+ cfg_agents.each do |a|
261
+ if (options = agent_options(a)) && options[:identity] == agent_id
262
+ return a
263
+ end
264
+ end
265
+ nil
266
+ end
267
+
268
+ # Get options from agent's configuration file
269
+ #
270
+ # === Parameters
271
+ # agent_name(String):: Agent name
272
+ #
273
+ # === Return
274
+ # (Hash|nil):: Agent options with key names symbolized,
275
+ # or nil if file not accessible or empty
276
+ def self.load_cfg(agent_name)
277
+ if (file = cfg_file(agent_name, exists = true)) && File.readable?(file) && (cfg = YAML.load(IO.read(file)))
278
+ SerializationHelper.symbolize_keys(cfg)
279
+ end
280
+ end
281
+
282
+ # Write agent's configuration to file
283
+ #
284
+ # === Parameters
285
+ # agent_name(String):: Agent name
286
+ # cfg(Hash):: Configuration options
287
+ #
288
+ # === Return
289
+ # file(String):: Configuration file path name
290
+ def self.store_cfg(agent_name, cfg)
291
+ file = cfg_file(agent_name)
292
+ FileUtils.mkdir_p(File.dirname(file))
293
+ File.delete(file) if File.exists?(file)
294
+ File.open(file, 'w') do |fd|
295
+ fd.puts "# Created at #{Time.now}"
296
+ fd.write(YAML.dump(cfg))
297
+ end
298
+ file
299
+ end
300
+
301
+ # Path to directory containing agent process id files
302
+ #
303
+ # === Return
304
+ # (String):: Directory path name
305
+ def self.pid_dir
306
+ @pid_dir ||= Platform.filesystem.pid_dir
307
+ end
308
+
309
+ # Retrieve agent process id file
310
+ #
311
+ # === Parameters
312
+ # agent_name(String):: Agent name
313
+ #
314
+ # === Return
315
+ # (PidFile|nil):: Process id file, or nil if there is no configuration file for agent
316
+ def self.pid_file(agent_name)
317
+ if options = load_cfg(agent_name)
318
+ PidFile.new(options[:identity], options[:pid_dir])
319
+ end
320
+ end
321
+
322
+ # Agent options from generated agent configuration file
323
+ # and agent process id file if they exist
324
+ # Reset root_dir and pid_dir to one found in agent configuration file
325
+ #
326
+ # === Parameters
327
+ # agent_name(String):: Agent name
328
+ #
329
+ # === Return
330
+ # options(Hash):: Agent options including
331
+ # :identity(String):: Serialized agent identity
332
+ # :log_path(String):: Path to directory for agent log file
333
+ # :pid(Integer):: Agent process pid if available
334
+ # :listen_port(Integer):: Agent command listen port if available
335
+ # :cookie(String):: Agent command cookie if available
336
+ def self.agent_options(agent_name)
337
+ if options = load_cfg(agent_name)
338
+ @root_dirs = array(options[:root_dir])
339
+ @pid_dir = options[:pid_dir]
340
+ options[:log_path] = options[:log_dir] || Platform.filesystem.log_dir
341
+ pid_file = PidFile.new(options[:identity])
342
+ options.merge!(pid_file.read_pid) if pid_file.exists?
343
+ end
344
+ options || {}
345
+ end
346
+
347
+ protected
348
+
349
+ # Convert value to array if not an array, unless nil
350
+ def self.array(value)
351
+ (value.nil? || value.is_a?(Array)) ? value : [value]
352
+ end
353
+
354
+ # Ordered list of root directories
355
+ def self.root_dirs
356
+ @root_dirs || [Dir.pwd]
357
+ end
358
+
359
+ # Path to agent directory containing initialization files
360
+ def self.init_dir(root_dir)
361
+ File.normalize_path(File.join(root_dir, "init"))
362
+ end
363
+
364
+ # Path to directory containing actor source files
365
+ def self.actors_dir(root_dir)
366
+ File.normalize_path(File.join(root_dir, "actors"))
367
+ end
368
+
369
+ # Path to agent directory containing code
370
+ def self.lib_dir2(root_dir)
371
+ File.normalize_path(File.join(root_dir, "lib"))
372
+ end
373
+
374
+ # Path to agent directory containing scripts
375
+ def self.scripts_dir2(root_dir)
376
+ File.normalize_path(File.join(root_dir, "scripts"))
377
+ end
378
+
379
+ # All existing directories of given type
380
+ def self.all_dirs(type)
381
+ dirs = []
382
+ root_dirs.each do |d|
383
+ c = self.__send__(type, d)
384
+ dirs << c if File.directory?(c)
385
+ end
386
+ dirs
387
+ end
388
+
389
+ # Path name of first file found of given type and name, or nil if none found
390
+ def self.first_file(type, name)
391
+ file = nil
392
+ root_dirs.each do |d|
393
+ if File.exist?(f = File.join(self.__send__(type, d), name))
394
+ file = f
395
+ break
396
+ end
397
+ end
398
+ file
399
+ end
400
+
401
+ end # AgentConfig
402
+
403
+ end # RightScale
@@ -0,0 +1,209 @@
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
+ # Cutover time at which agents began using new separator
29
+ SEPARATOR_EPOCH = Time.at(1256702400) unless defined?(SEPARATOR_EPOCH) # Tue Oct 27 21:00:00 -0700 2009
30
+
31
+ # Separator used to differentiate between identity components when serialized
32
+ ID_SEPARATOR = '-' unless defined?(ID_SEPARATOR)
33
+
34
+ # Separator used to differentiate between identity components prior to release 3.4
35
+ ID_SEPARATOR_OLD = '*' unless defined?(ID_SEPARATOR_OLD)
36
+
37
+ # Identity components
38
+ attr_reader :prefix, :agent_type, :token, :base_id
39
+
40
+ # Generate new id
41
+ #
42
+ # === Parameters
43
+ # prefix(String):: Prefix used to scope identity
44
+ # agent_type(String):: Agent type (e.g. 'core', 'instance')
45
+ # base_id(Integer):: Unique integer value
46
+ # token(String):: Unique identity token, will be generated randomly if not provided
47
+ # separator(String):: Character used to separate identity components, defaults to ID_SEPARATOR
48
+ #
49
+ # === Raise
50
+ # RightScale::Exceptions::Argument:: Invalid argument
51
+ def initialize(prefix, agent_type, base_id, token=nil, separator=nil)
52
+ err = "Prefix cannot contain '#{ID_SEPARATOR}'" if prefix && prefix.include?(ID_SEPARATOR)
53
+ err = "Prefix cannot contain '#{ID_SEPARATOR_OLD}'" if prefix && prefix.include?(ID_SEPARATOR_OLD)
54
+ err = "Agent type cannot contain '#{ID_SEPARATOR}'" if agent_type.include?(ID_SEPARATOR)
55
+ err = "Agent type cannot contain '#{ID_SEPARATOR_OLD}'" if agent_type.include?(ID_SEPARATOR_OLD)
56
+ err = "Agent type cannot be nil" if agent_type.nil?
57
+ err = "Agent type cannot be empty" if agent_type.size == 0
58
+ err = "Base ID must be a positive integer" unless base_id.kind_of?(Integer) && base_id >= 0
59
+ err = "Token cannot contain '#{ID_SEPARATOR}'" if token && token.include?(ID_SEPARATOR)
60
+ err = "Token cannot contain '#{ID_SEPARATOR_OLD}'" if token && token.include?(ID_SEPARATOR_OLD)
61
+ raise RightScale::Exceptions::Argument, err if err
62
+
63
+ @separator = separator || ID_SEPARATOR
64
+ @prefix = prefix
65
+ @agent_type = agent_type
66
+ @token = token || self.class.generate
67
+ @base_id = base_id
68
+ end
69
+
70
+ # Generate unique identity
71
+ #
72
+ # === Return
73
+ # id(String):: Random 128-bit hexadecimal string
74
+ def self.generate
75
+ bytes = Platform.rng.pseudorandom_bytes(16)
76
+ #Transform into hex string
77
+ id = bytes.unpack('H*')[0]
78
+ end
79
+
80
+ # Check validity of given serialized identity
81
+ #
82
+ # === Parameters
83
+ # serialized_id(String):: Serialized identity to be tested
84
+ #
85
+ # === Return
86
+ # (Boolean):: true if serialized identity is a valid, otherwise false
87
+ def self.valid?(serialized_id)
88
+ valid_parts?(self.compatible_serialized(serialized_id)) if serialized_id
89
+ end
90
+
91
+ # Instantiate by parsing given token
92
+ #
93
+ # === Parameters
94
+ # serialized_id(String):: Valid serialized agent identity (use 'valid?' to check first)
95
+ #
96
+ # === Return
97
+ # (AgentIdentity):: Corresponding agent identity
98
+ #
99
+ # === Raise
100
+ # (RightScale::Exceptions::Argument):: Serialized agent identity is incorrect
101
+ def self.parse(serialized_id)
102
+ serialized_id = self.compatible_serialized(serialized_id)
103
+ prefix, agent_type, token, bid, separator = parts(serialized_id)
104
+ raise RightScale::Exceptions::Argument, "Invalid agent identity token" unless prefix && agent_type && token && bid
105
+ base_id = bid.to_i
106
+ raise RightScale::Exceptions::Argument, "Invalid agent identity token (Base ID)" unless base_id.to_s == bid
107
+
108
+ AgentIdentity.new(prefix, agent_type, base_id, token, separator)
109
+ end
110
+
111
+ # Convert serialized agent identity to format valid for given protocol version
112
+ # Ignore identity that is not in serialized AgentIdentity format
113
+ #
114
+ # === Parameters
115
+ # serialized_id(String):: Serialized agent identity to be converted
116
+ # version(Integer):: Target protocol version
117
+ #
118
+ # === Return
119
+ # serialized_id(String):: Compatible serialized agent identity
120
+ def self.compatible_serialized(serialized_id, version = 10)
121
+ if version < 10
122
+ serialized_id = "nanite-#{serialized_id}" if self.valid_parts?(serialized_id)
123
+ else
124
+ serialized_id = serialized_id[7..-1] if serialized_id =~ /^nanite-|^mapper-/
125
+ end
126
+ serialized_id
127
+ end
128
+
129
+ # Check whether identity corresponds to an instance agent
130
+ #
131
+ # === Return
132
+ # (Boolean):: true if id corresponds to an instance agent, otherwise false
133
+ def instance_agent?
134
+ agent_type == 'instance'
135
+ end
136
+
137
+ # Check whether identity corresponds to an instance agent
138
+ #
139
+ # === Parameters
140
+ # serialized_id(String):: Valid serialized agent identity (use 'valid?' to check first)
141
+ #
142
+ # === Return
143
+ # (Boolean):: true if id corresponds to an instance agent, otherwise false
144
+ def self.instance_agent?(serialized_id)
145
+ parts(serialized_id)[1] == 'instance'
146
+ end
147
+
148
+ # String representation of identity
149
+ #
150
+ # === Return
151
+ # (String):: Serialized identity
152
+ def to_s
153
+ "#{@prefix}#{@separator}#{@agent_type}#{@separator}#{@token}#{@separator}#{@base_id}"
154
+ end
155
+
156
+ # Comparison operator
157
+ #
158
+ # === Parameters
159
+ # other(AgentIdentity):: Other agent identity
160
+ #
161
+ # === Return
162
+ # (Boolean):: true if other is identical to self, otherwise false
163
+ def ==(other)
164
+ other.kind_of?(::RightScale::AgentIdentity) &&
165
+ prefix == other.prefix &&
166
+ agent_type == other.agent_type &&
167
+ token == other.token &&
168
+ base_id == other.base_id
169
+ end
170
+
171
+ protected
172
+
173
+ # Split given serialized id into its parts
174
+ #
175
+ # === Parameters
176
+ # serialized_id(String):: Valid serialized agent identity (use 'valid?' to check first)
177
+ #
178
+ # === Return
179
+ # (Array):: Array of parts: prefix, agent type, token, base id and separator
180
+ def self.parts(serialized_id)
181
+ prefix = agent_type = token = bid = separator = nil
182
+ if serialized_id.include?(ID_SEPARATOR)
183
+ prefix, agent_type, token, bid = serialized_id.split(ID_SEPARATOR)
184
+ separator = ID_SEPARATOR
185
+ elsif serialized_id.include?(ID_SEPARATOR_OLD)
186
+ prefix, agent_type, token, bid = serialized_id.split(ID_SEPARATOR_OLD)
187
+ separator = ID_SEPARATOR_OLD
188
+ end
189
+ [ prefix, agent_type, token, bid, separator ]
190
+ end
191
+
192
+ # Check that given serialized identity has valid parts
193
+ #
194
+ # === Parameters
195
+ # serialized_id(String):: Serialized identity to be tested
196
+ #
197
+ # === Return
198
+ # (Boolean):: true if serialized identity is a valid identity token, otherwise false
199
+ def self.valid_parts?(serialized_id)
200
+ p = parts(serialized_id)
201
+ res = p.size == 5 &&
202
+ p[1] && p[1].size > 0 &&
203
+ p[2] && p[2].size > 0 &&
204
+ p[3] && p[3].to_i.to_s == p[3]
205
+ end
206
+
207
+ end # AgentIdentity
208
+
209
+ end # RightScale