right_link 5.9.1 → 5.9.2

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/RELEASES.rdoc CHANGED
@@ -1,3 +1,36 @@
1
+ = 5.9.2 (RightLink 5.9 beta 3)
2
+
3
+ Released 2013-09-06.
4
+
5
+ == New Features
6
+
7
+ * RightLink's log level can now be controlled by a tag, "rs_agent_dev:log_level". The rs_log_level
8
+ command is now an interface for getting or setting this tag.
9
+ * The log-level tag and command no longer apply to the RightLink agent, only to Chef and RightScript
10
+ execution. To set the RightLink agent's log level explicitly, use the "--agent" option of
11
+ rs_log_level.
12
+ * When running on a RedHat-derived distro, RightLink installs public keys for EPEL signed packages
13
+ at boot.
14
+
15
+ == Changes to Existing Functionality
16
+
17
+ * When installing RightLink, the recommended technique is to install _only_ the appropriate
18
+ cloud-support package for the cloud in which RightLink will run. The other RightLink packages
19
+ will be installed as dependencies. For instance, to install RightLink on an EC2 instance:
20
+ apt-get install rightlink-cloud-ec2
21
+ * The cloud-support packages for Rackspace clouds have been renamed to avoid confusion. The
22
+ package for Rackspace Classic is suffixed with "rackspace-first-gen". The support package for
23
+ Rackspace OpenCloud is suffixed with "rackspace-open-cloud".
24
+
25
+ == Bug Fixes
26
+
27
+ * RightLink now looks in the proper directory (/var/spool/rackspace) for cloud-injected
28
+ userdata when running on Rackspace OpenCloud.
29
+ * RightLink now requires a modern version of sudo (we rely on the #includedir directive)
30
+ * Included SUSE vendor-support tags in our rpmspec to prevent warnings from zypper
31
+ * RightLink DEBs are now signed
32
+ * Init scripts have more accurate LSB metadata, preventing warnings from init-updaters
33
+
1
34
  = 5.9.1 (RightLink 5.9 beta 2)
2
35
 
3
36
  Released 2013-08-07.
@@ -27,11 +60,13 @@ Released 2013-07-13.
27
60
 
28
61
  == New Features
29
62
 
30
- * The RS_DECOM_REASON environment variable is set during decommission script/recipe execution to indicate the reason why decommission
31
- is running. This variable will have one of the following values: 'reboot', 'stop', 'terminate' or 'unknown'
32
- The value will be 'reboot', 'stop' or 'terminate' when decommissioning through the RightScale dashboard or when using the
33
- rs_shutdown command. The 'unknown' value may be seen when the rightlink service is decommissioned (not stopped) from the console or
34
- else the instance is shutdown or rebooted without using the rs_shutdown command.
63
+ * The RS_DECOM_REASON environment variable is set during decommission script/recipe execution to
64
+ indicate the reason why decommission is running. This variable will have one of the following
65
+ values: 'reboot', 'stop', 'terminate' or 'unknown'. The value will be 'reboot', 'stop' or
66
+ 'terminate' when decommissioning through the RightScale dashboard or when using the rs_shutdown
67
+ command. The 'unknown' value may be seen when the rightlink service is decommissioned (not
68
+ stopped) from the console or else the instance is shutdown or rebooted without using the
69
+ rs_shutdown command.
35
70
  * RightLink is distributed as a modular "tree" of packages, making it easy to install just what you need
36
71
  * Improved package hygiene, e.g. clean uninstall and minimal post-install filesystem tampering
37
72
  * Ability to distinguish between sudo (server_login + server_superuser) and normal (server_login) users
@@ -169,7 +169,7 @@ class InstanceSetup
169
169
  # we are no longer freezing log level for v5.8+
170
170
  tagged_log_level = ::RightScale::CookState.dev_log_level
171
171
  RightScale::Log.level = tagged_log_level if tagged_log_level
172
- RightScale::Log.info("Tags discovered at initial startup: #{tags.inspect} (dev mode = #{::RightScale::CookState.dev_mode_enabled?})")
172
+ RightScale::Log.info("Tags discovered at initial startup: #{tags.inspect}")
173
173
  end
174
174
 
175
175
  # Setup suicide timer which will cause instance to shutdown if the rs_launch:type=auto tag
data/bin/cook_runner CHANGED
@@ -15,6 +15,7 @@ require 'right_scraper'
15
15
 
16
16
  BASE_DIR = File.join(File.dirname(__FILE__), '..')
17
17
 
18
+ require File.normalize_path(File.join(BASE_DIR, 'lib', 'right_link', 'version'))
18
19
  require File.normalize_path(File.join(BASE_DIR, 'lib', 'instance'))
19
20
  require File.normalize_path(File.join(BASE_DIR, 'lib', 'instance', 'cook'))
20
21
 
@@ -102,9 +102,7 @@ module RightScale
102
102
  return true if is_filtered?(severity, message)
103
103
  msg = format_message(format_severity(severity), Time.now, progname, message)
104
104
  case severity
105
- when Logger::DEBUG
106
- Log.debug(message)
107
- when Logger::INFO, Logger::WARN, Logger::UNKNOWN
105
+ when Logger::INFO, Logger::WARN, Logger::UNKNOWN, Logger::DEBUG
108
106
  AuditStub.instance.append_output(msg)
109
107
  when Logger::ERROR
110
108
  AuditStub.instance.append_error(msg)
@@ -94,6 +94,7 @@ module RightScale
94
94
  EM.run do
95
95
  begin
96
96
  AuditStub.instance.init(options)
97
+ check_for_missing_inputs(bundle)
97
98
  gatherer.callback { EM.defer { sequence.run } }
98
99
  gatherer.errback { success = false; report_failure(gatherer) }
99
100
  sequence.callback { success = true; send_inputs_patch(sequence) }
@@ -113,6 +114,17 @@ module RightScale
113
114
  exit(1) unless success
114
115
  end
115
116
 
117
+ def check_for_missing_inputs(bundle)
118
+ pending_executables = bundle.executables.select { |e| !e.ready }
119
+ unless pending_executables.empty?
120
+ pending_executables.each do |e|
121
+ missing_input_names = e.input_flags.collect {|k,v| k if v.member?("unready")}.compact
122
+ AuditStub.instance.append_info("Following inputs used by '#{e.nickname} are missing': #{missing_input_names.join(", ")}")
123
+ end
124
+ fail("Execution failed", "Missing inputs")
125
+ end
126
+ end
127
+
116
128
  # Determines if the current cook process has the default thread for purposes
117
129
  # of concurrency with non-defaulted cooks.
118
130
  def has_default_thread?
@@ -112,18 +112,6 @@ module RightScale
112
112
  !!@reboot
113
113
  end
114
114
 
115
- # Is the instance running in dev mode?
116
- # dev mode tweaks the behavior of the RightLink agent to help
117
- # the development of Chef recipes.
118
- # In dev mode, the log level is always debug.
119
- #
120
- # === Return
121
- # true:: If dev tags are defined on this instance
122
- # false:: Otherwise
123
- def dev_mode_enabled?
124
- !!tag_value(DEV_TAG_NAMESPACE)
125
- end
126
-
127
115
  # Determines the developer log level, if any, which forces and supercedes
128
116
  # all other log level configurations.
129
117
  #
@@ -202,7 +190,12 @@ module RightScale
202
190
  # === Return
203
191
  # level(Integer):: one of Logger::INFO ... Logger::FATAL
204
192
  def log_level
205
- @log_level
193
+ case @log_level
194
+ when Symbol, String
195
+ Log.level_from_sym(@log_level.to_sym)
196
+ else
197
+ @log_level
198
+ end
206
199
  end
207
200
 
208
201
  # Re-initialize then merge given state
@@ -557,6 +557,14 @@ module RightScale
557
557
  @audit.create_new_section('Preparing execution')
558
558
  end
559
559
 
560
+ log_desc = "Log level is #{Log.level_to_sym(CookState.log_level)}"
561
+ if CookState.dev_log_level
562
+ log_desc << " (overridden by #{CookState::LOG_LEVEL_TAG}=#{CookState.dev_log_level})"
563
+ end
564
+ log_desc << '.'
565
+ @audit.append_info(log_desc)
566
+ @audit.append_info('The download once flag is set.') if CookState.download_once?
567
+
560
568
  @audit.append_info("Run list for thread #{@thread_name.inspect} contains #{@run_list.size} items.")
561
569
  @audit.append_info(@run_list.join(', '))
562
570
 
@@ -109,12 +109,12 @@ module RightScale
109
109
  attempts += 1
110
110
  t0 = Time.now
111
111
 
112
- # Previously we accessed RestClient directly and used it's wrapper method to instantiate
112
+ # Previously we accessed RestClient directly and used it's wrapper method to instantiate
113
113
  # a RestClient::Request object. This wrapper was not passing all options down the stack
114
114
  # so now we invoke the RestClient::Request object directly, passing it our desired options
115
- client.execute(:method => :get, :url => "https://#{endpoint}:443#{resource}", :timeout => calculate_timeout(attempts), :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :ssl_ca_file => get_ca_file, :headers => {:user_agent => "RightLink v#{AgentConfig.protocol_version}"}) do |response, request, result|
115
+ client.execute(:method => :get, :url => "https://#{endpoint}:443#{resource}", :timeout => calculate_timeout(attempts), :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :ssl_ca_file => get_ca_file, :headers => {:user_agent => "RightLink v#{AgentConfig.protocol_version}", 'X-RightLink-Version' => RightLink::VERSION }) do |response, request, result|
116
116
  if result.kind_of?(Net::HTTPSuccess)
117
- @size = result.content_length
117
+ @size = result.content_length || response.size || 0
118
118
  @speed = @size / (Time.now - t0)
119
119
  yield response
120
120
  else
@@ -223,7 +223,7 @@ module RightScale
223
223
 
224
224
  # Orders ips by hostnames
225
225
  #
226
- # The purpose of this method is to sort ips of hostnames so it tries all IPs of hostname 1,
226
+ # The purpose of this method is to sort ips of hostnames so it tries all IPs of hostname 1,
227
227
  # then all IPs of hostname 2, etc
228
228
  #
229
229
  # == Return
@@ -264,7 +264,7 @@ module RightScale
264
264
  )
