sshkit 1.6.1 → 1.7.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/.gitignore +3 -0
- data/CHANGELOG.md +16 -1
- data/EXAMPLES.md +7 -0
- data/README.md +2 -2
- data/Vagrantfile +1 -8
- data/{assets → examples}/images/example_output.png +0 -0
- data/{assets → examples}/images/logo.png +0 -0
- data/lib/sshkit/backends/local.rb +47 -15
- data/lib/sshkit/backends/netssh.rb +4 -4
- data/lib/sshkit/command.rb +2 -4
- data/lib/sshkit/exception.rb +0 -8
- data/lib/sshkit/formatters/pretty.rb +2 -0
- data/lib/sshkit/host.rb +10 -1
- data/lib/sshkit/runners/abstract.rb +5 -1
- data/lib/sshkit/version.rb +1 -1
- data/test/functional/backends/test_netssh.rb +11 -0
- data/test/unit/test_host.rb +9 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbc4c4d5b2ac3c6cfda56f6d7582b6c2e4b0814d
|
4
|
+
data.tar.gz: 6a260d8a28ed5df45fd14de2140aa0de0f6ef577
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e37e0ac83457d83c0c5d41676830097c5ccd6f24ae5cc636533d2c2bb54a2f7706f387ec9af97a458a332a198b90189fd4263ec3411fb07a75db56cd0db25107
|
7
|
+
data.tar.gz: 135cc559ee24611b6f1ccab198445ea7a8efe2df7339c12409e5547a5c3ea0a1ae22d61a640b2a6703b1bb9e7c36af15d1f05fc2103d43d222bcd8fe9a978450
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,11 +3,26 @@
|
|
3
3
|
This file is written in reverse chronological order, newer releases will
|
4
4
|
appear at the top.
|
5
5
|
|
6
|
-
## (Unreleased)
|
6
|
+
## `master` (Unreleased)
|
7
7
|
|
8
8
|
* Add your entries here, remember to credit yourself however you want to be
|
9
9
|
credited!
|
10
10
|
|
11
|
+
## 1.7.0
|
12
|
+
|
13
|
+
* Update Vagrantfile to use multi-provider Hashicorp precise64 box - remove URLs. @townsen
|
14
|
+
* Merge host ssh_options and Netssh defaults @townsen
|
15
|
+
Previously if host-level ssh_options were defined the Netssh defaults
|
16
|
+
were ignored.
|
17
|
+
* Merge host ssh_options and Netssh defaults
|
18
|
+
* Fixed race condition where output of failed command would be empty. @townsen
|
19
|
+
Caused random failures of `test_execute_raises_on_non_zero_exit_status_and_captures_stdout_and_stderr`
|
20
|
+
Also fixes output handling in failed commands, and generally buggy output.
|
21
|
+
* Remove override of backtrace() and backtrace_locations() from ExecuteError. @townsen
|
22
|
+
This interferes with rake default behaviour and creates duplicate stacktraces.
|
23
|
+
* Allow running local commands using `on(:local)`
|
24
|
+
* Implement the upload! and download! methods for the local backend
|
25
|
+
|
11
26
|
## 1.6.0
|
12
27
|
|
13
28
|
* Fix colorize to use the correct API (@fazibear)
|
data/EXAMPLES.md
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-

|
2
2
|
|
3
3
|
**SSHKit** is a toolkit for running commands in a structured way on one or
|
4
4
|
more servers.
|
@@ -199,7 +199,7 @@ first argument before attempting to find it in the *command map*.
|
|
199
199
|
|
200
200
|
## Output Handling
|
201
201
|
|
202
|
-

