sshake 1.1.0 → 2.0.0
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/lib/sshake/base_session.rb +6 -15
- data/lib/sshake/error.rb +1 -1
- data/lib/sshake/klogger.rb +14 -0
- data/lib/sshake/mock/environment.rb +2 -2
- data/lib/sshake/session.rb +73 -74
- data/lib/sshake/version.rb +1 -1
- metadata +29 -8
- data/lib/sshake/logger.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95a0f6a6db803ff62826997e18e0b5d5ec81977046833bc32c10e29ebdbfd883
|
4
|
+
data.tar.gz: 8a2c9aa526b96827b3d50d25cd8b479bf3310eb6857822790410e79a38ac8423
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc53e93b8e027f96c6078acb1626a056512dbf932a5650a1e4e4dfa53d28d72c219cff4acb392ca3d46fcbd5cd136aa7114b3edca27884817f86ace0648ec0c5
|
7
|
+
data.tar.gz: 25e70b953ed507800fa3f1a0531c926023d383f8a73caf8de201e12db2b4dd4e864af0080bf657952ad00112528572368e6c9eced39adf254858897e9487a6e3
|
data/lib/sshake/base_session.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'securerandom'
|
4
|
-
require '
|
4
|
+
require 'klogger'
|
5
|
+
require 'sshake/klogger'
|
5
6
|
require 'sshake/execution_options'
|
6
7
|
|
7
8
|
module SSHake
|
@@ -9,8 +10,8 @@ module SSHake
|
|
9
10
|
|
10
11
|
# A logger for this session
|
11
12
|
#
|
12
|
-
# @return [
|
13
|
-
attr_accessor :
|
13
|
+
# @return [Klogger, nil]
|
14
|
+
attr_accessor :klogger
|
14
15
|
|
15
16
|
# An ID for this session
|
16
17
|
#
|
@@ -22,8 +23,9 @@ module SSHake
|
|
22
23
|
# @return [Boolean]
|
23
24
|
attr_accessor :raise_on_error
|
24
25
|
|
25
|
-
def initialize(*_args)
|
26
|
+
def initialize(*_args, klogger: nil)
|
26
27
|
@id = SecureRandom.hex(4)
|
28
|
+
@klogger = klogger || SSHake.klogger
|
27
29
|
end
|
28
30
|
|
29
31
|
# Connect to the SSH server
|
@@ -88,17 +90,6 @@ module SSHake
|
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
def log(type, text, _options = {})
|
92
|
-
logger = @logger || SSHake.logger
|
93
|
-
return unless logger
|
94
|
-
|
95
|
-
prefix = "[#{@id}] [#{@host}] "
|
96
|
-
|
97
|
-
text.split(/\n/).each do |line|
|
98
|
-
logger.send(type, prefix + line)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
93
|
def prepare_commands(commands, execution_options, **options)
|
103
94
|
commands = [commands] unless commands.is_a?(Array)
|
104
95
|
|
data/lib/sshake/error.rb
CHANGED
@@ -12,11 +12,11 @@ module SSHake
|
|
12
12
|
attr_accessor :command, :options, :captures
|
13
13
|
|
14
14
|
def store
|
15
|
-
@session
|
15
|
+
@session&.store
|
16
16
|
end
|
17
17
|
|
18
18
|
def written_files
|
19
|
-
@session
|
19
|
+
@session&.written_files
|
20
20
|
end
|
21
21
|
|
22
22
|
end
|
data/lib/sshake/session.rb
CHANGED
@@ -23,23 +23,19 @@ module SSHake
|
|
23
23
|
# Create a new SSH session
|
24
24
|
#
|
25
25
|
# @return [Sshake::Session]
|
26
|
-
def initialize(host,
|
26
|
+
def initialize(host, username = nil, **options)
|
27
27
|
super
|
28
28
|
@host = host
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
else
|
33
|
-
@user = username_or_options.delete(:user)
|
34
|
-
@session_options = username_or_options
|
35
|
-
end
|
29
|
+
@username = username
|
30
|
+
@session_options = options
|
31
|
+
@session_options.delete(:klogger)
|
36
32
|
end
|
37
33
|
|
38
34
|
# Return the username for the connection
|
39
35
|
#
|
40
36
|
# @return [String]
|
41
37
|
def user
|
42
|
-
@user || ENV
|
38
|
+
@user || ENV.fetch('USER', nil)
|
43
39
|
end
|
44
40
|
|
45
41
|
# Return the port that will be connected to
|
@@ -53,8 +49,7 @@ module SSHake
|
|
53
49
|
#
|
54
50
|
# @return [void]
|
55
51
|
def connect
|
56
|
-
|
57
|
-
log :debug, "Session options: #{@session_options.inspect}"
|
52
|
+
klogger.debug 'Connecting', id: @id, host: @host, user: @user, port: @session_options[:port] || 22
|
58
53
|
@session = Net::SSH.start(@host, user, @session_options)
|
59
54
|
true
|
60
55
|
end
|
@@ -73,11 +68,11 @@ module SSHake
|
|
73
68
|
return false if @session.nil?
|
74
69
|
|
75
70
|
begin
|
76
|
-
|
71
|
+
klogger.debug 'Closing connection', id: @id, host: @host
|
77
72
|
@session.close
|
78
|
-
|
73
|
+
klogger.debug 'Connection closed', id: @id, host: @host
|
79
74
|
rescue StandardError => e
|
80
|
-
|
75
|
+
logger.exception(e, 'Connection not closed')
|
81
76
|
nil
|
82
77
|
end
|
83
78
|
@session = nil
|
@@ -86,12 +81,13 @@ module SSHake
|
|
86
81
|
|
87
82
|
# Kill the underlying connection
|
88
83
|
def kill!
|
89
|
-
|
84
|
+
klogger.debug 'Attemping to shutdown', id: @id, host: @host
|
90
85
|
@session.shutdown!
|
91
|
-
|
86
|
+
klogger.debug 'Shutdown success', id: @id, host: @host
|
92
87
|
@session = nil
|
93
88
|
end
|
94
89
|
|
90
|
+
# rubocop:disable Metrics/AbcSize
|
95
91
|
def execute(commands, options = nil, &block)
|
96
92
|
options = create_options(options, block)
|
97
93
|
command_to_execute = prepare_commands(commands, options)
|
@@ -101,83 +97,86 @@ module SSHake
|
|
101
97
|
response.command = command_to_execute
|
102
98
|
connect unless connected?
|
103
99
|
|
104
|
-
|
105
|
-
|
106
|
-
log :debug, "Timeout: #{options.timeout}"
|
100
|
+
klogger.group(id: @id, host: @host) do
|
101
|
+
klogger.info 'Executing command', command: command_to_execute, timeout: options.timeout
|
107
102
|
|
108
|
-
|
109
|
-
|
110
|
-
Timeout.timeout(options.timeout) do
|
111
|
-
channel = @session.open_channel do |ch|
|
112
|
-
response.start_time = Time.now
|
113
|
-
channel.exec(command_to_execute) do |_, success|
|
114
|
-
raise "Command \"#{command_to_execute}\" was unable to execute" unless success
|
115
|
-
|
116
|
-
ch.send_data(options.stdin) if options.stdin
|
117
|
-
|
118
|
-
if options.file_to_stream.nil? && options.sudo_password.nil?
|
119
|
-
log :debug, 'Sending EOF to channel'
|
120
|
-
ch.eof!
|
121
|
-
end
|
103
|
+
begin
|
104
|
+
channel = nil
|
122
105
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
log :debug, data.gsub(/\r/, '')
|
127
|
-
end
|
106
|
+
Timeout.timeout(options.timeout) do
|
107
|
+
channel = @session.open_channel do |ch|
|
108
|
+
response.start_time = Time.now
|
128
109
|
|
129
|
-
|
130
|
-
|
131
|
-
options.stderr&.call(data)
|
132
|
-
log :debug, data
|
133
|
-
if options.sudo_password && data =~ /^\[sshake-sudo-password\]:\s\z/
|
134
|
-
log :debug, 'Sending sudo password'
|
135
|
-
ch.send_data "#{options.sudo_password}\n"
|
136
|
-
|
137
|
-
if options.file_to_stream.nil?
|
138
|
-
log :debug, 'Sending EOF after sudo password because no file'
|
139
|
-
ch.eof!
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
110
|
+
channel.exec(command_to_execute) do |_, success|
|
111
|
+
raise "Command \"#{command_to_execute}\" was unable to execute" unless success
|
143
112
|
|
144
|
-
|
145
|
-
response.exit_code = data.read_long&.to_i
|
146
|
-
log :debug, "Exit code: #{response.exit_code}"
|
147
|
-
end
|
113
|
+
ch.send_data(options.stdin) if options.stdin
|
148
114
|
|
149
|
-
|
150
|
-
|
151
|
-
|
115
|
+
if options.file_to_stream.nil? && options.sudo_password.nil?
|
116
|
+
klogger.debug 'Sending EOF to channel'
|
117
|
+
ch.eof!
|
118
|
+
end
|
152
119
|
|
153
|
-
|
154
|
-
|
155
|
-
|
120
|
+
ch.on_data do |_, data|
|
121
|
+
response.stdout += data
|
122
|
+
options.stdout&.call(data)
|
123
|
+
klogger.debug "[stdout] #{data.gsub(/\r/, '').strip}"
|
124
|
+
end
|
125
|
+
|
126
|
+
ch.on_extended_data do |_, _, data|
|
127
|
+
response.stderr += data.delete("\r")
|
128
|
+
options.stderr&.call(data)
|
129
|
+
klogger.debug "[stderr] #{data.gsub(/\r/, '').strip}"
|
130
|
+
if options.sudo_password && data =~ /^\[sshake-sudo-password\]:\s\z/
|
131
|
+
klogger.debug 'Sending sudo password', length: options.sudo_password.length
|
132
|
+
ch.send_data "#{options.sudo_password}\n"
|
156
133
|
|
157
|
-
|
158
|
-
|
159
|
-
ch.send_data(data)
|
160
|
-
response.bytes_streamed += data.bytesize
|
161
|
-
else
|
134
|
+
if options.file_to_stream.nil?
|
135
|
+
klogger.debug 'Sending EOF after password'
|
162
136
|
ch.eof!
|
163
137
|
end
|
164
138
|
end
|
165
139
|
end
|
140
|
+
|
141
|
+
ch.on_request('exit-status') do |_, data|
|
142
|
+
response.exit_code = data.read_long&.to_i
|
143
|
+
klogger.info 'Exited', exit_code: response.exit_code
|
144
|
+
end
|
145
|
+
|
146
|
+
ch.on_request('exit-signal') do |_, data|
|
147
|
+
response.exit_signal = data.read_long
|
148
|
+
end
|
149
|
+
|
150
|
+
if options.file_to_stream
|
151
|
+
ch.on_process do |_, data|
|
152
|
+
next if ch.eof?
|
153
|
+
|
154
|
+
if ch.output.length < 128 * 1024
|
155
|
+
if data = options.file_to_stream.read(1024 * 1024)
|
156
|
+
ch.send_data(data)
|
157
|
+
response.bytes_streamed += data.bytesize
|
158
|
+
else
|
159
|
+
ch.eof!
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
166
164
|
end
|
167
165
|
end
|
166
|
+
channel.wait
|
168
167
|
end
|
169
|
-
|
168
|
+
rescue Timeout::Error
|
169
|
+
klogger.debug 'Command timed out'
|
170
|
+
kill!
|
171
|
+
response.timeout!
|
172
|
+
ensure
|
173
|
+
response.finish_time = Time.now
|
170
174
|
end
|
171
|
-
rescue Timeout::Error
|
172
|
-
log :debug, 'Got timeout error while executing command'
|
173
|
-
kill!
|
174
|
-
response.timeout!
|
175
|
-
ensure
|
176
|
-
response.finish_time = Time.now
|
177
175
|
end
|
178
176
|
|
179
177
|
handle_response(response, options)
|
180
178
|
end
|
179
|
+
# rubocop:enable Metrics/AbcSize
|
181
180
|
|
182
181
|
def write_data(path, data, options = nil, &block)
|
183
182
|
connect unless connected?
|
data/lib/sshake/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sshake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Cooke
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: klogger-logger
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2'
|
13
33
|
- !ruby/object:Gem::Dependency
|
14
34
|
name: net-sftp
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +70,7 @@ files:
|
|
50
70
|
- lib/sshake/error.rb
|
51
71
|
- lib/sshake/execution_options.rb
|
52
72
|
- lib/sshake/execution_options_dsl.rb
|
53
|
-
- lib/sshake/
|
73
|
+
- lib/sshake/klogger.rb
|
54
74
|
- lib/sshake/mock/command.rb
|
55
75
|
- lib/sshake/mock/command_set.rb
|
56
76
|
- lib/sshake/mock/environment.rb
|
@@ -66,8 +86,9 @@ files:
|
|
66
86
|
homepage: https://github.com/adamcooke/sshake
|
67
87
|
licenses:
|
68
88
|
- MIT
|
69
|
-
metadata:
|
70
|
-
|
89
|
+
metadata:
|
90
|
+
rubygems_mfa_required: 'true'
|
91
|
+
post_install_message:
|
71
92
|
rdoc_options: []
|
72
93
|
require_paths:
|
73
94
|
- lib
|
@@ -82,8 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
103
|
- !ruby/object:Gem::Version
|
83
104
|
version: '0'
|
84
105
|
requirements: []
|
85
|
-
rubygems_version: 3.
|
86
|
-
signing_key:
|
106
|
+
rubygems_version: 3.2.32
|
107
|
+
signing_key:
|
87
108
|
specification_version: 4
|
88
109
|
summary: A wrapper for net/ssh to make running commands more fun
|
89
110
|
test_files: []
|