265
265
  end
266
266
 
267
- # Exponential incremental timeout algorithm. Returns the amount of
267
+ # Exponential incremental timeout algorithm. Returns the amount of
268
268
  # of time to wait for the next iteration
269
269
  #
270
270
  # === Parameters
@@ -0,0 +1,4 @@
1
+ module RightLink
2
+ VERSION = "5.9.2"
3
+ end
4
+
@@ -1,5 +1,5 @@
1
1
  # === Synopsis:
2
- # RightScale Agent Checker (rchk) - (c) 2010-2011 RightScale Inc
2
+ # RightScale Agent Checker (rchk) - (c) 2010-2013 RightScale Inc
3
3
  #
4
4
  # Checks the agent to see if it is actively communicating with RightNet and if not
5
5
  # triggers it to re-enroll and exits.
@@ -37,6 +37,7 @@ require 'right_agent/scripts/common_parser'
37
37
 
38
38
  require File.normalize_path(File.join(File.dirname(__FILE__), '..', 'lib', 'instance', 'agent_watcher'))
39
39
  require File.normalize_path(File.join(File.dirname(__FILE__), '..', 'lib', 'instance', 'agent_config'))
40
+ require File.expand_path(File.join(File.dirname(__FILE__), 'command_helper'))
40
41
 