|
203
203
|
|
204
204
|
By default, the output format is set to `:pretty`:
|
205
205
|
|
data/Vagrantfile
CHANGED
@@ -1,13 +1,7 @@
|
|
1
1
|
VAGRANTFILE_API_VERSION = "2"
|
2
2
|
|
3
3
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
4
|
-
config.vm.box = 'precise64'
|
5
|
-
config.vm.provider "vmware_fusion" do |vmf|
|
6
|
-
vmf.box_url = "http://files.vagrantup.com/precise64_vmware.box"
|
7
|
-
end
|
8
|
-
config.vm.provider "virtualbox" do |vb|
|
9
|
-
config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box"
|
10
|
-
end
|
4
|
+
config.vm.box = 'hashicorp/precise64'
|
11
5
|
|
12
6
|
json_config_path = File.join("test", "boxes.json")
|
13
7
|
list = File.open(json_config_path).read
|
@@ -15,7 +9,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|
15
9
|
|
16
10
|
list.each do |vm|
|
17
11
|
config.vm.define vm["name"] do |web|
|
18
|
-
web.vm.box = "precise64"
|
19
12
|
web.vm.network "forwarded_port", guest: 22, host: vm["port"]
|
20
13
|
end
|
21
14
|
end
|
File without changes
|
File without changes
|
@@ -1,17 +1,18 @@
|
|
1
1
|
require 'open3'
|
2
|
+
require 'fileutils'
|
2
3
|
module SSHKit
|
3
4
|
|
4
5
|
module Backend
|
5
6
|
|
6
7
|
class Local < Printer
|
7
8
|
|
8
|
-
def initialize(&block)
|
9
|
-
@host = Host.new(
|
9
|
+
def initialize(_ = nil, &block)
|
10
|
+
@host = Host.new(:local) # just for logging
|
10
11
|
@block = block
|
11
12
|
end
|
12
13
|
|
13
14
|
def run
|
14
|
-
instance_exec(&@block)
|
15
|
+
instance_exec(@host, &@block)
|
15
16
|
end
|
16
17
|
|
17
18
|
def test(*args)
|
@@ -31,6 +32,26 @@ module SSHKit
|
|
31
32
|
_execute(*[*args, options]).full_stdout
|
32
33
|
end
|
33
34
|
|
35
|
+
def upload!(local, remote, options = {})
|
36
|
+
if local.is_a?(String)
|
37
|
+
FileUtils.cp(local, remote)
|
38
|
+
else
|
39
|
+
File.open(remote, "wb") do |f|
|
40
|
+
IO.copy_stream(local, f)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def download!(remote, local=nil, options = {})
|
46
|
+
if local.nil?
|
47
|
+
FileUtils.cp(remote, File.basename(remote))
|
48
|
+
else
|
49
|
+
File.open(remote, "rb") do |f|
|
50
|
+
IO.copy_stream(f, local)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
34
55
|
private
|
35
56
|
|
36
57
|
def _execute(*args)
|
@@ -39,23 +60,34 @@ module SSHKit
|
|
39
60
|
|
40
61
|
cmd.started = Time.now
|
41
62
|
|
42
|
-
stdout, stderr,
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
63
|
+
Open3.popen3(cmd.to_command) do |stdin, stdout, stderr, wait_thr|
|
64
|
+
stdout_thread = Thread.new do
|
65
|
+
while line = stdout.gets do
|
66
|
+
cmd.stdout = line
|
67
|
+
cmd.full_stdout += line
|
68
|
+
|
69
|
+
output << cmd
|
70
|
+
end
|
48
71
|
end
|
49
72
|
|
50
|
-
|
51
|
-
|
73
|
+
stderr_thread = Thread.new do
|
74
|
+
while line = stderr.gets do
|
75
|
+
cmd.stderr = line
|
76
|
+
cmd.full_stderr += line
|
52
77
|
|
53
|
-
|
54
|
-
|
78
|
+
output << cmd
|
79
|
+
end
|
80
|
+
end
|
55
81
|
|
56
|
-
|
82
|
+
stdout_thread.join
|
83
|
+
stderr_thread.join
|
57
84
|
|
58
|
-
|
85
|
+
cmd.exit_status = wait_thr.value.to_i
|
86
|
+
cmd.stdout = ''
|
87
|
+
cmd.stderr = ''
|
88
|
+
|
89
|
+
output << cmd
|
90
|
+
end
|
59
91
|
end
|
60
92
|
end
|
61
93
|
|
@@ -133,6 +133,7 @@ module SSHKit
|
|
133
133
|
command(*args).tap do |cmd|
|
134
134
|
output << cmd
|
135
135
|
cmd.started = true
|
136
|
+
exit_status = nil
|
136
137
|
with_ssh do |ssh|
|
137
138
|
ssh.open_channel do |chan|
|
138
139
|
chan.request_pty if Netssh.config.pty
|
@@ -148,9 +149,7 @@ module SSHKit
|
|
148
149
|
output << cmd
|
149
150
|
end
|
150
151
|
chan.on_request("exit-status") do |ch, data|
|
151
|
-
|
152
|
-
cmd.stderr = ''
|
153
|
-
cmd.exit_status = data.read_long
|
152
|
+
exit_status = data.read_long
|
154
153
|
output << cmd
|
155
154
|
end
|
156
155
|
#chan.on_request("exit-signal") do |ch, data|
|
@@ -176,11 +175,12 @@ module SSHKit
|
|
176
175
|
end
|
177
176
|
ssh.loop
|
178
177
|
end
|
178
|
+
cmd.exit_status = exit_status if exit_status
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
182
|
def with_ssh
|
183
|
-
host.ssh_options
|
183
|
+
host.ssh_options = Netssh.config.ssh_options.merge(host.ssh_options || {})
|
184
184
|
conn = self.class.pool.checkout(
|
185
185
|
String(host.hostname),
|
186
186
|
host.username,
|
data/lib/sshkit/command.rb
CHANGED
@@ -90,10 +90,8 @@ module SSHKit
|
|
90
90
|
if options[:raise_on_non_zero_exit] && exit_status > 0
|
91
91
|
message = ""
|
92
92
|
message += "#{command} exit status: " + exit_status.to_s + "\n"
|
93
|
-
message += "#{command} stdout: " + (
|
94
|
-
|
95
|
-
stderr_message = [stderr.strip, full_stderr.strip].delete_if(&:empty?).first
|
96
|
-
message += "#{command} stderr: " + (stderr_message || 'Nothing written') + "\n"
|
93
|
+
message += "#{command} stdout: " + (full_stdout.strip.empty? ? "Nothing written" : full_stdout.strip) + "\n"
|
94
|
+
message += "#{command} stderr: " + (full_stderr.strip.empty? ? 'Nothing written' : full_stderr.strip) + "\n"
|
97
95
|
raise Failed, message
|
98
96
|
end
|
99
97
|
end
|
data/lib/sshkit/exception.rb
CHANGED
@@ -34,6 +34,7 @@ module SSHKit
|
|
34
34
|
uuid(command) + c.green("\t" + line)]
|
35
35
|
original_output << "\n" unless line[-1] == "\n"
|
36
36
|
end
|
37
|
+
command.stdout = ''
|
37
38
|
end
|
38
39
|
|
39
40
|
unless command.stderr.empty?
|
@@ -42,6 +43,7 @@ module SSHKit
|
|
42
43
|
uuid(command) + c.red("\t" + line)]
|
43
44
|
original_output << "\n" unless line[-1] == "\n"
|
44
45
|
end
|
46
|
+
command.stderr = ''
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
data/lib/sshkit/host.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ostruct'
|
2
|
+
require 'etc'
|
2
3
|
|
3
4
|
module SSHKit
|
4
5
|
|
@@ -22,7 +23,11 @@ module SSHKit
|
|
22
23
|
|
23
24
|
def initialize(host_string_or_options_hash)
|
24
25
|
|
25
|
-
|
26
|
+
if host_string_or_options_hash == :local
|
27
|
+
@local = true
|
28
|
+
@hostname = "localhost"
|
29
|
+
@user = Etc.getpwuid.name
|
30
|
+
elsif !host_string_or_options_hash.is_a?(Hash)
|
26
31
|
suitable_parsers = [
|
27
32
|
SimpleHostParser,
|
28
33
|
HostWithPortParser,
|
@@ -51,6 +56,10 @@ module SSHKit
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
59
|
+
def local?
|
60
|
+
@local
|
61
|
+
end
|
62
|
+
|
54
63
|
def hash
|
55
64
|
user.hash ^ hostname.hash ^ port.hash
|
56
65
|
end
|
data/lib/sshkit/version.rb
CHANGED
@@ -65,6 +65,17 @@ module SSHKit
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
def test_ssh_option_merge
|
69
|
+
a_host.ssh_options = { paranoid: true }
|
70
|
+
host_ssh_options = {}
|
71
|
+
SSHKit::Backend::Netssh.config.ssh_options = { forward_agent: false }
|
72
|
+
Netssh.new(a_host) do |host|
|
73
|
+
capture(:uname)
|
74
|
+
host_ssh_options = host.ssh_options
|
75
|
+
end.run
|
76
|
+
assert_equal({ forward_agent: false, paranoid: true }, host_ssh_options)
|
77
|
+
end
|
78
|
+
|
68
79
|
def test_execute_raises_on_non_zero_exit_status_and_captures_stdout_and_stderr
|
69
80
|
err = assert_raises SSHKit::Command::Failed do
|
70
81
|
Netssh.new(a_host) do |host|
|
data/test/unit/test_host.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'etc'
|
2
3
|
|
3
4
|
module SSHKit
|
4
5
|
|
@@ -41,6 +42,14 @@ module SSHKit
|
|
41
42
|
assert_equal 'example.com', h.hostname
|
42
43
|
end
|
43
44
|
|
45
|
+
def test_host_local
|
46
|
+
h = Host.new :local
|
47
|
+
assert h.local?
|
48
|
+
assert_nil h.port
|
49
|
+
assert_equal Etc.getpwuid.name, h.username
|
50
|
+
assert_equal 'localhost', h.hostname
|
51
|
+
end
|
52
|
+
|
44
53
|
def test_does_not_confuse_ipv6_hosts_with_port_specification
|
45
54
|
h = Host.new '[1fff:0:a88:85a3::ac1f]:8001'
|
46
55
|
assert_equal 8001, h.port
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sshkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Hambley
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-03-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-ssh
|
@@ -151,8 +151,8 @@ files:
|
|
151
151
|
- RELEASING.md
|
152
152
|
- Rakefile
|
153
153
|
- Vagrantfile
|
154
|
-
-
|
155
|
-
-
|
154
|
+
- examples/images/example_output.png
|
155
|
+
- examples/images/logo.png
|
156
156
|
- lib/core_ext/array.rb
|
157
157
|
- lib/core_ext/hash.rb
|
158
158
|
- lib/sshkit.rb
|
@@ -227,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
227
227
|
version: '0'
|
228
228
|
requirements: []
|
229
229
|
rubyforge_project:
|
230
|
-
rubygems_version: 2.
|
230
|
+
rubygems_version: 2.4.3
|
231
231
|
signing_key:
|
232
232
|
specification_version: 4
|
233
233
|
summary: SSHKit makes it easy to write structured, testable SSH commands in Ruby
|