sshake 1.0.0 → 1.0.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 +5 -5
- data/lib/sshake.rb +4 -0
- data/lib/sshake/base_session.rb +114 -0
- data/lib/sshake/error.rb +1 -1
- data/lib/sshake/execution_options.rb +7 -0
- data/lib/sshake/execution_options_dsl.rb +12 -2
- data/lib/sshake/mock/command.rb +36 -0
- data/lib/sshake/mock/command_set.rb +28 -0
- data/lib/sshake/mock/environment.rb +24 -0
- data/lib/sshake/mock/executed_command.rb +17 -0
- data/lib/sshake/mock/session.rb +101 -0
- data/lib/sshake/mock/unsupported_command_error.rb +17 -0
- data/lib/sshake/response.rb +7 -0
- data/lib/sshake/session.rb +56 -69
- data/lib/sshake/version.rb +1 -1
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 708fa3da7960099e94421e102ad22c9b8243a586b5bc6b978b6a8083857f4a68
|
4
|
+
data.tar.gz: d6711b1debc1e0dacd0d1f0880e3508f3ce939e142036d647e6471ce920e2011
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70f79029d3b42745a2661ea1627e3f8cd73201d50d6bf00abdb983e02663077fb3df4667ddc4d5dcf5920f4cfac2fb7b0927df7a7a8382a8354d65cd7f90c5ad
|
7
|
+
data.tar.gz: 60cdd9feff7600fecc5bec047eef5d7bd513baf9fcb4ba280b4c1f2e964e9e5e81c0a1828d7cfabe32c30216ea3b5893eb6cad4a1941fd7e21cffec6fa724a77
|
data/lib/sshake.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'sshake/logger'
|
3
|
+
require 'sshake/execution_options'
|
4
|
+
|
5
|
+
module SSHake
|
6
|
+
class BaseSession
|
7
|
+
# A logger for this session
|
8
|
+
#
|
9
|
+
# @return [Logger, nil]
|
10
|
+
attr_accessor :logger
|
11
|
+
|
12
|
+
# An ID for this session
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
attr_reader :id
|
16
|
+
|
17
|
+
# Specify the default behaviour for raising erors
|
18
|
+
#
|
19
|
+
# @return [Boolean]
|
20
|
+
attr_accessor :raise_on_error
|
21
|
+
|
22
|
+
def initialize(*args)
|
23
|
+
@id = SecureRandom.hex(4)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Connect to the SSH server
|
27
|
+
#
|
28
|
+
# @return [void]
|
29
|
+
def connect
|
30
|
+
raise "Override #connect in sub-sessions"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is there an established SSH connection
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
def connected?
|
37
|
+
raise "Override #connected? in sub-sessions"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Disconnect the underlying SSH connection
|
41
|
+
#
|
42
|
+
# @return [void]
|
43
|
+
def disconnect
|
44
|
+
raise "Override #disconnect in sub-sessions"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Kill the underlying connection
|
48
|
+
def kill!
|
49
|
+
raise "Override #kill! in sub-sessions"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Execute a command
|
53
|
+
#
|
54
|
+
def execute(commands, options = nil, &block)
|
55
|
+
raise "Override #execute in sub-sessions"
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_data(path, data, options = nil, &block)
|
59
|
+
raise "Override #write_data in sub-sessions"
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def add_sudo_to_commands_array(commands, user)
|
65
|
+
commands.map do |command|
|
66
|
+
"sudo -u #{user} --stdin #{command}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_options(hash, block)
|
71
|
+
if block && hash
|
72
|
+
raise Error, 'You cannot provide a block and options'
|
73
|
+
elsif block
|
74
|
+
ExecutionOptions.from_block(&block)
|
75
|
+
elsif hash.is_a?(Hash)
|
76
|
+
ExecutionOptions.from_hash(hash)
|
77
|
+
else
|
78
|
+
ExecutionOptions.new
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def log(type, text, options = {})
|
83
|
+
logger = @logger || SSHake.logger
|
84
|
+
return unless logger
|
85
|
+
|
86
|
+
prefix = "[#{@id}] [#{@host}] "
|
87
|
+
|
88
|
+
text.split(/\n/).each do |line|
|
89
|
+
logger.send(type, prefix + line)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def prepare_commands(commands, execution_options, **options)
|
94
|
+
commands = [commands] unless commands.is_a?(Array)
|
95
|
+
|
96
|
+
# Map sudo onto command
|
97
|
+
if execution_options.sudo_user && options[:add_sudo] != false
|
98
|
+
commands = add_sudo_to_commands_array(commands, execution_options.sudo_user)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Construct a full command string to execute
|
102
|
+
commands.join(' && ')
|
103
|
+
end
|
104
|
+
|
105
|
+
def handle_response(response, options)
|
106
|
+
if !response.success? && ((options.raise_on_error.nil? && @raise_on_error) || options.raise_on_error?)
|
107
|
+
raise ExecutionError, response
|
108
|
+
else
|
109
|
+
response
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
data/lib/sshake/error.rb
CHANGED
@@ -41,6 +41,12 @@ module SSHake
|
|
41
41
|
# @return [Proc]
|
42
42
|
attr_accessor :stderr
|
43
43
|
|
44
|
+
# A file that you wish to stream to the remote channel
|
45
|
+
# with the current commend
|
46
|
+
#
|
47
|
+
# @return [File]
|
48
|
+
attr_accessor :file_to_stream
|
49
|
+
|
44
50
|
# Should errors be raised
|
45
51
|
#
|
46
52
|
# @return [Boolean]
|
@@ -76,6 +82,7 @@ module SSHake
|
|
76
82
|
options.stdin = hash[:stdin]
|
77
83
|
options.stdout = hash[:stdout]
|
78
84
|
options.stderr = hash[:stderr]
|
85
|
+
options.file_to_stream = hash[:file_to_stream]
|
79
86
|
options
|
80
87
|
end
|
81
88
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SSHake
|
2
4
|
class ExecutionOptionsDSL
|
3
5
|
def initialize(options)
|
@@ -13,8 +15,12 @@ module SSHake
|
|
13
15
|
@options.sudo_password = options[:password]
|
14
16
|
end
|
15
17
|
|
16
|
-
def raise_on_error
|
17
|
-
@options.raise_on_error =
|
18
|
+
def raise_on_error(bool = true)
|
19
|
+
@options.raise_on_error = bool
|
20
|
+
end
|
21
|
+
|
22
|
+
def dont_raise_on_error
|
23
|
+
@options.raise_on_error = false
|
18
24
|
end
|
19
25
|
|
20
26
|
def stdin(value)
|
@@ -28,5 +34,9 @@ module SSHake
|
|
28
34
|
def stderr(&block)
|
29
35
|
@options.stderr = block
|
30
36
|
end
|
37
|
+
|
38
|
+
def file_to_stream(file)
|
39
|
+
@options.file_to_stream = file
|
40
|
+
end
|
31
41
|
end
|
32
42
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'sshake/response'
|
2
|
+
|
3
|
+
module SSHake
|
4
|
+
module Mock
|
5
|
+
class Command
|
6
|
+
|
7
|
+
def initialize(matcher, &block)
|
8
|
+
@matcher = matcher
|
9
|
+
@block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def match(command)
|
13
|
+
command = command.to_s
|
14
|
+
case @matcher
|
15
|
+
when String
|
16
|
+
@matcher == command ? [] : nil
|
17
|
+
when Regexp
|
18
|
+
if match = command.match(/\A#{@matcher}\z/)
|
19
|
+
match.captures
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def make_response(environment)
|
25
|
+
response = SSHake::Response.new
|
26
|
+
response.start_time = Time.now
|
27
|
+
if @block
|
28
|
+
@block.call(response, environment)
|
29
|
+
end
|
30
|
+
response.finish_time = Time.now
|
31
|
+
response
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'sshake/mock/command'
|
2
|
+
|
3
|
+
module SSHake
|
4
|
+
module Mock
|
5
|
+
class CommandSet
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@commands = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(matcher, &block)
|
12
|
+
command = Command.new(matcher, &block)
|
13
|
+
@commands << command
|
14
|
+
command
|
15
|
+
end
|
16
|
+
|
17
|
+
def match(given_command)
|
18
|
+
@commands.each do |command|
|
19
|
+
if matches = command.match(given_command)
|
20
|
+
return [command, matches]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SSHake
|
2
|
+
module Mock
|
3
|
+
class Environment
|
4
|
+
|
5
|
+
def initialize(session)
|
6
|
+
@session = session
|
7
|
+
@captures = []
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :command
|
11
|
+
attr_accessor :options
|
12
|
+
attr_accessor :captures
|
13
|
+
|
14
|
+
def store
|
15
|
+
@session ? @session.store : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def written_files
|
19
|
+
@session ? @session.written_files : nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SSHake
|
2
|
+
module Mock
|
3
|
+
class ExecutedCommand
|
4
|
+
|
5
|
+
attr_reader :command
|
6
|
+
attr_reader :environment
|
7
|
+
attr_reader :response
|
8
|
+
|
9
|
+
def initialize(command, environment, response)
|
10
|
+
@command = command
|
11
|
+
@environment = environment
|
12
|
+
@response = response
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'sshake/base_session'
|
3
|
+
require 'sshake/mock/command_set'
|
4
|
+
require 'sshake/mock/environment'
|
5
|
+
require 'sshake/mock/unsupported_command_error'
|
6
|
+
require 'sshake/mock/executed_command'
|
7
|
+
|
8
|
+
module SSHake
|
9
|
+
module Mock
|
10
|
+
class Session < BaseSession
|
11
|
+
|
12
|
+
attr_reader :command_set
|
13
|
+
attr_reader :store
|
14
|
+
attr_reader :written_files
|
15
|
+
attr_reader :executed_commands
|
16
|
+
|
17
|
+
def initialize(**options)
|
18
|
+
@options = options
|
19
|
+
@command_set = options[:command_set] || CommandSet.new
|
20
|
+
@executed_commands = []
|
21
|
+
@store = {}
|
22
|
+
@written_files = {}
|
23
|
+
@connected = false
|
24
|
+
yield(self) if block_given?
|
25
|
+
end
|
26
|
+
|
27
|
+
def connect
|
28
|
+
case @options[:connection_error]
|
29
|
+
when :timeout
|
30
|
+
raise Net::SSH::ConnectionTimeout
|
31
|
+
when :authentication_failed
|
32
|
+
raise Net::SSH::AuthenticationFailed
|
33
|
+
when :connection_refused
|
34
|
+
raise Errno::ECONNREFUSED
|
35
|
+
when :host_unreachable
|
36
|
+
raise Errno::EHOSTUNREACH
|
37
|
+
else
|
38
|
+
@connected = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def connected?
|
43
|
+
@connected == true
|
44
|
+
end
|
45
|
+
|
46
|
+
def disconnect
|
47
|
+
@connected = false
|
48
|
+
end
|
49
|
+
|
50
|
+
def kill!
|
51
|
+
disconnect
|
52
|
+
end
|
53
|
+
|
54
|
+
def execute(commands, options = nil, &block)
|
55
|
+
connect unless connected?
|
56
|
+
|
57
|
+
environment = Environment.new(self)
|
58
|
+
|
59
|
+
environment.options = create_options(options, block)
|
60
|
+
environment.command = prepare_commands(commands, environment.options, :add_sudo => false)
|
61
|
+
|
62
|
+
command, environment.captures = @command_set.match(environment.command)
|
63
|
+
|
64
|
+
if command.nil?
|
65
|
+
raise UnsupportedCommandError.new(environment.command)
|
66
|
+
end
|
67
|
+
|
68
|
+
response = command.make_response(environment)
|
69
|
+
|
70
|
+
if environment.options.file_to_stream
|
71
|
+
response.bytes_streamed = environment.options.file_to_stream.size
|
72
|
+
end
|
73
|
+
|
74
|
+
@executed_commands << ExecutedCommand.new(command, environment, response)
|
75
|
+
handle_response(response, environment.options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def write_data(path, data, options = nil, &block)
|
79
|
+
connect unless connected?
|
80
|
+
@written_files[path] = data
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def find_executed_commands(matcher)
|
85
|
+
if matcher.is_a?(Regexp)
|
86
|
+
matcher = /\A#{matcher}\z/
|
87
|
+
else
|
88
|
+
matcher = /\A#{Regexp.escape(matcher.to_s)}\z/
|
89
|
+
end
|
90
|
+
@executed_commands.select do |command|
|
91
|
+
command.environment.command =~ matcher
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def has_executed_command?(matcher)
|
96
|
+
find_executed_commands(matcher).size > 0
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sshake/error'
|
2
|
+
|
3
|
+
module SSHake
|
4
|
+
module Mock
|
5
|
+
class UnsupportedCommandError < Error
|
6
|
+
|
7
|
+
def initialize(command)
|
8
|
+
@command = command
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"Executed command is not support by the mock session (`#{@command}`)"
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/sshake/response.rb
CHANGED
@@ -5,6 +5,8 @@ module SSHake
|
|
5
5
|
def initialize
|
6
6
|
@stdout = ''
|
7
7
|
@stderr = ''
|
8
|
+
@exit_code = 0
|
9
|
+
@bytes_streamed = 0
|
8
10
|
end
|
9
11
|
|
10
12
|
attr_accessor :command
|
@@ -14,6 +16,7 @@ module SSHake
|
|
14
16
|
attr_accessor :exit_signal
|
15
17
|
attr_accessor :start_time
|
16
18
|
attr_accessor :finish_time
|
19
|
+
attr_accessor :bytes_streamed
|
17
20
|
|
18
21
|
def success?
|
19
22
|
@exit_code == 0
|
@@ -26,5 +29,9 @@ module SSHake
|
|
26
29
|
def timeout?
|
27
30
|
@exit_code == -255
|
28
31
|
end
|
32
|
+
|
33
|
+
def timeout!
|
34
|
+
@exit_code = -255
|
35
|
+
end
|
29
36
|
end
|
30
37
|
end
|
data/lib/sshake/session.rb
CHANGED
@@ -4,26 +4,21 @@ require 'net/ssh'
|
|
4
4
|
require 'net/sftp'
|
5
5
|
require 'timeout'
|
6
6
|
require 'sshake/error'
|
7
|
-
require 'sshake/logger'
|
8
7
|
require 'sshake/response'
|
9
|
-
require 'sshake/
|
8
|
+
require 'sshake/base_session'
|
10
9
|
|
11
10
|
module SSHake
|
12
|
-
class Session
|
11
|
+
class Session < BaseSession
|
13
12
|
# The underlying net/ssh session
|
14
13
|
#
|
15
14
|
# @return [Net::SSH::Session]
|
16
15
|
attr_reader :session
|
17
16
|
|
18
|
-
# A logger for this session
|
19
|
-
#
|
20
|
-
# @return [Logger, nil]
|
21
|
-
attr_accessor :logger
|
22
|
-
|
23
17
|
# Create a new SSH session
|
24
18
|
#
|
25
19
|
# @return [Sshake::Session]
|
26
20
|
def initialize(host, *args)
|
21
|
+
super
|
27
22
|
@host = host
|
28
23
|
@session_options = args
|
29
24
|
end
|
@@ -32,6 +27,8 @@ module SSHake
|
|
32
27
|
#
|
33
28
|
# @return [void]
|
34
29
|
def connect
|
30
|
+
log :debug, "Creating connection to #{@host}"
|
31
|
+
log :debug, "Session options: #{@session_options.inspect}"
|
35
32
|
@session = Net::SSH.start(@host, *@session_options)
|
36
33
|
true
|
37
34
|
end
|
@@ -47,9 +44,14 @@ module SSHake
|
|
47
44
|
#
|
48
45
|
# @return [void]
|
49
46
|
def disconnect
|
47
|
+
return false if @session.nil?
|
48
|
+
|
50
49
|
begin
|
50
|
+
log :debug, 'Closing connectiong'
|
51
51
|
@session.close
|
52
|
-
|
52
|
+
log :debug, 'Connection closed successfully'
|
53
|
+
rescue StandardError => e
|
54
|
+
log :debug, "Connection not closed: #{e.message} (#{e.class})"
|
53
55
|
nil
|
54
56
|
end
|
55
57
|
@session = nil
|
@@ -58,121 +60,106 @@ module SSHake
|
|
58
60
|
|
59
61
|
# Kill the underlying connection
|
60
62
|
def kill!
|
63
|
+
log :debug, "Attempting kill/shutdown of session"
|
61
64
|
@session.shutdown!
|
65
|
+
log :debug, "Session shutdown success"
|
62
66
|
@session = nil
|
63
67
|
end
|
64
68
|
|
65
|
-
# Execute a command
|
66
|
-
#
|
67
69
|
def execute(commands, options = nil, &block)
|
68
|
-
commands = [commands] unless commands.is_a?(Array)
|
69
|
-
|
70
70
|
options = create_options(options, block)
|
71
|
-
|
72
|
-
# Map sudo onto command
|
73
|
-
if options.sudo_user
|
74
|
-
commands = add_sudo_to_commands_array(commands, options.sudo_user)
|
75
|
-
end
|
76
|
-
|
77
|
-
# Construct a full command string to execute
|
78
|
-
command = commands.join(' && ')
|
79
|
-
|
80
|
-
# Log the command
|
81
|
-
log :info, "\e[44;37m=> #{command}\e[0m"
|
71
|
+
command_to_execute = prepare_commands(commands, options)
|
82
72
|
|
83
73
|
# Execute the command
|
84
74
|
response = Response.new
|
85
|
-
response.command =
|
75
|
+
response.command = command_to_execute
|
86
76
|
connect unless connected?
|
77
|
+
|
78
|
+
# Log the command
|
79
|
+
log :info, "Executing: #{command_to_execute}"
|
80
|
+
log :debug, "Timeout: #{options.timeout}"
|
81
|
+
|
87
82
|
begin
|
88
83
|
channel = nil
|
89
84
|
Timeout.timeout(options.timeout) do
|
90
85
|
channel = @session.open_channel do |ch|
|
91
86
|
response.start_time = Time.now
|
92
|
-
channel.exec(
|
93
|
-
raise "Command \"#{
|
87
|
+
channel.exec(command_to_execute) do |_, success|
|
88
|
+
raise "Command \"#{command_to_execute}\" was unable to execute" unless success
|
89
|
+
|
90
|
+
if options.stdin
|
91
|
+
ch.send_data(options.stdin)
|
92
|
+
end
|
94
93
|
|
95
|
-
|
96
|
-
|
94
|
+
if options.file_to_stream.nil?
|
95
|
+
ch.eof!
|
96
|
+
end
|
97
97
|
|
98
98
|
ch.on_data do |_, data|
|
99
99
|
response.stdout += data
|
100
100
|
options.stdout&.call(data)
|
101
|
-
log :debug, data.gsub(/[\r]/, '')
|
101
|
+
log :debug, data.gsub(/[\r]/, '')
|
102
102
|
end
|
103
103
|
|
104
104
|
ch.on_extended_data do |_, _, data|
|
105
105
|
response.stderr += data.delete("\r")
|
106
106
|
options.stderr&.call(data)
|
107
|
-
log :
|
107
|
+
log :debug, data
|
108
108
|
if data =~ /^\[sudo\] password for/
|
109
|
+
log :debug, 'Sending sudo password'
|
109
110
|
ch.send_data "#{options.sudo_password}\n"
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
113
114
|
ch.on_request('exit-status') do |_, data|
|
114
115
|
response.exit_code = data.read_long&.to_i
|
115
|
-
log :
|
116
|
+
log :debug, "Exit code: #{response.exit_code}"
|
116
117
|
end
|
117
118
|
|
118
119
|
ch.on_request('exit-signal') do |_, data|
|
119
120
|
response.exit_signal = data.read_long
|
120
121
|
end
|
122
|
+
|
123
|
+
if options.file_to_stream
|
124
|
+
ch.on_process do |_, data|
|
125
|
+
next if ch.eof?
|
126
|
+
if ch.output.length < 128 * 1024
|
127
|
+
if data = options.file_to_stream.read(1024 * 1024)
|
128
|
+
ch.send_data(data)
|
129
|
+
response.bytes_streamed += data.bytesize
|
130
|
+
else
|
131
|
+
ch.eof!
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
121
136
|
end
|
122
137
|
end
|
123
138
|
channel.wait
|
124
139
|
end
|
125
140
|
rescue Timeout::Error => e
|
141
|
+
log :debug, "Got timeout error while executing command"
|
126
142
|
kill!
|
127
|
-
response.
|
143
|
+
response.timeout!
|
128
144
|
ensure
|
129
145
|
response.finish_time = Time.now
|
130
146
|
end
|
131
147
|
|
132
|
-
|
133
|
-
raise ExecutionError, response
|
134
|
-
else
|
135
|
-
response
|
136
|
-
end
|
148
|
+
handle_response(response, options)
|
137
149
|
end
|
138
150
|
|
139
151
|
def write_data(path, data, options = nil, &block)
|
140
152
|
connect unless connected?
|
141
153
|
tmp_path = "/tmp/sshake-tmp-file-#{SecureRandom.hex(32)}"
|
142
|
-
@session.sftp.file.open(
|
154
|
+
@session.sftp.file.open(tmp_path, 'w') do |f|
|
155
|
+
d = data.dup.force_encoding('BINARY')
|
156
|
+
until d.empty?
|
157
|
+
f.write(d.slice!(0, 1024))
|
158
|
+
end
|
159
|
+
end
|
143
160
|
response = execute("mv #{tmp_path} #{path}", options, &block)
|
144
161
|
response.success?
|
145
162
|
end
|
146
163
|
|
147
|
-
private
|
148
|
-
|
149
|
-
def add_sudo_to_commands_array(commands, user)
|
150
|
-
commands.map do |command|
|
151
|
-
"sudo -u #{user} --stdin #{command}"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def create_options(hash, block)
|
156
|
-
if block && hash
|
157
|
-
raise Error, 'You cannot provide a block and options'
|
158
|
-
elsif block
|
159
|
-
ExecutionOptions.from_block(&block)
|
160
|
-
elsif hash.is_a?(Hash)
|
161
|
-
ExecutionOptions.from_hash(hash)
|
162
|
-
else
|
163
|
-
ExecutionOptions.new
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def log(type, text, options = {})
|
168
|
-
logger = @logger || SSHake.logger
|
169
|
-
return unless logger
|
170
|
-
|
171
|
-
prefix = "\e[45;37m[#{@host}]\e[0m"
|
172
|
-
tabs = ' ' * (options[:tab] || 0)
|
173
|
-
text.split(/\n/).each do |line|
|
174
|
-
logger.send(type, prefix + tabs + line)
|
175
|
-
end
|
176
|
-
end
|
177
164
|
end
|
178
165
|
end
|
data/lib/sshake/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sshake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Cooke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-sftp
|
@@ -45,10 +45,18 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- lib/sshake.rb
|
49
|
+
- lib/sshake/base_session.rb
|
48
50
|
- lib/sshake/error.rb
|
49
51
|
- lib/sshake/execution_options.rb
|
50
52
|
- lib/sshake/execution_options_dsl.rb
|
51
53
|
- lib/sshake/logger.rb
|
54
|
+
- lib/sshake/mock/command.rb
|
55
|
+
- lib/sshake/mock/command_set.rb
|
56
|
+
- lib/sshake/mock/environment.rb
|
57
|
+
- lib/sshake/mock/executed_command.rb
|
58
|
+
- lib/sshake/mock/session.rb
|
59
|
+
- lib/sshake/mock/unsupported_command_error.rb
|
52
60
|
- lib/sshake/response.rb
|
53
61
|
- lib/sshake/session.rb
|
54
62
|
- lib/sshake/version.rb
|
@@ -71,8 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
79
|
- !ruby/object:Gem::Version
|
72
80
|
version: '0'
|
73
81
|
requirements: []
|
74
|
-
|
75
|
-
rubygems_version: 2.5.2.3
|
82
|
+
rubygems_version: 3.0.3
|
76
83
|
signing_key:
|
77
84
|
specification_version: 4
|
78
85
|
summary: A wrapper for net/ssh to make running commands more fun
|