41
42
  module RightScale
42
43
 
@@ -81,7 +82,7 @@ module RightScale
81
82
  end # AgentCheckerCommands
82
83
 
83
84
  class AgentChecker
84
-
85
+ include CommandHelper
85
86
  include DaemonizeHelper
86
87
 
87
88
  VERSION = [0, 1]
@@ -163,7 +164,6 @@ module RightScale
163
164
  def start(options)
164
165
  begin
165
166
  setup_traps
166
- @command_serializer = Serializer.new
167
167
  @state_serializer = Serializer.new(:json)
168
168
 
169
169
  # Retrieve instance agent configuration options
@@ -248,7 +248,7 @@ module RightScale
248
248
  version ""
249
249
  end
250
250
 
251
- begin
251
+ parse do
252
252
  options = parser.parse
253
253
  options.delete(:max_attempts) unless options[:max_attempts] > 0
254
254
  if options[:delete]
@@ -256,17 +256,10 @@ module RightScale
256
256
  end
257
257
  options.delete(:retry_interval) unless options[:retry_interval] > 0
258
258
  options
259
- rescue Trollop::HelpNeeded
260
- puts Usage.scan(__FILE__)
261
- exit
262
- rescue Trollop::CommandlineError => e
263
- error("#{e}\nUse --help for additional information", nil, abort = true)
264
- rescue Trollop::VersionNeeded
265
- puts version
266
- exit
267
259
  end
