right_link 5.9.1 → 5.9.2

Sign up to get free protection for your applications and to get access to all the features.
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