beaker 4.23.2 → 4.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +8 -0
- data/.rspec +1 -0
- data/.travis.yml +2 -4
- data/CHANGELOG.md +56 -2
- data/CODEOWNERS +0 -2
- data/Rakefile +1 -4
- data/beaker.gemspec +5 -5
- data/lib/beaker/host.rb +7 -1
- data/lib/beaker/host/pswindows/exec.rb +19 -4
- data/lib/beaker/host/pswindows/file.rb +3 -3
- data/lib/beaker/host/unix/exec.rb +86 -58
- data/lib/beaker/local_connection.rb +86 -0
- data/lib/beaker/ssh_connection.rb +6 -1
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/host/pswindows/exec_spec.rb +59 -6
- data/spec/beaker/host/pswindows/file_spec.rb +23 -4
- data/spec/beaker/host/unix/exec_spec.rb +175 -113
- data/spec/beaker/host_spec.rb +7 -1
- data/spec/beaker/localhost_connection_spec.rb +106 -0
- metadata +22 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1708680196db2be9b63b514162605faa19df47fb2b8f13bfd336af02b464118
|
4
|
+
data.tar.gz: 8ea244f5c438736aa003db09aa4d6f8bd7b96f3f99988c5bad0f6302a88f598c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3811e71f7e592d024150b6470610df72dbc466cc8bdfeea50e9eb4cd57227892d6bd005e071a710516992a4dc94e5a2c0009970674a8bc0ffd998f494ada76f
|
7
|
+
data.tar.gz: cce923c69673ab3e5aea1a7022a2b94ee9e5205b700885cf389b5734f71b60d78c617d4b44214ea8a3fc93614ff1be3f4d580d61e8381afe03d01dcb462d8c15
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -20,13 +20,67 @@ The headers used in [Keep a Changelog](http://keepachangelog.com) are:
|
|
20
20
|
- Fixed - for any bug fixes.
|
21
21
|
- Security - in case of vulnerabilities.
|
22
22
|
|
23
|
-
# [Unreleased](https://github.com/puppetlabs/beaker/compare/4.
|
23
|
+
# [Unreleased](https://github.com/puppetlabs/beaker/compare/4.27.0...master)
|
24
|
+
|
25
|
+
# [4.27.1](https://github.com/puppetlabs/beaker/compare/4.27.0...4.27.1) - 09-29-2020
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
- Update net-scp requirement from "~> 1.2" to ">= 1.2, < 4.0"
|
30
|
+
|
31
|
+
### Fixed
|
32
|
+
|
33
|
+
- Handle systems going back in time after reboot
|
34
|
+
- Enhanced error handling during the reboot sequence
|
35
|
+
- Fixed time check logic during reboot
|
36
|
+
- Wrap paths around "" on pswindows
|
37
|
+
|
38
|
+
# [4.27.0](https://github.com/puppetlabs/beaker/compare/4.26.0...4.27.0) - 07-24-2020
|
39
|
+
|
40
|
+
### Changed
|
41
|
+
|
42
|
+
- Updated dependency versions and minimum Ruby version in gemspec to Ruby 2.4, which is the minimum
|
43
|
+
version Beaker will run with.
|
44
|
+
- Added Travis unit testing and disabled Jenkins integrations in preparation for transferring the
|
45
|
+
repo to Vox Pupuli
|
46
|
+
|
47
|
+
|
48
|
+
# [4.26.0](https://github.com/puppetlabs/beaker/compare/4.25.0...4.26.0)
|
49
|
+
|
50
|
+
### Changed
|
51
|
+
|
52
|
+
- Fixed deprecated SSH option handling for `verify_ssh_key` being passed into Net::SSH. #1655
|
53
|
+
|
54
|
+
### Removed
|
55
|
+
|
56
|
+
- Removed deprecated use of `paranoid` flag with Net::SSH. #1655
|
57
|
+
|
58
|
+
# [4.25.0](https://github.com/puppetlabs/beaker/compare/4.24.0...4.25.0)
|
59
|
+
|
60
|
+
### Added
|
61
|
+
|
62
|
+
- Execution of Beaker directly through ruby on localhost #1637 ([#1637](https://github.com/puppetlabs/beaker/pull/1637))
|
63
|
+
|
64
|
+
### Fixed
|
65
|
+
|
66
|
+
- Reliability improvements to the `Host#reboot` method ([#1656](https://github.com/puppetlabs/beaker/pull/1656)) ([#1659](https://github.com/puppetlabs/beaker/pull/1659))
|
67
|
+
|
68
|
+
# [4.24.0](https://github.com/puppetlabs/beaker/compare/4.23.0...4.24.0) - 2020-06-05
|
69
|
+
|
70
|
+
### Added
|
71
|
+
|
72
|
+
- Host method which ([#1651](https://github.com/puppetlabs/beaker/pull/1651))
|
73
|
+
|
74
|
+
### Fixed
|
75
|
+
|
76
|
+
- Fixed implementation for cat and file_exists? host methods for PSWindows ([#1654](https://github.com/puppetlabs/beaker/pull/1654))
|
77
|
+
- Fixed implementation for mkdir_p host method for PSWindows ([#1657](https://github.com/puppetlabs/beaker/pull/1657))
|
24
78
|
|
25
79
|
# [4.23.2](https://github.com/puppetlabs/beaker/compare/4.23.1...4.23.2)
|
26
80
|
|
27
81
|
### Fixed
|
28
82
|
|
29
|
-
- Fixed Beaker's behavior when the `strict_host_key_checking` option is
|
83
|
+
- Fixed Beaker's behavior when the `strict_host_key_checking` option is
|
30
84
|
provided in the SSH config and Net-SSH > 5 is specified. (#1652)
|
31
85
|
|
32
86
|
# [4.23.1](https://github.com/puppetlabs/beaker/compare/4.23.0...4.23.1)
|
data/CODEOWNERS
CHANGED
data/Rakefile
CHANGED
@@ -26,10 +26,7 @@ task :history do
|
|
26
26
|
Rake::Task['history:gen'].invoke
|
27
27
|
end
|
28
28
|
|
29
|
-
task :
|
30
|
-
Rake::Task['yard'].invoke if !Beaker::Shared::Semvar.version_is_less(RUBY_VERSION, '2.0.0')
|
31
|
-
Rake::Task['spec'].invoke
|
32
|
-
end
|
29
|
+
task travis: [:yard, :test]
|
33
30
|
|
34
31
|
module HarnessOptions
|
35
32
|
defaults = {
|
data/beaker.gemspec
CHANGED
@@ -18,14 +18,14 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.required_ruby_version = Gem::Requirement.new('>= 2.
|
21
|
+
s.required_ruby_version = Gem::Requirement.new('>= 2.4')
|
22
22
|
|
23
23
|
# Testing dependencies
|
24
24
|
s.add_development_dependency 'rspec', '~> 3.0'
|
25
25
|
s.add_development_dependency 'rspec-its'
|
26
|
-
s.add_development_dependency 'fakefs', '~>
|
26
|
+
s.add_development_dependency 'fakefs', '~> 1.2', '< 1.3.0'
|
27
27
|
s.add_development_dependency 'simplecov'
|
28
|
-
s.add_development_dependency 'rake', '~>
|
28
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
29
29
|
|
30
30
|
# Provisioner dependencies - needed for acceptance tests
|
31
31
|
# TODO: figure out how to remove these
|
@@ -39,13 +39,13 @@ Gem::Specification.new do |s|
|
|
39
39
|
# Run time dependencies
|
40
40
|
s.add_runtime_dependency 'minitest', '~> 5.4'
|
41
41
|
s.add_runtime_dependency 'minitar', '~> 0.6'
|
42
|
-
s.add_runtime_dependency 'pry-byebug', '~> 3.
|
42
|
+
s.add_runtime_dependency 'pry-byebug', '~> 3.9'
|
43
43
|
# pry-byebug can have issues with native readline libs so add rb-readline
|
44
44
|
s.add_runtime_dependency 'rb-readline', '~> 0.5.3'
|
45
45
|
|
46
46
|
s.add_runtime_dependency 'hocon', '~> 1.0'
|
47
47
|
s.add_runtime_dependency 'net-ssh', '>= 5.0'
|
48
|
-
s.add_runtime_dependency 'net-scp', '
|
48
|
+
s.add_runtime_dependency 'net-scp', '>= 1.2', '< 4.0'
|
49
49
|
s.add_runtime_dependency 'inifile', '~> 3.0'
|
50
50
|
|
51
51
|
s.add_runtime_dependency 'rsync', '~> 1.0.9'
|
data/lib/beaker/host.rb
CHANGED
@@ -6,7 +6,7 @@ require 'rsync'
|
|
6
6
|
require 'beaker/dsl/helpers'
|
7
7
|
require 'beaker/dsl/patterns'
|
8
8
|
|
9
|
-
[ 'command', 'ssh_connection'].each do |lib|
|
9
|
+
[ 'command', 'ssh_connection', 'local_connection' ].each do |lib|
|
10
10
|
require "beaker/#{lib}"
|
11
11
|
end
|
12
12
|
|
@@ -19,6 +19,7 @@ module Beaker
|
|
19
19
|
|
20
20
|
class CommandFailure < StandardError; end
|
21
21
|
class RebootFailure < CommandFailure; end
|
22
|
+
class RebootWarning < StandardError; end
|
22
23
|
|
23
24
|
# This class provides array syntax for using puppet --configprint on a host
|
24
25
|
class PuppetConfigReader
|
@@ -294,6 +295,11 @@ module Beaker
|
|
294
295
|
|
295
296
|
def connection
|
296
297
|
# create new connection object if necessary
|
298
|
+
if self['hypervisor'] == 'none' && @name == 'localhost'
|
299
|
+
@connection ||= LocalConnection.connect( { :ssh_env_file => self['ssh_env_file'], :logger => @logger })
|
300
|
+
return @connection
|
301
|
+
end
|
302
|
+
|
297
303
|
@connection ||= SshConnection.connect( { :ip => self['ip'], :vmhostname => self['vmhostname'], :hostname => @name },
|
298
304
|
self['user'],
|
299
305
|
self['ssh'], { :logger => @logger, :ssh_connection_preference => self[:ssh_connection_preference]} )
|
@@ -22,7 +22,7 @@ module PSWindows::Exec
|
|
22
22
|
def rm_rf path
|
23
23
|
# ensure that we have the right slashes for windows
|
24
24
|
path = path.gsub(/\//, '\\')
|
25
|
-
execute(
|
25
|
+
execute(%(del /s /q "#{path}"))
|
26
26
|
end
|
27
27
|
|
28
28
|
# Move the origin to destination. The destination is removed prior to moving.
|
@@ -104,9 +104,9 @@ module PSWindows::Exec
|
|
104
104
|
# @param [String] dir The directory structure to create on the host
|
105
105
|
# @return [Boolean] True, if directory construction succeeded, otherwise False
|
106
106
|
def mkdir_p dir
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
normalized_path = dir.gsub('/','\\')
|
108
|
+
result = exec(powershell("New-Item -Path '#{normalized_path}' -ItemType 'directory'"),
|
109
|
+
:acceptable_exit_codes => [0, 1])
|
110
110
|
result.exit_code == 0
|
111
111
|
end
|
112
112
|
|
@@ -237,4 +237,19 @@ module PSWindows::Exec
|
|
237
237
|
end
|
238
238
|
end
|
239
239
|
|
240
|
+
#First path it finds for the command executable
|
241
|
+
#@param [String] command The command executable to search for
|
242
|
+
#
|
243
|
+
# @return [String] Path to the searched executable or empty string if not found
|
244
|
+
#
|
245
|
+
#@example
|
246
|
+
# host.which('ruby')
|
247
|
+
def which(command)
|
248
|
+
where_command = "cmd /C \"where #{command}\""
|
249
|
+
|
250
|
+
result = execute(where_command, :accept_all_exit_codes => true)
|
251
|
+
return '' if result.empty?
|
252
|
+
|
253
|
+
result
|
254
|
+
end
|
240
255
|
end
|
@@ -21,11 +21,11 @@ module PSWindows::File
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def cat(path)
|
24
|
-
exec(powershell("type #{path}"))
|
24
|
+
exec(powershell("type #{path}")).stdout
|
25
25
|
end
|
26
26
|
|
27
27
|
def file_exist?(path)
|
28
|
-
result = exec(Beaker::Command.new("if exist #{path} echo true"), :
|
29
|
-
result.stdout
|
28
|
+
result = exec(Beaker::Command.new("if exist #{path} echo true"), accept_all_exit_codes: true)
|
29
|
+
result.stdout.strip == 'true'
|
30
30
|
end
|
31
31
|
end
|
@@ -14,91 +14,104 @@ module Unix::Exec
|
|
14
14
|
def reboot(wait_time=10, max_connection_tries=9, uptime_retries=18)
|
15
15
|
require 'time'
|
16
16
|
|
17
|
+
attempts = 0
|
18
|
+
|
19
|
+
# Some systems don't support 'last -F reboot' but it has second granularity
|
20
|
+
boot_time_cmd = 'last -F reboot || who -b'
|
21
|
+
|
22
|
+
# Try to match all of the common formats for 'last' and 'who'
|
23
|
+
current_year = Time.now.strftime("%Y")
|
24
|
+
boot_time_regex = Regexp.new(%{((?:#{(Date::ABBR_DAYNAMES + Date::ABBR_MONTHNAMES).compact.join('|')}|#{current_year}).+?(\\d+:\\d+)+?(?::(\\d+).+?#{current_year})?)})
|
25
|
+
|
26
|
+
original_boot_time_str = nil
|
27
|
+
original_boot_time_line = nil
|
17
28
|
begin
|
18
|
-
|
29
|
+
attempts += 1
|
30
|
+
# Number of seconds to sleep before rebooting.
|
31
|
+
reboot_sleep = 1
|
32
|
+
|
33
|
+
original_boot_time_str = exec(Beaker::Command.new(boot_time_cmd), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
|
19
34
|
original_boot_time_line = original_boot_time_str.lines.grep(/boot/).first
|
20
35
|
|
21
|
-
raise Beaker::Host::
|
36
|
+
raise Beaker::Host::RebootWarning, "Could not find system boot time using '#{boot_time_cmd}': '#{original_boot_time_str}'" unless original_boot_time_line
|
37
|
+
|
38
|
+
original_boot_time_matches = original_boot_time_line.scan(boot_time_regex).last
|
39
|
+
|
40
|
+
raise Beaker::Host::RebootWarning, "Found no valid times in '#{original_boot_time_line}'" unless original_boot_time_matches
|
41
|
+
|
42
|
+
original_boot_time = Time.parse(original_boot_time_matches.first)
|
43
|
+
|
44
|
+
unless original_boot_time_matches.last
|
45
|
+
reboot_sleep = (61 - Time.now.strftime("%S").to_i)
|
46
|
+
end
|
47
|
+
|
48
|
+
@logger.notify("Sleeping #{reboot_sleep} seconds before rebooting")
|
22
49
|
|
23
|
-
|
50
|
+
sleep(reboot_sleep)
|
24
51
|
|
25
52
|
exec(Beaker::Command.new('/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now'), :expect_connection_failure => true)
|
26
|
-
rescue Beaker::Host::CommandFailure => e
|
27
|
-
raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
|
28
|
-
rescue RuntimeError => e
|
29
|
-
raise Beaker::Host::RebootFailure, "Unexpected exception in reboot: #{e.message}"
|
30
53
|
rescue ArgumentError => e
|
31
54
|
raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
|
55
|
+
rescue Beaker::Host::RebootWarning => e
|
56
|
+
raise if attempts > uptime_retries
|
57
|
+
@logger.warn(e.message)
|
58
|
+
@logger.warn("Retrying #{uptime_retries - attempts} more times.")
|
59
|
+
retry
|
60
|
+
rescue StandardError => e
|
61
|
+
raise if attempts > uptime_retries
|
62
|
+
@logger.warn("Unexpected Exception: #{e.message}")
|
63
|
+
@logger.warn("Retrying #{uptime_retries - attempts} more times.")
|
64
|
+
@logger.warn(e.backtrace[0,3].join("\n"))
|
65
|
+
@logger.debug(e.backtrace.join("\n"))
|
66
|
+
retry
|
32
67
|
end
|
33
68
|
|
34
69
|
attempts = 0
|
35
70
|
begin
|
71
|
+
attempts += 1
|
72
|
+
|
36
73
|
# give the host a little time to shutdown
|
37
74
|
@logger.debug("Waiting #{wait_time} for host to shut down.")
|
38
75
|
sleep wait_time
|
39
76
|
|
40
|
-
|
41
|
-
|
77
|
+
# Accept all exit codes because this may fail due to the parallel nature of systemd
|
78
|
+
current_boot_time_str = exec(Beaker::Command.new(boot_time_cmd), {:max_connection_tries => max_connection_tries, :silent => true, :accept_all_exit_codes => true}).stdout
|
79
|
+
current_boot_time_line = current_boot_time_str.lines.grep(/boot/).first
|
80
|
+
|
81
|
+
raise Beaker::Host::RebootWarning, "Could not find system boot time using '#{boot_time_cmd}': '#{current_boot_time_str}'" unless current_boot_time_line
|
82
|
+
|
83
|
+
current_boot_time_matches = current_boot_time_line.scan(boot_time_regex).last
|
84
|
+
|
85
|
+
raise Beaker::Host::RebootWarning, "Found no valid times in '#{current_boot_time_line}'" unless current_boot_time_matches
|
86
|
+
|
87
|
+
current_boot_time = Time.parse(current_boot_time_matches.first)
|
42
88
|
|
43
89
|
@logger.debug("Original Boot Time: #{original_boot_time}")
|
44
90
|
@logger.debug("Current Boot Time: #{current_boot_time}")
|
45
91
|
|
46
|
-
|
92
|
+
# If this is *exactly* the same then there is really no good way to detect a reboot
|
93
|
+
if current_boot_time == original_boot_time
|
47
94
|
raise Beaker::Host::RebootFailure, "Boot time did not reset. Reboot appears to have failed."
|
48
95
|
end
|
49
|
-
rescue Beaker::Host::RebootFailure => e
|
50
|
-
attempts += 1
|
51
|
-
if attempts < uptime_retries
|
52
|
-
@logger.debug("Boot time did not reset. Will retry #{uptime_retries - attempts} more times.")
|
53
|
-
retry
|
54
|
-
else
|
55
|
-
raise
|
56
|
-
end
|
57
|
-
rescue Beaker::Host::CommandFailure => e
|
58
|
-
raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
|
59
|
-
rescue RuntimeError => e
|
60
|
-
raise Beaker::Host::RebootFailure, "Unexpected exception in reboot: #{e.message}"
|
61
96
|
rescue ArgumentError => e
|
62
97
|
raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
|
98
|
+
rescue Beaker::Host::RebootFailure => e
|
99
|
+
raise
|
100
|
+
rescue Beaker::Host::RebootWarning => e
|
101
|
+
raise if attempts > uptime_retries
|
102
|
+
@logger.warn(e.message)
|
103
|
+
@logger.warn("Retrying #{uptime_retries - attempts} more times.")
|
104
|
+
retry
|
105
|
+
rescue StandardError => e
|
106
|
+
raise if attempts > uptime_retries
|
107
|
+
@logger.warn("Unexpected Exception: #{e.message}")
|
108
|
+
@logger.warn("Retrying #{uptime_retries - attempts} more times.")
|
109
|
+
@logger.warn(e.backtrace[0,3].join("\n"))
|
110
|
+
@logger.debug(e.backtrace.join("\n"))
|
111
|
+
retry
|
63
112
|
end
|
64
113
|
end
|
65
114
|
|
66
|
-
def uptime_int(uptime_str)
|
67
|
-
time_array = uptime_str.split(", ")
|
68
|
-
accumulated_mins = 0
|
69
|
-
time_array.each do |time_segment|
|
70
|
-
value, unit = time_segment.split
|
71
|
-
if unit.nil?
|
72
|
-
# 20:47 case: hours & mins
|
73
|
-
hours, mins = value.split(":")
|
74
|
-
accumulated_mins += (hours.to_i * 60 + mins.to_i)
|
75
|
-
elsif unit =~ /day(s)?/
|
76
|
-
accumulated_mins += (value.to_i * 1440) # 60 * 24 = 1440
|
77
|
-
elsif unit =~ /min(s)?/
|
78
|
-
accumulated_mins += value.to_i
|
79
|
-
else
|
80
|
-
raise ArgumentError, "can't parse uptime segment: #{time_segment}"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
accumulated_mins
|
85
|
-
end
|
86
|
-
|
87
|
-
def parse_uptime(uptime)
|
88
|
-
# get String from up to users
|
89
|
-
# eg 19:52 up 14 mins, 2 users, load averages: 2.95 4.19 4.31
|
90
|
-
# 8:03 up 52 days, 20:47, 3 users, load averages: 1.36 1.42 1.40
|
91
|
-
# 22:19 up 54 days, 1 min, 4 users, load averages: 2.08 2.06 2.27
|
92
|
-
regexp = /.*up (.*)[[:space:]]+[[:digit:]]+ user.*/
|
93
|
-
result = uptime.match regexp
|
94
|
-
if self['platform'] =~ /solaris-/ && result[1].empty?
|
95
|
-
return "0 min"
|
96
|
-
end
|
97
|
-
raise "Couldn't parse uptime: #{uptime}" if result.nil?
|
98
|
-
|
99
|
-
result[1].strip.chomp(",")
|
100
|
-
end
|
101
|
-
|
102
115
|
def echo(msg, abs=true)
|
103
116
|
(abs ? '/bin/echo' : 'echo') + " #{msg}"
|
104
117
|
end
|
@@ -435,4 +448,19 @@ module Unix::Exec
|
|
435
448
|
true
|
436
449
|
end
|
437
450
|
|
451
|
+
#First path it finds for the command executable
|
452
|
+
#@param [String] command The command executable to search for
|
453
|
+
#
|
454
|
+
# @return [String] Path to the searched executable or empty string if not found
|
455
|
+
#
|
456
|
+
#@example
|
457
|
+
# host.which('ruby')
|
458
|
+
def which(command)
|
459
|
+
which_command = "which #{command}"
|
460
|
+
|
461
|
+
result = execute(which_command, :accept_all_exit_codes => true)
|
462
|
+
return '' if result.empty?
|
463
|
+
|
464
|
+
result
|
465
|
+
end
|
438
466
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Beaker
|
4
|
+
class LocalConnection
|
5
|
+
|
6
|
+
attr_accessor :logger, :hostname, :ip
|
7
|
+
|
8
|
+
def initialize options = {}
|
9
|
+
@logger = options[:logger]
|
10
|
+
@ssh_env_file = File.expand_path(options[:ssh_env_file])
|
11
|
+
@hostname = 'localhost'
|
12
|
+
@ip = '127.0.0.1'
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.connect options = {}
|
17
|
+
connection = new options
|
18
|
+
connection.connect
|
19
|
+
connection
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect options = {}
|
23
|
+
@logger.debug "Local connection, no connection to start"
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
@logger.debug "Local connection, no connection to close"
|
28
|
+
end
|
29
|
+
|
30
|
+
def with_env(env)
|
31
|
+
backup = ENV.to_hash
|
32
|
+
ENV.replace(env)
|
33
|
+
yield
|
34
|
+
ensure
|
35
|
+
ENV.replace(backup)
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute command, options = {}, stdout_callback = nil, stderr_callback = stdout_callback
|
39
|
+
result = Result.new(@hostname, command)
|
40
|
+
envs = {}
|
41
|
+
if File.readable?(@ssh_env_file)
|
42
|
+
File.foreach(@ssh_env_file) do |line|
|
43
|
+
key, value = line.split('=')
|
44
|
+
envs[key] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
begin
|
49
|
+
clean_env = ENV.reject{ |k| k =~ /^BUNDLE|^RUBY|^GEM/ }
|
50
|
+
|
51
|
+
with_env(clean_env) do
|
52
|
+
std_out, std_err, status = Open3.capture3(envs, command)
|
53
|
+
result.stdout << std_out
|
54
|
+
result.stderr << std_err
|
55
|
+
result.exit_code = status.exitstatus
|
56
|
+
end
|
57
|
+
rescue => e
|
58
|
+
result.stderr << e.inspect
|
59
|
+
result.exit_code = 1
|
60
|
+
end
|
61
|
+
|
62
|
+
result.finalize!
|
63
|
+
@logger.last_result = result
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
def scp_to(source, target, _options = {})
|
68
|
+
|
69
|
+
result = Result.new(@hostname, [source, target])
|
70
|
+
begin
|
71
|
+
FileUtils.cp_r source, target
|
72
|
+
rescue Errno::ENOENT => e
|
73
|
+
@logger.warn "#{e.class} error in cp'ing. Forcing the connection to close, which should " \
|
74
|
+
"raise an error."
|
75
|
+
end
|
76
|
+
|
77
|
+
result.stdout << " CP'ed file #{source} to #{target}"
|
78
|
+
result.exit_code = 0
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
def scp_from(source, target, options = {})
|
83
|
+
scp_to(target, source, options)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|