268
260
  end
269
261
 
262
+
270
263
  protected
271
264
 
272
265
  # Perform required checks
@@ -285,8 +278,7 @@ protected
285
278
  info("Stopping checker daemon")
286
279
  if RightScale::Platform.windows?
287
280
  begin
288
- client = CommandClient.new(pid_data[:listen_port], pid_data[:cookie])
289
- client.send_command({:name => :terminate}, verbose = @options[:verbose], timeout = 30) do |r|
281
+ send_command({:name => :terminate}, verbose = @options[:verbose], timeout = 30) do |r|
290
282
  info(r)
291
283
  terminate
292
284
  end
@@ -391,11 +383,9 @@ protected
391
383
  # true:: Always return true
392
384
  def try_communicating(attempt)
393
385
  begin
394
- listen_port = @agent[:listen_port]
395
- client = CommandClient.new(listen_port, @agent[:cookie])
396
- client.send_command({:name => "check_connectivity"}, @options[:verbose], COMMAND_IO_TIMEOUT) do |r|
386
+ send_command({:name => "check_connectivity"}, @options[:verbose], COMMAND_IO_TIMEOUT) do |r|
397
387
  @command_io_failures = 0
398
- res = OperationResult.from_results(@command_serializer.load(r)) rescue nil
388
+ res = serialize_operation_result(r) rescue nil
399
389
  if res && res.success?
400
390
  info("Successful agent communication" + (attempt > 1 ? " on attempt #{attempt}" : ""))
401
391
  @retry_timer.cancel if @retry_timer
@@ -542,7 +532,11 @@ protected
542
532
  # === Return
543
533
  # ver(String):: Version information
544
534
  def version
545
- ver = "rchk #{VERSION.join('.')} - RightScale Agent Checker (c) 2010 RightScale"
535
+ ver = "rchk #{VERSION.join('.')} - RightScale Agent Checker (c) 2013 RightScale"
536
+ end
537
+
538
+ def usage
539
+ Usage.scan(__FILE__)
546
540
  end
547
541
 
548
542
  end # AgentChecker
@@ -1,5 +1,5 @@
1
1
  # === Synopsis:
2
- # RightScale Agent Controller (rnac) - (c) 2009-2011 RightScale Inc
2
+ # RightScale Agent Controller (rnac) - (c) 2009-2013 RightScale Inc
3
3
  #
4
4
  # rnac is a command line tool for managing a RightLink agent
5
5
  #
@@ -79,10 +79,12 @@ require 'rubygems'
79
79
  require 'right_agent/scripts/agent_controller'
80
80
 
81
81
  require File.normalize_path(File.join(File.dirname(__FILE__), '..', 'lib', 'instance', 'agent_watcher'))
