sshkit 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +26 -0
- data/EXAMPLES.md +25 -9
- data/lib/sshkit.rb +4 -3
- data/lib/sshkit/backends/abstract.rb +7 -2
- data/lib/sshkit/backends/netssh.rb +5 -0
- data/lib/sshkit/command.rb +10 -1
- data/lib/sshkit/host.rb +1 -1
- data/lib/sshkit/runners/parallel.rb +2 -0
- data/lib/sshkit/version.rb +1 -1
- data/test/helper.rb +1 -1
- data/test/integration/backends/test_netssh.rb +17 -19
- data/test/unit/test_command.rb +11 -3
- metadata +1 -1
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,32 @@
|
|
3
3
|
This file is written in reverse chronological order, newer releases will
|
4
4
|
appear at the top.
|
5
5
|
|
6
|
+
## 0.0.7
|
7
|
+
|
8
|
+
* DSL method `execute()` will now raise `SSHKit::Command::Failed` when the
|
9
|
+
exit status is non-zero. The message of the exception will be whatever the
|
10
|
+
process had written to stdout.
|
11
|
+
* New DSL method `test()` behaves as `execute()` used to until this version.
|
12
|
+
* `Command` now raises an error in `#exit_status=()` if the exit status given
|
13
|
+
is not zero. (see below)
|
14
|
+
* All errors raised by error conditions of SSHKit are defined as subclasses of
|
15
|
+
`SSHKit::StandardError` which is itself a subclass of `StandardError`.
|
16
|
+
|
17
|
+
The `Command` objects can be set to not raise, by passing `raise_on_non_zero_exit: false`
|
18
|
+
when instantiating them, this is exactly what `test()` does internally.
|
19
|
+
|
20
|
+
Example:
|
21
|
+
|
22
|
+
on hosts do |host
|
23
|
+
if test "[ -d /opt/sites ]" do
|
24
|
+
within "/opt/sites" do
|
25
|
+
execute :git, :pull
|
26
|
+
end
|
27
|
+
else
|
28
|
+
execute :git, :clone, 'some-repository', '/opt/sites'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
6
32
|
## 0.0.6
|
7
33
|
|
8
34
|
* Support arbitrary properties on Host objects. (see below)
|
data/EXAMPLES.md
CHANGED
@@ -43,7 +43,7 @@ This will output:
|
|
43
43
|
**Note:** This example is a bit misleading, as the `www-data` user doesn't
|
44
44
|
have a shell defined, one cannot switch to that user.
|
45
45
|
|
46
|
-
## Stack directory nestings
|
46
|
+
## Stack directory nestings
|
47
47
|
|
48
48
|
on hosts do
|
49
49
|
in "/var" do
|
@@ -65,7 +65,7 @@ leading slashes. It may be misleading as the `File.join()` is performed on the
|
|
65
65
|
machine running the code, if that's a Windows box, the paths may be incorrectly
|
66
66
|
joined according to the expectations of the machine receiving the commands.
|
67
67
|
|
68
|
-
## Do not care about the host block
|
68
|
+
## Do not care about the host block
|
69
69
|
|
70
70
|
on hosts do
|
71
71
|
# The |host| argument is optional, it will
|
@@ -76,7 +76,7 @@ joined according to the expectations of the machine receiving the commands.
|
|
76
76
|
|
77
77
|
SSHKit.config.output = File.open('/dev/null')
|
78
78
|
|
79
|
-
## Implement a dirt-simple formatter class
|
79
|
+
## Implement a dirt-simple formatter class
|
80
80
|
|
81
81
|
class MyFormatter < SSHKit::Formatter::Abstract
|
82
82
|
def write(obj)
|
@@ -99,16 +99,32 @@ joined according to the expectations of the machine receiving the commands.
|
|
99
99
|
puts capture(:echo, "I don't care about security!")
|
100
100
|
end
|
101
101
|
|
102
|
-
## Execute and raise an error if something goes wrong
|
102
|
+
## Execute and raise an error if something goes wrong
|
103
103
|
|
104
104
|
on hosts do |host|
|
105
105
|
execute!(:echo, '"Example Message!" 1>&2; false')
|
106
106
|
end
|
107
107
|
|
108
|
-
This will raise `SSHKit::
|
109
|
-
will cause the command to abort.
|
108
|
+
This will raise `SSHKit::Command:Failed` with the `#message` "Example Message!"`
|
109
|
+
which will cause the command to abort.
|
110
110
|
|
111
|
-
##
|
111
|
+
## Make a test, or run a command which may fail without raising an error:
|
112
|
+
|
113
|
+
on hosts do |host
|
114
|
+
if test "[ -d /opt/sites ]" do
|
115
|
+
within "/opt/sites" do
|
116
|
+
execute :git, :pull
|
117
|
+
end
|
118
|
+
else
|
119
|
+
execute :git, :clone, 'some-repository', '/opt/sites'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
The `test()` command behaves exactly the same as execute however will return
|
124
|
+
false if the command exits with a non-zero exit (as `man 1 test` does). As ti
|
125
|
+
returns boolean it can be used to direct the control flow within the block.
|
126
|
+
|
127
|
+
## Do something different on one host, or another depending on a host property
|
112
128
|
|
113
129
|
host1 = SSHKit::Host.new 'user@example.com'
|
114
130
|
host2 = SSHKit::Host.new 'user@example.org'
|
@@ -123,7 +139,7 @@ will cause the command to abort.
|
|
123
139
|
execute! :git, :clone, "git@git.#{host.hostname}", target
|
124
140
|
end
|
125
141
|
|
126
|
-
## Connect to a host in the easiest possible way
|
142
|
+
## Connect to a host in the easiest possible way
|
127
143
|
|
128
144
|
on 'example.com' do |host|
|
129
145
|
execute :uptime
|
@@ -133,7 +149,7 @@ This will resolve the `example.com` hostname into a `SSHKit::Host` object, and
|
|
133
149
|
try to pull up the correct configuration for it.
|
134
150
|
|
135
151
|
|
136
|
-
## Run a command without it being command-mapped
|
152
|
+
## Run a command without it being command-mapped
|
137
153
|
|
138
154
|
If the command you attempt to call contains a space character it won't be
|
139
155
|
mapped:
|
data/lib/sshkit.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module SSHKit
|
2
2
|
module Backend
|
3
3
|
|
4
|
-
MethodUnavailableError = Class.new(
|
4
|
+
MethodUnavailableError = Class.new(SSHKit::StandardError)
|
5
5
|
|
6
6
|
class Abstract
|
7
7
|
|
@@ -25,6 +25,10 @@ module SSHKit
|
|
25
25
|
raise MethodUnavailableError
|
26
26
|
end
|
27
27
|
|
28
|
+
def test(command, args=[])
|
29
|
+
raise MethodUnavailableError
|
30
|
+
end
|
31
|
+
|
28
32
|
def execute(command, args=[])
|
29
33
|
raise MethodUnavailableError
|
30
34
|
end
|
@@ -71,7 +75,8 @@ module SSHKit
|
|
71
75
|
private
|
72
76
|
|
73
77
|
def command(*args)
|
74
|
-
|
78
|
+
options = args.extract_options!
|
79
|
+
SSHKit::Command.new(*[*args, options.merge({in: @pwd.nil? ? nil : File.join(@pwd), env: @env, host: @host, user: @user})])
|
75
80
|
end
|
76
81
|
|
77
82
|
def connection
|
@@ -11,6 +11,11 @@ module SSHKit
|
|
11
11
|
instance_exec(host, &@block)
|
12
12
|
end
|
13
13
|
|
14
|
+
def test(*args)
|
15
|
+
options = args.extract_options!.merge(raise_on_non_zero_exit: false)
|
16
|
+
_execute(*[*args, options]).success?
|
17
|
+
end
|
18
|
+
|
14
19
|
def execute(*args)
|
15
20
|
_execute(*args).success?
|
16
21
|
end
|
data/lib/sshkit/command.rb
CHANGED
@@ -31,6 +31,8 @@ module SSHKit
|
|
31
31
|
# @author Lee Hambley
|
32
32
|
class Command
|
33
33
|
|
34
|
+
Failed = Class.new(SSHKit::StandardError)
|
35
|
+
|
34
36
|
attr_reader :command, :args, :options, :started_at, :started, :exit_status
|
35
37
|
|
36
38
|
attr_accessor :stdout, :stderr
|
@@ -44,7 +46,7 @@ module SSHKit
|
|
44
46
|
#
|
45
47
|
def initialize(*args)
|
46
48
|
raise ArgumentError, "May not pass no arguments to Command.new" if args.empty?
|
47
|
-
@options = args.extract_options!
|
49
|
+
@options = default_options.merge(args.extract_options!)
|
48
50
|
@command = args.shift.to_s.strip.to_sym
|
49
51
|
@args = args
|
50
52
|
@options.symbolize_keys!
|
@@ -83,6 +85,9 @@ module SSHKit
|
|
83
85
|
def exit_status=(new_exit_status)
|
84
86
|
@finished_at = Time.now
|
85
87
|
@exit_status = new_exit_status
|
88
|
+
if options[:raise_on_non_zero_exit] && exit_status > 0
|
89
|
+
raise Failed, stderr.empty? ? "No messages written to stderr" : stderr.strip
|
90
|
+
end
|
86
91
|
end
|
87
92
|
|
88
93
|
def runtime
|
@@ -136,6 +141,10 @@ module SSHKit
|
|
136
141
|
|
137
142
|
private
|
138
143
|
|
144
|
+
def default_options
|
145
|
+
{ raise_on_non_zero_exit: true }
|
146
|
+
end
|
147
|
+
|
139
148
|
def sanitize_command!
|
140
149
|
command.to_s.strip!
|
141
150
|
if command.to_s.match("\n")
|
data/lib/sshkit/host.rb
CHANGED
data/lib/sshkit/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -17,7 +17,12 @@ module SSHKit
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
class
|
20
|
+
class TestNetssh < FunctionalTest
|
21
|
+
|
22
|
+
def setup
|
23
|
+
super
|
24
|
+
SSHKit.config.output = SSHKit::Formatter::BlackHole.new($stdout)
|
25
|
+
end
|
21
26
|
|
22
27
|
def block_to_run
|
23
28
|
lambda do |host|
|
@@ -70,26 +75,19 @@ module SSHKit
|
|
70
75
|
end
|
71
76
|
end
|
72
77
|
|
73
|
-
def
|
74
|
-
|
78
|
+
def test_execute_raises_on_non_zero_exit_status_and_captures_stderr
|
79
|
+
err = assert_raises SSHKit::Command::Failed do
|
80
|
+
Netssh.new(a_host) do |host|
|
81
|
+
execute :echo, "'Test capturing stderr' 1>&2; false"
|
82
|
+
end.run
|
83
|
+
end
|
84
|
+
assert_equal "Test capturing stderr", err.message
|
75
85
|
end
|
76
86
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
# be passed to command (raise_errors: false), which could also be
|
82
|
-
# inherited through Backend#command and specified on the (not yet
|
83
|
-
# existing) backend configurations.
|
84
|
-
assert_raises RuntimeError do
|
85
|
-
File.open('/dev/null', 'w') do |dnull|
|
86
|
-
SSHKit.capture_output(dnull) do
|
87
|
-
Netssh.new(a_host) do |host|
|
88
|
-
execute :false
|
89
|
-
end.run
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
87
|
+
def test_test_does_not_raise_on_non_zero_exit_status
|
88
|
+
Netssh.new(a_host) do |host|
|
89
|
+
test :false
|
90
|
+
end.run
|
93
91
|
end
|
94
92
|
|
95
93
|
end
|
data/test/unit/test_command.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'sshkit'
|
2
3
|
|
3
4
|
module SSHKit
|
4
5
|
class TestCommand < UnitTest
|
@@ -51,7 +52,7 @@ module SSHKit
|
|
51
52
|
end
|
52
53
|
|
53
54
|
def test_complete?
|
54
|
-
c = Command.new(:whoami)
|
55
|
+
c = Command.new(:whoami, raise_on_non_zero_exit: false)
|
55
56
|
refute c.complete?
|
56
57
|
c.exit_status = 1
|
57
58
|
assert c.complete?
|
@@ -69,7 +70,7 @@ module SSHKit
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def test_failure?
|
72
|
-
c = Command.new(:whoami)
|
73
|
+
c = Command.new(:whoami, raise_on_non_zero_exit: false)
|
73
74
|
refute c.failure?
|
74
75
|
refute c.failed?
|
75
76
|
c.exit_status = 1
|
@@ -93,7 +94,7 @@ module SSHKit
|
|
93
94
|
end
|
94
95
|
|
95
96
|
def test_setting_exit_status
|
96
|
-
c = Command.new(:whoami)
|
97
|
+
c = Command.new(:whoami, raise_on_non_zero_exit: false)
|
97
98
|
assert_equal nil, c.exit_status
|
98
99
|
assert c.exit_status = 1
|
99
100
|
assert_equal 1, c.exit_status
|
@@ -109,5 +110,12 @@ module SSHKit
|
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
113
|
+
def test_command_raises_command_failed_error_when_non_zero_exit
|
114
|
+
error = assert_raises SSHKit::Command::Failed do
|
115
|
+
Command.new(:whoami).exit_status = 1
|
116
|
+
end
|
117
|
+
assert_equal "No messages written to stderr", error.message
|
118
|
+
end
|
119
|
+
|
112
120
|
end
|
113
121
|
end
|