class NoradSpecRunner::RemoteTask
Class to run Rspec tests over SSH
Constants
- SSH_TIMEOUT
Attributes
cisco_enable_pw[R]
disable_sudo[R]
host[R]
obj[R]
platform[R]
results_file[R]
ssh_port[R]
sshkey[R]
tests_parent_dir[R]
username[R]
Public Class Methods
new(encoded_key, options)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 16 def initialize(encoded_key, options) @host = options.fetch(:host) @sshkey = options.fetch(:sshkey) @cisco_enable_pw = options.fetch(:cisco_enable_pw, '') @disable_sudo = options.fetch(:disable_sudo, 'true') # Decode the key and store File.open(@sshkey, "w") do |f| f.write Base64.decode64(encoded_key) end @ssh_port = options.fetch(:port, nil) @username = options.fetch(:username, nil) @tests_parent_dir = ENV.fetch('TESTS_PARENT_DIR', '/') tests = options.fetch(:tests) detect_os = options.fetch(:detect_os, false) @obj = RSpec::Core::RakeTask.new(@host) do |_| true end @results_file = options.fetch(:results_file) @obj.pattern = detect_os ? autodetect_test_pattern(tests) : tests @obj.rspec_opts = build_rspec_opts(options) rescue Exception => e write_error_to_results_file e.message end
Public Instance Methods
run()
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 41 def run pstderr = STDERR.dup ftmp = Tempfile.open('eout') FileUtils.touch results_file return if platform.nil? && unable_to_ssh? ENV['AUDIT_HOST'] = host ENV['AUDIT_USERNAME'] = username ENV['AUDIT_SSHKEY'] = sshkey ENV['AUDIT_SSH_PORT'] = ssh_port ENV['AUDIT_CISCO_ENABLE_PASSWORD'] = cisco_enable_pw ENV['AUDIT_DISABLE_SUDO'] = disable_sudo.to_s # Capture STDERR for SSH related errors STDERR.reopen(ftmp) obj.run_task(true) rescue SystemExit => e ftmp.rewind err = ftmp.read ftmp.close p err # We land here even on successful run (SystemExit exception), only report error if stderr is not empty if err =~ /Please set sudo password to Specinfra.configuration.sudo_password|set :request_pty, true/ write_error_to_results_file "SSH user #{username} requires SUDO permission with NOPASSWD: option set." elsif not err.empty? write_error_to_results_file err end rescue Exception => e # Unknown exception! write_error_to_results_file e.message ensure STDERR.reopen pstderr end
Private Instance Methods
autodetect_test_pattern(tests)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 87 def autodetect_test_pattern(tests) pattern = select_spec_for_os(tests) puts "Trying to run #{pattern}" pattern end
build_rspec_opts(options)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 143 def build_rspec_opts(options) sub_tests = options.fetch(:sub_tests) rspec_opts = [ '--format NoradSpecRunner::CustomJsonFormatter', "-r #{__dir__}/example.rb", "-r #{__dir__}/formatter.rb", "-o #{@results_file}"] options.fetch(:tags).split(',').each do |tag| rspec_opts << "--tag=#{tag}" end # --tag and --example do not work together so # if there is a tag disable example option if options.fetch(:tags) == '' rspec_opts << "-e #{sub_tests}" end rspec_opts.join(' ') end
select_spec_for_os(test_name)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 93 def select_spec_for_os(test_name) # Explicitly need this test case first if target_is_ios_device?(start_ssh_session) test_klass = SecTest elsif target_is_linux?(start_ssh_session) test_klass = LinuxSecTest else test_klass = SecTest end test_klass.new(tests_parent_dir, test_name, platform).test_to_run end
start_ssh_session()
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 83 def start_ssh_session Net::SSH.start(host, username, port: ssh_port, timeout: SSH_TIMEOUT, auth_methods: ['publickey'], keys: [sshkey] ) end
target_is_ios_device?(ssh_session)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 105 def target_is_ios_device?(ssh_session) out = ssh_session.exec!('show version') if out =~ /Cisco ((?:\w+\s?){1,6}) Software.+Version ([[:alnum:][:punct:]]+)/ @platform = $1.gsub(/\s/, '_').downcase end !@platform.nil? end
target_is_linux?(ssh_session)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 113 def target_is_linux?(ssh_session) spec_infra_backend = Specinfra::Backend::Ssh.new spec_infra_backend.set_config(:ssh, ssh_session) spec_infra_backend.set_config(:ssh_options, { user: username }) spec_infra_backend.set_config(:request_pty, true) Specinfra::Helper::DetectOs.subclasses.each do |c| detector = c.new(spec_infra_backend) res = detector.detect if res && res[:family] res[:arch] ||= spec_infra_backend.run_command('uname -m').stdout.strip @platform = res[:family] # we can optionally add release here if we want break end end !@platform.nil? end
unable_to_ssh?()
click to toggle source
Check if given host/ip is reachable and we can ssh as root If not, then create empty log file for that host and return false.
# File lib/norad_spec_runner/remote_task.rb, line 132 def unable_to_ssh? session = start_ssh_session session.exec('ls') session.close() false rescue Net::SSH::AuthenticationFailed, Net::SSH::ConnectionTimeout, Net::SSH::Timeout, Net::SSH::Disconnect, Net::SSH::Exception, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e p e write_error_to_results_file e.message true end
write_error_to_results_file(error)
click to toggle source
# File lib/norad_spec_runner/remote_task.rb, line 77 def write_error_to_results_file(error) File.open(results_file, "w") do |f| f.write "!! NORAD SPECS SSH ERROR !!\nError: #{error}\n" end end