82
+ require File.expand_path(File.join(File.dirname(__FILE__), 'command_helper'))
82
83
 
83
84
  module RightScale
84
85
 
85
86
  class RightLinkAgentController < AgentController
87
+ include CommandHelper
86
88
 
87
89
  # Create and run controller
88
90
  #
@@ -157,16 +159,9 @@ module RightScale
157
159
  # === Return
158
160
  # (Boolean):: true if command executed successfully, otherwise false
159
161
  def run_command(message, command)
160
- options = AgentConfig.agent_options(@options[:agent_name])
161
- listen_port = options[:listen_port]
162
- unless listen_port
163
- $stderr.puts "Could not retrieve listen port for agent #{@options[:identity]}"
164
- return false
165
- end
166
162
  puts message
167
163
  begin
168
- @client = CommandClient.new(listen_port, options[:cookie])
169
- @client.send_command({ :name => command }, verbose = false, timeout = 100) { |r| puts r }
164
+ send_command({ :name => command }, verbose = false, timeout = 100) { |r| puts r }
170
165
  rescue SystemExit => e
171
166
  raise e
172
167
  rescue Exception => e
@@ -1,5 +1,5 @@
1
1
  # === Synopsis:
2
- # RightScale Agent Deployer (rad) - (c) 2009-2011 RightScale Inc
2
+ # RightScale Agent Deployer (rad) - (c) 2009-2013 RightScale Inc
3
3
  #
4
4
  # rad is a command line tool for building the configuration file for a RightLink agent
5
5
  #
@@ -1,5 +1,5 @@
1
1
  # === Synopsis:
2
- # RightScale Bundle Runner (rs_run_right_script/rs_run_recipe) - (c) 2009-2011 RightScale Inc
2
+ # RightScale Bundle Runner (rs_run_right_script/rs_run_recipe) - (c) 2009-2013 RightScale Inc
3
3
  #
4
4
  # rs_run_right_script and rs_run_recipe are command line tools that allow
5
5
  # running RightScripts and recipes respectively from within an instance
@@ -68,10 +68,12 @@ require 'right_agent'
68
68
  require 'right_agent/scripts/usage'
69
69
  require 'right_agent/scripts/common_parser'
70
70
  require 'right_agent/core_payload_types'
71
+ require File.expand_path(File.join(File.dirname(__FILE__), 'command_helper'))
71
72
 
72
73
  module RightScale
73
74
 
74
75
  class BundleRunner
76
+ include CommandHelper
75
77
 
76
78
  # Default number of seconds to wait for command response
77
79
  DEFAULT_TIMEOUT = 20
@@ -97,15 +99,10 @@ module RightScale
97
99
  cmd = { :options => to_forwarder_options(options) }
98
100
  cmd[:name] = options[:bundle_type] == :right_script ? 'run_right_script' : 'run_recipe'
99
101
  AgentConfig.cfg_dir = options[:cfg_dir]
100
- config_options = AgentConfig.agent_options('instance')
101
- listen_port = config_options[:listen_port]
102
- fail('Could not retrieve listen port', false) unless listen_port
103
- command_serializer = Serializer.new
104
- client = CommandClient.new(listen_port, config_options[:cookie])
105
102
 
106
103
  exit_code = true
107
104
  callback ||= lambda do |r|
108
- response = OperationResult.from_results(command_serializer.load(r)) rescue nil
105
+ response = serialize_operation_result(r) rescue nil
109
106
  if r == 'OK'
110
107
  puts "Request sent successfully"
111
108
  elsif response.respond_to?(:success?) && response.success?
@@ -117,8 +114,9 @@ module RightScale
117
114
  end
118
115
 
119
116
  begin
117
+ check_privileges
120
118
  timeout = options[:timeout] || DEFAULT_TIMEOUT
121
- client.send_command(cmd, options[:verbose], timeout) { |r| callback.call(r) }
119
+ send_command(cmd, options[:verbose], timeout) { |r| callback.call(r) }
122
120
  rescue Exception => e
