Class: OpsWalrus::RuntimeEnvironment

Inherits:
Object
  • Object
show all
Includes:
Traversable
Defined in:
lib/opswalrus/runtime_environment.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Traversable

#pre_order_traverse

Constructor Details

#initialize(app) ⇒ RuntimeEnvironment

Returns a new instance of RuntimeEnvironment.



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/opswalrus/runtime_environment.rb', line 241

def initialize(app)
  @app = app
  @env = @app.inventory.env.deep_merge(ENV.to_h).with_indifferent_access.easynav
  @bundle_load_path = LoadPath.new(self, @app.bundle_dir)
  @app_load_path = LoadPath.new(self, @app.pwd)

  # we include this sudo password mapping by default because if a bundled script is being run on a remote host,
  # then the remote command invocation will include the --pass flag when being run on the remote host, which will
  # interactively prompt for a sudo password, and that will be the only opportunity for the command host
  # that is running the bundled script on the remote host to interactively enter a sudo password for the remote context
  # since the remote ops command will be running within a PTY, and the interactive prompts running on the remote
  # host will be managed by the local ScopedMappingInteractionHandler running within the instance of the ops command
  # process on the remote host, and the command host will not have any further opportunity to interactively enter
  # any prompts on the remote host
  # All that to say that this initial mapping handler will be used to fill in the sudo password for commands running
  # on the remote host, and it will be the instance of the ops tool running on the remote host that will interactively
  # fill out the password on the remote host
  interaction_handler_mapping_for_sudo_password = ScopedMappingInteractionHandler.mapping_for_sudo_password(sudo_password)
  @interaction_handler = ScopedMappingInteractionHandler.new(interaction_handler_mapping_for_sudo_password)

  configure_sshkit
end

Instance Attribute Details

#appObject

Returns the value of attribute app.



237
238
239
# File 'lib/opswalrus/runtime_environment.rb', line 237

def app
  @app
end

#envObject (readonly)

Returns the value of attribute env.



239
240
241
# File 'lib/opswalrus/runtime_environment.rb', line 239

def env
  @env
end

#ptyObject

Returns the value of attribute pty.



238
239
240
# File 'lib/opswalrus/runtime_environment.rb', line 238

def pty
  @pty
end

Instance Method Details

#configure_sshkitObject

configure sshkit globally



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/opswalrus/runtime_environment.rb', line 282

def configure_sshkit
  SSHKit.config.use_format :blackhole
  SSHKit.config.output_verbosity = :info

  if app.debug? || app.trace?
    SSHKit.config.use_format :pretty
    SSHKit.config.output_verbosity = :debug
  end

  SSHKit::Backend::Netssh.configure do |ssh|
    ssh.pty = true                # necessary for interaction with sudo on the remote host
    ssh.connection_timeout = 60   # seconds
    ssh.ssh_options = {           # this hash is passed in as the options hash (3rd argument) to Net::SSH.start(host, user, options) - see https://net-ssh.github.io/net-ssh/Net/SSH.html
      auth_methods: %w(publickey password),   # :auth_methods => an array of authentication methods to try
                                              # :forward_agent => set to true if you want the SSH agent connection to be forwarded
                                              # :keepalive => set to true to send a keepalive packet to the SSH server when there's no traffic between the SSH server and Net::SSH client for the keepalive_interval seconds. Defaults to false.
                                              # :keepalive_interval => the interval seconds for keepalive. Defaults to 300 seconds.
                                              # :keepalive_maxcount => the maximun number of keepalive packet miss allowed. Defaults to 3
      timeout: 2,                             # :timeout => how long to wait for the initial connection to be made
    }
  end
  SSHKit::Backend::Netssh.pool.idle_timeout = 1   # seconds
end

#find_load_path_that_includes_path(path) ⇒ Object



336
337
338
339
340
# File 'lib/opswalrus/runtime_environment.rb', line 336

def find_load_path_that_includes_path(path)
  load_path = [@bundle_load_path, @app_load_path].find {|load_path| load_path.includes_path?(path) }
  raise SymbolResolutionError, "No load path includes the path: #{path}" unless load_path
  load_path
end

