Class: ForemanRemoteExecutionCore::ScriptRunner
- Inherits:
-
ForemanTasksCore::Runner::Base
- Object
- ForemanTasksCore::Runner::Base
- ForemanRemoteExecutionCore::ScriptRunner
- Defined in:
- lib/foreman_remote_execution_core/script_runner.rb
Direct Known Subclasses
Constant Summary collapse
- EXPECTED_POWER_ACTION_MESSAGES =
['restart host', 'shutdown host'].freeze
- DEFAULT_REFRESH_INTERVAL =
1
- MAX_PROCESS_RETRIES =
4
- VERIFY_HOST_KEY =
Gem::Version.create(Net::SSH::Version::STRING) < Gem::Version.create('5.0.0') || :accept_new_or_local_tunnel
Instance Attribute Summary collapse
-
#execution_timeout_interval ⇒ Object
readonly
Returns the value of attribute execution_timeout_interval.
Class Method Summary collapse
Instance Method Summary collapse
- #close ⇒ Object
-
#initialization_script ⇒ Object
the script that initiates the execution.
-
#initialize(options, user_method, suspended_action: nil) ⇒ ScriptRunner
constructor
A new instance of ScriptRunner.
- #kill ⇒ Object
- #prepare_start ⇒ Object
- #publish_data(data, type) ⇒ Object
- #refresh ⇒ Object
- #start ⇒ Object
- #timeout ⇒ Object
- #timeout_interval ⇒ Object
- #trigger(*args) ⇒ Object
- #with_disconnect_handling ⇒ Object
- #with_retries ⇒ Object
Constructor Details
#initialize(options, user_method, suspended_action: nil) ⇒ ScriptRunner
Returns a new instance of ScriptRunner.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 111 def initialize(, user_method, suspended_action: nil) super suspended_action: suspended_action @host = .fetch(:hostname) @script = .fetch(:script) @ssh_user = .fetch(:ssh_user, 'root') @ssh_port = .fetch(:ssh_port, 22) @ssh_password = .fetch(:secrets, {}).fetch(:ssh_password, nil) @key_passphrase = .fetch(:secrets, {}).fetch(:key_passphrase, nil) @host_public_key = .fetch(:host_public_key, nil) @verify_host = .fetch(:verify_host, nil) @execution_timeout_interval = .fetch(:execution_timeout_interval, nil) @client_private_key_file = settings.fetch(:ssh_identity_key_file) @local_working_dir = .fetch(:local_working_dir, settings.fetch(:local_working_dir)) @remote_working_dir = .fetch(:remote_working_dir, settings.fetch(:remote_working_dir)) @cleanup_working_dirs = .fetch(:cleanup_working_dirs, settings.fetch(:cleanup_working_dirs)) @first_execution = .fetch(:first_execution, false) @user_method = user_method end |
Instance Attribute Details
#execution_timeout_interval ⇒ Object (readonly)
Returns the value of attribute execution_timeout_interval.
103 104 105 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 103 def execution_timeout_interval @execution_timeout_interval end |
Class Method Details
.build(options, suspended_action:) ⇒ Object
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 131 def self.build(, suspended_action:) effective_user = .fetch(:effective_user, nil) ssh_user = .fetch(:ssh_user, 'root') effective_user_method = .fetch(:effective_user_method, 'sudo') user_method = if effective_user.nil? || effective_user == ssh_user NoopUserMethod.new elsif effective_user_method == 'sudo' SudoUserMethod.new(effective_user, ssh_user, .fetch(:secrets, {}).fetch(:effective_user_password, nil)) elsif effective_user_method == 'dzdo' DzdoUserMethod.new(effective_user, ssh_user, .fetch(:secrets, {}).fetch(:effective_user_password, nil)) elsif effective_user_method == 'su' SuUserMethod.new(effective_user, ssh_user, .fetch(:secrets, {}).fetch(:effective_user_password, nil)) else raise "effective_user_method '#{effective_user_method}' not supported" end new(, user_method, suspended_action: suspended_action) end |
Instance Method Details
#close ⇒ Object
244 245 246 247 248 249 250 251 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 244 def close run_sync("rm -rf \"#{remote_command_dir}\"") if should_cleanup? rescue => e publish_exception('Error when removing remote working dir', e, false) ensure @session.close if @session && !@session.closed? FileUtils.rm_rf(local_command_dir) if Dir.exist?(local_command_dir) && @cleanup_working_dirs end |
#initialization_script ⇒ Object
the script that initiates the execution
176 177 178 179 180 181 182 183 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 176 def initialization_script su_method = @user_method.instance_of?(ForemanRemoteExecutionCore::SuUserMethod) # pipe the output to tee while capturing the exit code in a file <<-SCRIPT.gsub(/^\s+\| /, '') | sh -c "(#{@user_method.cli_command_prefix}#{su_method ? "'#{@remote_script} < /dev/null '" : "#{@remote_script} < /dev/null"}; echo \\$?>#{@exit_code_path}) | /usr/bin/tee #{@output_path} | exit \\$(cat #{@exit_code_path})" SCRIPT end |
#kill ⇒ Object
197 198 199 200 201 202 203 204 205 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 197 def kill if @session run_sync("pkill -f #{remote_command_file('script')}") else logger.debug('connection closed') end rescue => e publish_exception('Unexpected error', e, false) end |
#prepare_start ⇒ Object
169 170 171 172 173 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 169 def prepare_start @remote_script = cp_script_to_remote @output_path = File.join(File.dirname(@remote_script), 'output') @exit_code_path = File.join(File.dirname(@remote_script), 'exit_code') end |
#publish_data(data, type) ⇒ Object
253 254 255 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 253 def publish_data(data, type) super(data.force_encoding('UTF-8'), type) end |
#refresh ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 185 def refresh return if @session.nil? with_retries do with_disconnect_handling do @session.process(0) end end ensure check_expecting_disconnect end |
#start ⇒ Object
154 155 156 157 158 159 160 161 162 163 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 154 def start Utils.prune_known_hosts!(@host, @ssh_port, logger) if @first_execution prepare_start script = initialization_script logger.debug("executing script:\n#{indent_multiline(script)}") trigger(script) rescue StandardError, NotImplementedError => e logger.error("error while initalizing command #{e.class} #{e.}:\n #{e.backtrace.join("\n")}") publish_exception('Error initializing command', e) end |
#timeout ⇒ Object
207 208 209 210 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 207 def timeout @logger.debug('job timed out') super end |
#timeout_interval ⇒ Object
212 213 214 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 212 def timeout_interval execution_timeout_interval end |
#trigger(*args) ⇒ Object
165 166 167 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 165 def trigger(*args) run_async(*args) end |
#with_disconnect_handling ⇒ Object
232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 232 def with_disconnect_handling yield rescue IOError, Net::SSH::Disconnect => e @session.shutdown! check_expecting_disconnect if @expecting_disconnect publish_exit_status(0) else publish_exception('Unexpected disconnect', e) end end |
#with_retries ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/foreman_remote_execution_core/script_runner.rb', line 216 def with_retries tries = 0 begin yield rescue => e logger.error("Unexpected error: #{e.class} #{e.}\n #{e.backtrace.join("\n")}") tries += 1 if tries <= MAX_PROCESS_RETRIES logger.error('Retrying') retry else publish_exception('Unexpected error', e) end end end |