123
121
  fail(e.message)
124
122
  end
@@ -187,7 +185,7 @@ module RightScale
187
185
  version ""
188
186
  end
189
187
 
190
- begin
188
+ parse do
191
189
  options.merge!(parser.parse(arguments))
192
190
  options.delete(:name) if options[:id]
193
191
  if options[:parameter]
@@ -222,46 +220,10 @@ module RightScale
222
220
  end
223
221
  end
224
222
  options
225
- rescue Trollop::HelpNeeded
226
- puts Usage.scan(__FILE__)
227
- exit
228
- rescue Trollop::VersionNeeded
229
- puts version
230
- succeed
231
- rescue Exception => e
232
- puts e.message + "\nUse --help for additional information"
233
- exit(1)
234
223
  end
235
224
  end
236
225
 
237
226
  protected
238
-
239
- # Print error on console and exit abnormally
240
- #
241
- # === Parameter
242
- # reason(String|Exception):: Error message or exception, default to nil (no message printed)
243
- # print_usage(Boolean):: Whether script usage should be printed, default to false
244
- #
245
- # === Return
246
- # R.I.P. does not return
247
- def fail(reason=nil, print_usage=false)
248
- case reason
249
- when Errno::EACCES
250
- STDERR.puts "** #{reason.message}"
251
- STDERR.puts "** Try elevating privilege (sudo/runas) before invoking this command."
252
- code = 2
253
- when Exception
254
- STDERR.puts "** #{reason.message}"
255
- code = 1
256
- else
257
- STDERR.puts "** #{reason}" if reason
258
- code = 1
259
- end
260
-
261
- puts Usage.scan(__FILE__) if print_usage
262
- exit(code)
263
- end
264
-
265
227
  # Map arguments options into forwarder actor compatible options
266
228
  #
267
229
  # === Parameters
@@ -301,12 +263,11 @@ protected
301
263
  # === Return
302
264
  # (String):: Version information
303
265
  def version
304
- gemspec = eval(File.read(File.join(File.dirname(__FILE__), '..', 'right_link.gemspec')))
305
- "rs_run_right_script & rs_run_recipe #{gemspec.version} - RightLink's bundle runner (c) 2011 RightScale"
266
+ "rs_run_right_script & rs_run_recipe #{right_link_version} - RightLink's bundle runner (c) 2013 RightScale"
306
267
  end
307
268
 
308
- def succeed
309
- exit(0)
269
+ def usage
270
+ Usage.scan(__FILE__)
310
271
  end
311
272
 
312
273
  end # BundleRunner
@@ -1,5 +1,5 @@
1
1
  # === Synopsis:
2
- # RightScale Cloud Controller (cloud) - Copyright (c) 2011 by RightScale Inc
2
+ # RightScale Cloud Controller (cloud) - Copyright (c) 2013 by RightScale Inc
3
3
  #
4
4
  # cloud is a command line tool which invokes cloud-specific actions
5
5
  #
@@ -37,10 +37,12 @@ require 'right_agent/scripts/usage'
37
37
 
38
38
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'instance', 'agent_config'))
39
39
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'clouds', 'register_clouds'))
40
+ require File.expand_path(File.join(File.dirname(__FILE__), 'command_helper'))
40
41
 
41
42
  module RightScale
42
43
 
43
44
  class CloudController
45
+ include CommandHelper
44
46
 
45
47
  # Convenience wrapper
46
48
  def self.run
@@ -121,7 +123,7 @@ module RightScale
121
123
  opt :quiet # note that :quiet is deprecated (use -v instead) because Trollop cannot easily support inverse flags that default to true
122
124
  opt :verbose
123
125
  end
124
- begin
126
+ parse do
125
127
  options = parser.parse
126
128
  if options[:parameters_given]
127
129
  if options[:parameters].start_with?("[")
@@ -131,12 +133,13 @@ module RightScale
131
133
  end
132
134
  end
133
135
  options