#handle_input(input_mapping, sudo_password: nil, ops_sudo_password: nil, inherit_existing_mappings: true, lookback_window_chars: DefaultLookbackWindowCharCount, &block) ⇒ Object

input_mapping : Hash[ String | Regex => String ] sudo_password : String



270
271
272
273
274
275
276
277
278
279
# File 'lib/opswalrus/runtime_environment.rb', line 270

def handle_input(input_mapping, sudo_password: nil, ops_sudo_password: nil, inherit_existing_mappings: true, lookback_window_chars: DefaultLookbackWindowCharCount, &block)
  @interaction_handler.with_mapping(
    input_mapping,
    sudo_password: sudo_password,
    ops_sudo_password: ops_sudo_password,
    inherit_existing_mappings: inherit_existing_mappings,
    lookback_window_chars: lookback_window_chars,
    &block
  )
end

#invoke(ops_file, hashlike_params) ⇒ Object



332
333
334
# File 'lib/opswalrus/runtime_environment.rb', line 332

def invoke(ops_file, hashlike_params)
  ops_file.invoke(self, hashlike_params)
end

#local_hostnameObject



306
307
308
# File 'lib/opswalrus/runtime_environment.rb', line 306

def local_hostname
  @app.local_hostname
end

#read_secret(secret_name) ⇒ Object



264
265
266
# File 'lib/opswalrus/runtime_environment.rb', line 264

def read_secret(secret_name)
  @app.inventory.read_secret(secret_name.to_s)
end

#resolve_import_reference(origin_ops_file, import_reference) ⇒ Object

returns a Namespace | OpsFile



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/opswalrus/runtime_environment.rb', line 353

def resolve_import_reference(origin_ops_file, import_reference)
  load_path = case import_reference

  # We know we're dealing with a package dependency reference, so we want to do the lookup in the bundle load path, where package dependencies live.
  # Package references are guaranteed to live in the bundle dir
  when PackageDependencyReference, DynamicPackageImportReference
    @bundle_load_path
  when DirectoryReference
    find_load_path_that_includes_path(import_reference.dirname)
  when OpsFileReference
    find_load_path_that_includes_path(import_reference.ops_file_path)
  end

  namespace_or_ops_file = load_path.resolve_import_reference(origin_ops_file, import_reference)

  raise SymbolResolutionError, "Import reference '#{import_reference.summary}' not in load path for #{origin_ops_file.ops_file_path}" unless namespace_or_ops_file

  namespace_or_ops_file
end

#resolve_sibling_symbol(origin_ops_file, symbol_name) ⇒ Object

returns a Namespace | OpsFile



343
344
345
346
347
348
349
350
# File 'lib/opswalrus/runtime_environment.rb', line 343

def resolve_sibling_symbol(origin_ops_file, symbol_name)
  # if the origin_ops_file's file path is contained within a Bundler::BUNDLE_DIR directory, then we want to consult the @bundle_load_path
  # otherwise, we want to consult the @app_load_path
  load_path = find_load_path_that_includes_path(origin_ops_file.ops_file_path)
  namespace_or_ops_file = load_path.resolve_symbol(origin_ops_file, symbol_name)
  raise SymbolResolutionError, "Symbol '#{symbol_name}' not in load path for #{origin_ops_file.ops_file_path}" unless namespace_or_ops_file
  namespace_or_ops_file
end

#run(entry_point_ops_file, params_hash) ⇒ Object



322
323
324
325
326
327
328
329
330
# File 'lib/opswalrus/runtime_environment.rb', line 322

def run(entry_point_ops_file, params_hash)
  runtime_env = self
  SSHKit::Backend::LocalPty.new do
    runtime_env.pty = self
    retval = runtime_env.invoke(entry_point_ops_file, params_hash)
    runtime_env.pty = nil
    retval
  end.run
end

#sudo_passwordObject



314
315
316
# File 'lib/opswalrus/runtime_environment.rb', line 314

def sudo_password
  @app.sudo_password
end

#sudo_userObject



310
311
312
# File 'lib/opswalrus/runtime_environment.rb', line 310

def sudo_user
  @app.sudo_user
end

#zip_bundle_pathObject



318
319
320
# File 'lib/opswalrus/runtime_environment.rb', line 318

def zip_bundle_path
  app.zip
end