Module: Beaker::DSL::Helpers::HostHelpers
- Included in:
- Beaker::DSL::Helpers
- Defined in:
- lib/beaker/dsl/helpers/host_helpers.rb
Overview
Methods that help you interact and manage the state of your Beaker SUTs, these methods do not require puppet to be installed to execute correctly
Instance Method Summary collapse
-
#add_system32_hosts_entry(host, opts = {}) ⇒ Object
Configure a host entry on the give host @example: will add a host entry for forge.puppetlabs.com add_system32_hosts_entry(host, { :ip => ‘23.251.154.122’, :name => ‘forge.puppetlabs.com’ }).
-
#archive_file_from(host, from_path, opts = {}, archive_root = 'archive/sut-files', archive_name = 'sut-files.tgz') ⇒ Result
Copy a remote file to the local system and save it under a directory meant for storing SUT files to be viewed in the event of test failures.
-
#backup_the_file(host, current_dir, new_dir, filename = 'puppet.conf') ⇒ String?
Back up the given file in the current_dir to the new_dir.
-
#check_for_package(host, package_name) ⇒ Boolean
Check to see if a package is installed on a remote host.
-
#create_remote_file(hosts, file_path, file_content, opts = {}) ⇒ Result
Create a remote file out of a string.
-
#curl_on(host, cmd, opts = {}, &block) ⇒ Object
Run a curl command on the provided host(s).
- #curl_with_retries(_desc, host, url, desired_exit_codes, max_retries = 60, retry_interval = 1) ⇒ Object
-
#directory_exists_on(host, dir_path) ⇒ Boolean
Check whether a directory exists on the host.
-
#echo_on(hosts, val) ⇒ String, Array<String> The echo'ed value(s) returned by the host(s)
‘echo’ the provided value on the given host(s).
-
#execute_powershell_script_on(hosts, powershell_script, opts = {}) ⇒ Result
Execute a powershell script from file, remote file created from provided string.
-
#file_contents_on(host, file_path) ⇒ String
Get the contents of a file on the host.
-
#file_exists_on(host, file_path) ⇒ Boolean
Check whether a file exists on the host.
-
#install_package(host, package_name, package_version = nil) ⇒ Result
Install a package on a host.
-
#link_exists_on(host, link_path) ⇒ Boolean
Check whether a symlink exists on the host.
-
#on(host, command, opts = {}, &block) ⇒ Result
The primary method for executing commands on some set of hosts.
-
#retry_on(host, command, opts = {}, &block) ⇒ Result
This command will execute repeatedly until success or it runs out with an error.
-
#rsync_to(host, from_path, to_path, opts = {}) ⇒ Result
Move a local file or directory to a remote host using rsync.
-
#run_script(script, opts = {}, &block) ⇒ Object
Move a local script to default host and execute it.
-
#run_script_on(host, script, opts = {}, &block) ⇒ Result
Move a local script to a remote host and execute it.
-
#scp_from(host, from_path, to_path, opts = {}) ⇒ Result
Move a file from a remote to a local path.
-
#scp_to(host, from_path, to_path, opts = {}) ⇒ Result
Move a local file to a remote host using scp.
-
#shell(command, opts = {}, &block) ⇒ Result
The method for executing commands on the default host.
-
#uninstall_package(host, package_name) ⇒ Result
Uninstall a package on a host.
-
#upgrade_package(host, package_name) ⇒ Result
Upgrade a package on a host.
-
#win_ads_path(file_path) ⇒ Hash
Return a Hash with the Alternate Data Stream (ADS) name as well as the base file path.
Instance Method Details
#add_system32_hosts_entry(host, opts = {}) ⇒ Object
Configure a host entry on the give host @example: will add a host entry for forge.puppetlabs.com
add_system32_hosts_entry(host, { :ip => '23.251.154.122', :name => 'forge.puppetlabs.com' })
374 375 376 377 378 379 380 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 374 def add_system32_hosts_entry(host, opts = {}) raise "nothing to do for #{host.name} on #{host['platform']}" unless host.is_powershell? hosts_file = 'C:\Windows\System32\Drivers\etc\hosts' host_entry = "#{opts['ip']}`t`t#{opts['name']}" on host, powershell("\$text = \\\"#{host_entry}\\\"; Add-Content -path '#{hosts_file}' -value \$text") end |
#archive_file_from(host, from_path, opts = {}, archive_root = 'archive/sut-files', archive_name = 'sut-files.tgz') ⇒ Result
Copy a remote file to the local system and save it under a directory meant for storing SUT files to be viewed in the event of test failures.
Files are stored locally with the following structure:
./<archive_root>/<hostname>/<from_path>
This can be used during the post-suite phase to persist relevant log files from the SUTs so they can available with the test results (without having to preserve the SUT host and SSH in after the fact).
Example
Archive the Puppet Server log file from the master ('abc123'),
and archive the Puppet Agent log file from the agent ('xyz098'):
archive_file_from(master, '/var/log/puppetlabs/puppetserver.log')
archive_file_from(agent, '/var/log/puppetlabs/puppetagent.log')
Results in the following files on the test runner:
archive/sut-files/abc123/var/log/puppetlabs/puppetserver.log
archive/sut-files/xyz098/var/log/puppetlabs/puppetagent.log
228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 228 def archive_file_from(host, from_path, opts = {}, archive_root = 'archive/sut-files', archive_name = 'sut-files.tgz') require 'minitar' filedir = File.dirname(from_path) targetdir = File.join(archive_root, host.hostname, filedir) # full path to check for existance later filename = "#{targetdir}/" + File.basename(from_path) FileUtils.mkdir_p(targetdir) scp_from(host, from_path, targetdir, opts) # scp_from does succeed on a non-existant file, checking if the file/folder actually exists raise IOError, "No such file or directory - #{filename}" if not File.exist?(filename) create_tarball(archive_root, archive_name) end |
#backup_the_file(host, current_dir, new_dir, filename = 'puppet.conf') ⇒ String?
Back up the given file in the current_dir to the new_dir
391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 391 def backup_the_file host, current_dir, new_dir, filename = 'puppet.conf' old_location = current_dir + '/' + filename new_location = new_dir + '/' + filename + '.bak' if host.file_exist? old_location host.exec(Command.new("cp #{old_location} #{new_location}")) return new_location else logger.warn "Could not backup file '#{old_location}': no such file" nil end end |
#check_for_package(host, package_name) ⇒ Boolean
Check to see if a package is installed on a remote host
355 356 357 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 355 def check_for_package host, package_name host.check_for_package package_name end |
#create_remote_file(hosts, file_path, file_content, opts = {}) ⇒ Result
This method uses Tempfile in Ruby’s STDLIB as well as #scp_to.
Create a remote file out of a string
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 262 def create_remote_file(hosts, file_path, file_content, opts = {}) Tempfile.open 'beaker' do |tempfile| File.open(tempfile.path, 'w') { |file| file.puts file_content } opts[:protocol] ||= 'scp' case opts[:protocol] when 'scp' scp_to hosts, tempfile.path, file_path, opts when 'rsync' rsync_to hosts, tempfile.path, file_path, opts else logger.debug "Unsupported transfer protocol, returning nil" nil end end end |
#curl_on(host, cmd, opts = {}, &block) ⇒ Object
Run a curl command on the provided host(s)
518 519 520 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 518 def curl_on(host, cmd, opts = {}, &block) on host, "curl --tlsv1 %s" % cmd, opts, &block end |
#curl_with_retries(_desc, host, url, desired_exit_codes, max_retries = 60, retry_interval = 1) ⇒ Object
522 523 524 525 526 527 528 529 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 522 def curl_with_retries(_desc, host, url, desired_exit_codes, max_retries = 60, retry_interval = 1) opts = { :desired_exit_codes => desired_exit_codes, :max_retries => max_retries, :retry_interval => retry_interval, } retry_on(host, "curl -m 1 #{url}", opts) end |
#directory_exists_on(host, dir_path) ⇒ Boolean
Check whether a directory exists on the host
457 458 459 460 461 462 463 464 465 466 467 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 457 def directory_exists_on(host, dir_path) if host[:platform].include?('windows') dir_path = "#{dir_path}\\" unless (dir_path[-1].chr == '\\') command = Command.new(%{IF exist "#{dir_path}" ( exit 0 ) ELSE ( exit 1 )}, [], { :cmdexe => true }) else command = Command.new(%(test -d "#{dir_path}"), []) end return on(host, command, { :accept_all_exit_codes => true }).exit_code.zero? end |
#echo_on(hosts, val) ⇒ String, Array<String> The echo'ed value(s) returned by the host(s)
‘echo’ the provided value on the given host(s)
621 622 623 624 625 626 627 628 629 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 621 def echo_on hosts, val block_on hosts do |host| if host.is_powershell? host.exec(Command.new("echo #{val}")).stdout.chomp else host.exec(Command.new("echo \"#{val}\"")).stdout.chomp end end end |
#execute_powershell_script_on(hosts, powershell_script, opts = {}) ⇒ Result
This method uses Tempfile in Ruby’s STDLIB as well as #create_remote_file.
Execute a powershell script from file, remote file created from provided string
290 291 292 293 294 295 296 297 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 290 def execute_powershell_script_on(hosts, powershell_script, opts = {}) block_on hosts, opts do |host| script_path = "beaker_powershell_script_#{Time.now.to_i}.ps1" create_remote_file(host, script_path, powershell_script, opts) native_path = script_path.tr('/', "\\") on host, powershell("", { "File" => native_path }), opts end end |
#file_contents_on(host, file_path) ⇒ String
Get the contents of a file on the host
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 488 def file_contents_on(host, file_path) file_contents = nil split_path = win_ads_path(file_path) if file_exists_on(host, split_path[:path]) if host[:platform].include?('windows') file_path.tr!('/', '\\') command = %{Get-Content -Raw -Path #{file_path}} command += %{ -Stream #{split_path[:ads]}} if split_path[:ads] file_contents = on(host, powershell(command))&.stdout&.strip else file_contents = on(host, %(cat "#{file_path}"))&.stdout&.strip end else logger.warn("File '#{file_path}' on '#{host} does not exist") end return file_contents end |
#file_exists_on(host, file_path) ⇒ Boolean
Check whether a file exists on the host
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 432 def file_exists_on(host, file_path) if host[:platform].include?('windows') command = %(Test-Path #{file_path}) if file_path.include?(':') split_path = win_ads_path(file_path) command = %(Test-Path #{split_path[:path]}) command += %( -AND Get-Item -path #{split_path[:path]} -stream #{split_path[:ads]}) if split_path[:ads] end command = powershell(command) else command = %(test -f "#{file_path}") end return on(host, command, { :accept_all_exit_codes => true }).exit_code.zero? end |
#install_package(host, package_name, package_version = nil) ⇒ Result
Install a package on a host
335 336 337 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 335 def install_package host, package_name, package_version = nil host.install_package package_name, '', package_version end |
#link_exists_on(host, link_path) ⇒ Boolean
Check whether a symlink exists on the host
475 476 477 478 479 480 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 475 def link_exists_on(host, link_path) # Links are weird on windows, fall back to seeing if the file exists return file_exists_on(host, link_path) if host[:platform].include?('windows') return on(host, Command.new(%(test -L "#{link_path}"), accept_all_exit_codes: true)).exit_code.zero? end |
#on(host, command, opts = {}, &block) ⇒ Result
The primary method for executing commands on some set of hosts.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 61 def on(host, command, opts = {}, &block) block_on host, opts do |host| if command.is_a? String cmd_opts = {} # add any additional environment variables to the command cmd_opts['ENV'] = opts[:environment] if opts[:environment] command_object = Command.new(command.to_s, [], cmd_opts) elsif command.is_a? Command if opts[:environment] command_object = command.clone command_object.environment = opts[:environment] else command_object = command end else msg = "DSL method `on` can only be called with a String or Beaker::Command" msg << " object as the command parameter, not #{command.class}." raise ArgumentError, msg end result = host.exec(command_object, opts) # Also, let additional checking be performed by the caller. if block case block.arity # block with arity of 0, just hand back yourself when 0 yield self # block with arity of 1 or greater, hand back the result object else yield result end end result end end |
#retry_on(host, command, opts = {}, &block) ⇒ Result
This command will execute repeatedly until success or it runs out with an error
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 550 def retry_on(host, command, opts = {}, &block) option_exit_codes = opts[:desired_exit_codes] option_max_retries = opts[:max_retries].to_i option_retry_interval = opts[:retry_interval].to_f desired_exit_codes = option_exit_codes ? [option_exit_codes].flatten : [0] desired_exit_codes = [0] if desired_exit_codes.empty? max_retries = option_max_retries == 0 ? 60 : option_max_retries # nil & "" both return 0 retry_interval = option_retry_interval == 0 ? 1 : option_retry_interval verbose = true.to_s == opts[:verbose] log_prefix = host.log_prefix logger.debug "\n#{log_prefix} #{Time.new.strftime('%H:%M:%S')}$ #{command}" logger.debug " Trying command #{max_retries} times." logger.debug ".", add_newline = false result = on host, command, { :accept_all_exit_codes => true, :silent => !verbose }, &block num_retries = 0 until desired_exit_codes.include?(result.exit_code) sleep retry_interval result = on host, command, { :accept_all_exit_codes => true, :silent => !verbose }, &block num_retries += 1 logger.debug ".", add_newline = false if (num_retries > max_retries) logger.debug " Command \`#{command}\` failed." fail("Command \`#{command}\` failed.") end end logger.debug "\n#{log_prefix} #{Time.new.strftime('%H:%M:%S')}$ #{command} ostensibly successful." result end |
#rsync_to(host, from_path, to_path, opts = {}) ⇒ Result
rsync is required on the local host.
Move a local file or directory to a remote host using rsync
183 184 185 186 187 188 189 190 191 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 183 def rsync_to host, from_path, to_path, opts = {} block_on host do |host| if host['platform'].include?('windows') && to_path.match('`cygpath') result = host.echo "#{to_path}" to_path = result.raw_output.chomp end host.do_rsync_to(from_path, to_path, opts) end end |
#run_script(script, opts = {}, &block) ⇒ Object
Move a local script to default host and execute it
325 326 327 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 325 def run_script(script, opts = {}, &block) run_script_on(default, script, opts, &block) end |
#run_script_on(host, script, opts = {}, &block) ⇒ Result
310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 310 def run_script_on(host, script, opts = {}, &block) # this is unsafe as it uses the File::SEPARATOR will be set to that # of the coordinator node. This works for us because we use cygwin # which will properly convert the paths. Otherwise this would not # work for running tests on a windows machine when the coordinator # that the harness is running on is *nix. We should use # {Beaker::Host#temp_path} instead. TODO remote_path = File.join("", "tmp", File.basename(script)) scp_to host, script, remote_path on host, remote_path, opts, &block end |
#scp_from(host, from_path, to_path, opts = {}) ⇒ Result
If using Host for the hosts scp is not required on the system as it uses Ruby’s net/scp library. The net-scp gem however is required (and specified in the gemspec).
Move a file from a remote to a local path
138 139 140 141 142 143 144 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 138 def scp_from host, from_path, to_path, opts = {} block_on host do |host| result = host.do_scp_from(from_path, to_path, opts) result.log logger result end end |
#scp_to(host, from_path, to_path, opts = {}) ⇒ Result
If using Host for the hosts scp is not required on the system as it uses Ruby’s net/scp library. The net-scp gem however is required (and specified in the gemspec. When using SCP with Windows it will now auto expand path when using ‘cygpath instead of failing or requiring full path
Move a local file to a remote host using scp
161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 161 def scp_to host, from_path, to_path, opts = {} block_on host do |host| if host['platform'].include?('windows') && to_path.match('`cygpath') result = on host, "echo #{to_path}" to_path = result.raw_output.chomp end result = host.do_scp_to(from_path, to_path, opts) result.log logger result end end |
#shell(command, opts = {}, &block) ⇒ Result
The method for executing commands on the default host
121 122 123 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 121 def shell(command, opts = {}, &block) on(default, command, opts, &block) end |
#uninstall_package(host, package_name) ⇒ Result
Uninstall a package on a host
345 346 347 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 345 def uninstall_package host, package_name host.uninstall_package package_name end |
#upgrade_package(host, package_name) ⇒ Result
Upgrade a package on a host. The package must already be installed
365 366 367 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 365 def upgrade_package host, package_name host.upgrade_package package_name end |
#win_ads_path(file_path) ⇒ Hash
Return a Hash with the Alternate Data Stream (ADS) name as well as the base file path
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/beaker/dsl/helpers/host_helpers.rb', line 410 def win_ads_path(file_path) ads_path = { path: file_path, ads: nil, } split_path = file_path.split(':') if split_path.size > 2 ads_path[:ads] = split_path.pop ads_path[:path] = split_path.join(':') end return ads_path end |