134
- rescue Trollop::HelpNeeded
135
- puts Usage.scan(__FILE__)
136
- exit 0
137
136
  end
138
137
  end
139
138
 
139
+ def usage
140
+ Usage.scan(__FILE__)
141
+ end
142
+
140
143
  # Default logger for printing to console
141
144
  def default_logger(verbose)
142
145
  if verbose
@@ -0,0 +1,101 @@
1
+ module RightScale
2
+ module CommandHelper
3
+ def check_privileges
4
+ config_options = ::RightScale::AgentConfig.agent_options('instance')
5
+ pid_dir = config_options[:pid_dir]
6
+ identity = config_options[:identity]
7
+ raise ::ArgumentError.new('Could not get cookie file path') if (pid_dir.nil? & identity.nil?)
8
+ cookie_file = File.join(pid_dir, "#{identity}.cookie")
9
+ File.open(cookie_file, "r") { |f| f.close }
10
+ true
11
+ rescue Errno::EACCES => e
12
+ fail(e)
13
+ end
14
+ # Creates a command client and sends the given payload.
15
+ #
16
+ # === Parameters
17
+ # @param [Hash] cmd as a payload hash
18
+ # @param [TrueClass, FalseClass] verbose flag
19
+ # @param [TrueClass, FalseClass] timeout or nil
20
+ #
21
+ # === Block
22
+ # @yield [response] callback for response
23
+ # @yieldparam response [Object] response of any type
24
+ def send_command(cmd, verbose, timeout=20)
25
+ config_options = ::RightScale::AgentConfig.agent_options('instance')
26
+ listen_port = config_options[:listen_port]
27
+ raise ::ArgumentError.new('Could not retrieve agent listen port') unless listen_port
28
+ client = ::RightScale::CommandClient.new(listen_port, config_options[:cookie])
29
+ result = nil
30
+ block = Proc.new do |res|
31
+ result = res
32
+ yield res if block_given?
33
+ end
34
+ client.send_command(cmd, verbose, timeout, &block)
35
+ result
36
+ end
37
+
38
+ def serialize_operation_result(res)
39
+ command_serializer = ::RightScale::Serializer.new
40
+ ::RightScale::OperationResult.from_results(command_serializer.load(res))
41
+ end
42
+
43
+ # Exit with success.
44
+ #
45
+ # === Return
46
+ # R.I.P. does not return
47
+ def succeed
48
+ exit(0)
49
+ end
50
+
51
+ # Print error on console and exit abnormally
52
+ #
53
+ # === Parameter
54
+ # reason(Exception|String|Integer):: Exception, error message or numeric failure code
55
+ #
56
+ # === Return
57
+ # R.I.P. does not return
58
+ def fail(reason=nil)
59
+ case reason
60
+ when Errno::EACCES
61
+ STDERR.puts reason.message
62
+ STDERR.puts "Try elevating privilege (sudo/runas) before invoking this command."
63
+ code = 2
64
+ when Exception
65
+ STDERR.puts reason.message
66
+ code = reason.respond_to(:code) ? reason.code : 50
67
+ when String
68
+ STDERR.puts reason
69
+ code = 50
70
+ when Integer
71
+ code = reason
72
+ else
73
+ code = 1
74
+ end
75
+
76
+ exit(code)
77
+ end
78
+
79
+ def parse
80
+ begin
81
+ yield
82
+ rescue Trollop::VersionNeeded
83
+ STDOUT.puts(version)
84
+ succeed
85
+ rescue Trollop::HelpNeeded
86
+ STDOUT.puts(usage)
87
+ succeed
88
+ rescue Trollop::CommandlineError => e
89
+ puts e.message + "\nUse --help for additional information"
90
+ fail
91
+ rescue SystemExit => e
92
+ raise e
93
+ end
94
+ end
95
+
96
+ def right_link_version
97
+ gemspec = eval(File.read(File.join(File.dirname(__FILE__), '..', 'right_link.gemspec')))
98
+ gemspec.version
99
+ end
100
+ end
101
+ end