sshkit 1.7.1 → 1.8.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/.travis.yml +2 -2
- data/BREAKING_API_WISHLIST.md +14 -0
- data/CHANGELOG.md +74 -0
- data/CONTRIBUTING.md +43 -0
- data/EXAMPLES.md +265 -169
- data/Gemfile +7 -0
- data/README.md +274 -9
- data/RELEASING.md +16 -8
- data/Rakefile +8 -0
- data/lib/sshkit.rb +0 -9
- data/lib/sshkit/all.rb +6 -4
- data/lib/sshkit/backends/abstract.rb +42 -42
- data/lib/sshkit/backends/connection_pool.rb +57 -8
- data/lib/sshkit/backends/local.rb +21 -50
- data/lib/sshkit/backends/netssh.rb +45 -98
- data/lib/sshkit/backends/printer.rb +3 -23
- data/lib/sshkit/backends/skipper.rb +4 -8
- data/lib/sshkit/color.rb +51 -20
- data/lib/sshkit/command.rb +68 -47
- data/lib/sshkit/configuration.rb +38 -5
- data/lib/sshkit/deprecation_logger.rb +17 -0
- data/lib/sshkit/formatters/abstract.rb +28 -4
- data/lib/sshkit/formatters/black_hole.rb +1 -2
- data/lib/sshkit/formatters/dot.rb +3 -10
- data/lib/sshkit/formatters/pretty.rb +31 -56
- data/lib/sshkit/formatters/simple_text.rb +6 -44
- data/lib/sshkit/host.rb +5 -6
- data/lib/sshkit/logger.rb +0 -1
- data/lib/sshkit/mapping_interaction_handler.rb +47 -0
- data/lib/sshkit/runners/parallel.rb +1 -1
- data/lib/sshkit/runners/sequential.rb +1 -1
- data/lib/sshkit/version.rb +1 -1
- data/sshkit.gemspec +0 -1
- data/test/functional/backends/test_local.rb +14 -1
- data/test/functional/backends/test_netssh.rb +58 -50
- data/test/helper.rb +2 -2
- data/test/unit/backends/test_abstract.rb +145 -0
- data/test/unit/backends/test_connection_pool.rb +27 -2
- data/test/unit/backends/test_printer.rb +47 -47
- data/test/unit/formatters/test_custom.rb +65 -0
- data/test/unit/formatters/test_dot.rb +25 -32
- data/test/unit/formatters/test_pretty.rb +114 -22
- data/test/unit/formatters/test_simple_text.rb +83 -0
- data/test/unit/test_color.rb +69 -5
- data/test/unit/test_command.rb +53 -18
- data/test/unit/test_command_map.rb +0 -4
- data/test/unit/test_configuration.rb +47 -7
- data/test/unit/test_coordinator.rb +45 -52
- data/test/unit/test_deprecation_logger.rb +38 -0
- data/test/unit/test_host.rb +3 -4
- data/test/unit/test_logger.rb +0 -1
- data/test/unit/test_mapping_interaction_handler.rb +101 -0
- metadata +37 -41
- data/lib/sshkit/utils/capture_output_methods.rb +0 -13
- data/test/functional/test_coordinator.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a957fee02819d1f897b5b77ee0311b7ad7d4dd9e
|
4
|
+
data.tar.gz: 2b84ecc03637cf6d23664fa8c00f98a165d12db4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a84d2b9ca8f28c5a32eb8a97b2b8f444f8c77885d07321eca21e6e62b2c9bfb2fbb35c59f02e6b9e920cf5ca6b91bb66e6e5965118f4269dfc2d22a5f292e950
|
7
|
+
data.tar.gz: 83a1190b38ca613ec201909b974c7f04ce0c9619f02493b45c29f04cde6e3bca1a98304ce5ec72a2858739e7effd3117ce11d1ea0fcc850855b8954c5d91a539
|
data/.travis.yml
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Breaking API Wishlist
|
2
|
+
|
3
|
+
SSHKit respects semantic versioning. This file is a place to record breaking API improvements
|
4
|
+
which could be considered at the next major release.
|
5
|
+
|
6
|
+
* Consider no longer stripping by default on `capture` [#249](https://github.com/capistrano/sshkit/pull/249)
|
7
|
+
|
8
|
+
## Deprecated code which could be deleted in a future major release
|
9
|
+
|
10
|
+
* [Abstract.background method](lib/sshkit/backends/abstract.rb#L43)
|
11
|
+
* [`@stderr`, `@stdout` attrs on `Command`](lib/sshkit/command.rb#L28)
|
12
|
+
|
13
|
+
## Cleanup when Ruby 1.9 support is dropped
|
14
|
+
* `to_a` can probably be removed from `"str".lines.to_a`, since `"str".lines` returns an `Array` under Ruby 2
|
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,80 @@ appear at the top.
|
|
8
8
|
* Add your entries below here, remember to credit yourself however you want
|
9
9
|
to be credited!
|
10
10
|
|
11
|
+
## 1.8.0
|
12
|
+
|
13
|
+
* add SSHKit::Backend::ConnectionPool#close_connections
|
14
|
+
[PR #285](https://github.com/capistrano/sshkit/pull/285)
|
15
|
+
@akm
|
16
|
+
* Clean up rubocop lint warnings
|
17
|
+
[PR #275](https://github.com/capistrano/sshkit/pull/275)
|
18
|
+
@cshaffer
|
19
|
+
* Prepend unused parameter names with an underscore
|
20
|
+
* Prefer “safe assignment in condition”
|
21
|
+
* Disambiguate regexp literals with parens
|
22
|
+
* Prefer `sprintf` over `String#%`
|
23
|
+
* No longer shadow `caller_line` variable in `DeprecationLogger`
|
24
|
+
* Rescue `StandardError` instead of `Exception`
|
25
|
+
* Remove useless `private` access modifier in `TestAbstract`
|
26
|
+
* Disambiguate block operator with parens
|
27
|
+
* Disambiguate between grouped expression and method params
|
28
|
+
* Remove assertion in `TestHost#test_assert_hosts_compare_equal` that compares something with itself
|
29
|
+
* Export environment variables and execute command in a subshell.
|
30
|
+
[PR #273](https://github.com/capistrano/sshkit/pull/273)
|
31
|
+
@kuon
|
32
|
+
* Introduce `log_command_start`, `log_command_data`, `log_command_exit` methods on `Formatter`
|
33
|
+
[PR #257](https://github.com/capistrano/sshkit/pull/257)
|
34
|
+
@robd
|
35
|
+
* Deprecate `@stdout` and `@stderr` accessors on `Command`
|
36
|
+
* Add support for deprecation logging options.
|
37
|
+
[README](README.md#deprecation-warnings),
|
38
|
+
[PR #258](https://github.com/capistrano/sshkit/pull/258)
|
39
|
+
@robd
|
40
|
+
* Quote environment variable values.
|
41
|
+
[PR #250](https://github.com/capistrano/sshkit/pull/250)
|
42
|
+
@Sinjo - Chris Sinjakli
|
43
|
+
* Simplified formatter hierarchy.
|
44
|
+
[PR #248](https://github.com/capistrano/sshkit/pull/248)
|
45
|
+
@robd
|
46
|
+
* `SimpleText` formatter now extends `Pretty`, rather than duplicating.
|
47
|
+
* Hide ANSI color escape sequences when outputting to a file.
|
48
|
+
[README](README.md#output-colors),
|
49
|
+
[Issue #245](https://github.com/capistrano/sshkit/issues/245),
|
50
|
+
[PR #246](https://github.com/capistrano/sshkit/pull/246)
|
51
|
+
@robd
|
52
|
+
* Now only color the output if it is associated with a tty,
|
53
|
+
or the `SSHKIT_COLOR` environment variable is set.
|
54
|
+
* Removed broken support for assigning an `IO` to the `output` config option.
|
55
|
+
[Issue #243](https://github.com/capistrano/sshkit/issues/243),
|
56
|
+
[PR #244](https://github.com/capistrano/sshkit/pull/244)
|
57
|
+
@robd
|
58
|
+
* Use `SSHKit.config.output = SSHKit::Formatter::SimpleText.new($stdin)` instead
|
59
|
+
* Added support for `:interaction_handler` option on commands.
|
60
|
+
[PR #234](https://github.com/capistrano/sshkit/pull/234),
|
61
|
+
[PR #242](https://github.com/capistrano/sshkit/pull/242)
|
62
|
+
@robd
|
63
|
+
* Removed partially supported `TRACE` log level.
|
64
|
+
[2aa7890](https://github.com/capistrano/sshkit/commit/2aa78905f0c521ad9f697e7a4ed04ba438d5ee78)
|
65
|
+
@robd
|
66
|
+
* Add support for the `:strip` option to the `capture` method and strip by default on the `Local` backend.
|
67
|
+
[PR #239](https://github.com/capistrano/sshkit/pull/239),
|
68
|
+
[PR #249](https://github.com/capistrano/sshkit/pull/249)
|
69
|
+
@robd
|
70
|
+
* The `Local` backend now strips by default to be consistent with the `Netssh` one.
|
71
|
+
* This reverses change [7d15a9a](https://github.com/capistrano/sshkit/commit/7d15a9aebfcc43807c8151bf6f3a4bc038ce6218) to the `Local` capture API to remove stripping by default.
|
72
|
+
* If you require the raw, unstripped output, pass the `strip: false` option: `capture(:ls, strip: false)`
|
73
|
+
* Simplified backend hierarchy.
|
74
|
+
[PR #235](https://github.com/capistrano/sshkit/pull/235),
|
75
|
+
[PR #237](https://github.com/capistrano/sshkit/pull/237)
|
76
|
+
@robd
|
77
|
+
* Moved duplicate implementations of `make`, `rake`, `test`, `capture`, `background` on to `Abstract` backend.
|
78
|
+
* Backend implementations now only need to implement `execute_command`, `upload!` and `download!`
|
79
|
+
* Removed `Printer` from backend hierarchy for `Local` and `Netssh` backends (they now just extend `Abstract`)
|
80
|
+
* Removed unused `Net::SSH:LogLevelShim`
|
81
|
+
* Removed dependency on the `colorize` gem. SSHKit now implements its own ANSI color logic, with no external dependencies. Note that SSHKit now only supports the `:bold` or plain modes. Other modes will be gracefully ignored. [#263](https://github.com/capistrano/sshkit/issues/263)
|
82
|
+
* New API for setting the formatter: `use_format`. This differs from `format=` in that it accepts options or arguments that will be passed to the formatter's constructor. The `format=` syntax will be deprecated in a future release. [#295](https://github.com/capistrano/sshkit/issues/295)
|
83
|
+
* SSHKit now immediately raises a `NameError` if you try to set a formatter that does not exist. [#295](https://github.com/capistrano/sshkit/issues/295)
|
84
|
+
|
11
85
|
## 1.7.1
|
12
86
|
|
13
87
|
* Fix a regression in 1.7.0 that caused command completion messages to be removed from log output. @mattbrictson
|
data/CONTRIBUTING.md
CHANGED
@@ -2,3 +2,46 @@
|
|
2
2
|
|
3
3
|
* [**Don't** push your pull request](http://www.igvita.com/2011/12/19/dont-push-your-pull-requests/)
|
4
4
|
* [**Do** write a good commit message](http://365git.tumblr.com/post/3308646748/writing-git-commit-messages)
|
5
|
+
|
6
|
+
## Ruby versions
|
7
|
+
|
8
|
+
You can see the current ruby versions we support in [.travis.yml](.travis.yml).
|
9
|
+
Obviously, any language features you use must be available in the oldest version we support.
|
10
|
+
Therefore, it's often helpful to develop / test against the oldest version to avoid accidentally
|
11
|
+
using unsupported features.
|
12
|
+
|
13
|
+
## Tests
|
14
|
+
|
15
|
+
SSHKit has a unit test suite and a functional test suite. Some functional tests run against
|
16
|
+
[Vagrant](https://www.vagrantup.com/) VMs. If possible, you should make sure that the
|
17
|
+
tests pass for each commit by running `rake` in the sshkit directory. This is in case we
|
18
|
+
need to cherry pick commits or rebase. You should ensure the tests pass, (preferably on
|
19
|
+
the minimum and maximum ruby version), before creating a PR.
|
20
|
+
|
21
|
+
Pull requests are much more likely to be accepted if you write a tests for the new functionality
|
22
|
+
you are adding. If you are fixing a bug, it would be great if you could add a test to
|
23
|
+
expose the bug you are fixing to show that the behaviour is fixed by your changes.
|
24
|
+
|
25
|
+
We use [Travis CI](https://travis-ci.org/capistrano/sshkit) to run the tests on different
|
26
|
+
ruby versions.
|
27
|
+
|
28
|
+
**The Travis build does not run the functional tests,
|
29
|
+
so make sure all the tests pass locally before creating your PR.**
|
30
|
+
|
31
|
+
## Changelog
|
32
|
+
|
33
|
+
Most changes should have an accompanying entry in the [CHANGELOG](CHANGELOG.md), unless they
|
34
|
+
are minor documentation / config changes. This is incredibly important so that our users can
|
35
|
+
see the affect of new versions without having to trawl through the commits.
|
36
|
+
|
37
|
+
## Breaking changes
|
38
|
+
|
39
|
+
We adhere to [semver](http://semver.org/) so breaking changes will require a major release.
|
40
|
+
For breaking changes, it would normally be helpful to discuss them by raising a 'Proposal' issue
|
41
|
+
or PR with examples of the new API you're proposing
|
42
|
+
[before doing a lot of work](https://www.igvita.com/2011/12/19/dont-push-your-pull-requests/).
|
43
|
+
Bear in mind that breaking changes may require many hundreds / thousands of users to update their
|
44
|
+
code.
|
45
|
+
|
46
|
+
You can use the [BREAKING_API_WISHLIST](BREAKING_API_WISHLIST.md) to record issues / PRs where
|
47
|
+
API changes have been discussed, and not implemented.
|
data/EXAMPLES.md
CHANGED
@@ -2,59 +2,71 @@
|
|
2
2
|
|
3
3
|
## Run a command as a different user
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
```ruby
|
6
|
+
on hosts do |host|
|
7
|
+
as 'www-data' do
|
8
|
+
puts capture(:whoami)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
```
|
10
12
|
|
11
13
|
## Run with default environmental variables
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
```ruby
|
16
|
+
SSHKit.config.default_env = { path: '/usr/local/libexec/bin:$PATH' }
|
17
|
+
on hosts do |host|
|
18
|
+
puts capture(:env)
|
19
|
+
end
|
20
|
+
```
|
17
21
|
|
18
22
|
## Run a command in a different directory
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
```ruby
|
25
|
+
on hosts do |host|
|
26
|
+
within '/var/log' do
|
27
|
+
puts capture(:head, '-n5', 'messages')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
```
|
25
31
|
|
26
32
|
## Run a command with specific environmental variables
|
27
33
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
34
|
+
```ruby
|
35
|
+
on hosts do |host|
|
36
|
+
with rack_env: :test do
|
37
|
+
puts capture("env | grep RACK_ENV")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
33
41
|
|
34
42
|
## Print some arbitrary output with the logging methods
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
+
```ruby
|
45
|
+
on hosts do |host|
|
46
|
+
f = '/some/file'
|
47
|
+
if test("[ -d #{f} ]")
|
48
|
+
execute :touch, f
|
49
|
+
else
|
50
|
+
info "#{f} already exists on #{host}!"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
44
54
|
|
45
55
|
The `debug()`, `info()`, `warn()`, `error()` and `fatal()` honor the current
|
46
56
|
log level of `SSHKit.config.output_verbosity`
|
47
57
|
|
48
58
|
## Run a command in a different directory as a different user
|
49
59
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
60
|
+
```ruby
|
61
|
+
on hosts do |host|
|
62
|
+
as 'www-data' do
|
63
|
+
within '/var/log' do
|
64
|
+
puts capture(:whoami)
|
65
|
+
puts capture(:pwd)
|
57
66
|
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
58
70
|
|
59
71
|
This will output:
|
60
72
|
|
@@ -64,31 +76,59 @@ This will output:
|
|
64
76
|
**Note:** This example is a bit misleading, as the `www-data` user doesn't
|
65
77
|
have a shell defined, one cannot switch to that user.
|
66
78
|
|
79
|
+
## Run a command which requires interaction between the client and the server
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
on hosts do |host|
|
83
|
+
execute(:passwd, interaction_handler: {
|
84
|
+
'(current) UNIX password: ' => "old_pw\n",
|
85
|
+
'Enter new UNIX password: ' => "new_pw\n",
|
86
|
+
'Retype new UNIX password: ' => "new_pw\n",
|
87
|
+
'passwd: password updated successfully' => nil # For stdout/stderr which can be ignored, map a nil input
|
88
|
+
})
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
## Download a file from disk
|
93
|
+
```ruby
|
94
|
+
on roles(:all) do
|
95
|
+
puts 'Downloading DB Backup File'
|
96
|
+
date_path = Date.today.strftime("%Y/%m/%d")
|
97
|
+
download! "/var/mysql-backup/#{date_path}/my-awesome-db.sql.gz", "my-awesome-db.sql.gz"
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
67
101
|
## Upload a file from disk
|
68
102
|
|
69
|
-
|
70
|
-
|
71
|
-
|
103
|
+
```ruby
|
104
|
+
on hosts do |host|
|
105
|
+
upload! '/config/database.yml', '/opt/my_project/shared/database.yml'
|
106
|
+
end
|
107
|
+
```
|
72
108
|
|
73
109
|
**Note:** The `upload!()` method doesn't honor the values of `within()`, `as()`
|
74
110
|
etc, this will be improved as the library matures, but we're not there yet.
|
75
111
|
|
76
112
|
## Upload a file from a stream
|
77
113
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
114
|
+
```ruby
|
115
|
+
on hosts do |host|
|
116
|
+
file = File.open('/config/database.yml')
|
117
|
+
io = StringIO.new(....)
|
118
|
+
upload! file, '/opt/my_project/shared/database.yml'
|
119
|
+
upload! io, '/opt/my_project/shared/io.io.io'
|
120
|
+
end
|
121
|
+
```
|
84
122
|
|
85
123
|
The IO streaming is useful for uploading something rather than "cat"ing it,
|
86
124
|
for example
|
87
125
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
126
|
+
```ruby
|
127
|
+
on hosts do |host|
|
128
|
+
contents = StringIO.new('ALL ALL = (ALL) NOPASSWD: ALL')
|
129
|
+
upload! contents, '/etc/sudoers.d/yolo'
|
130
|
+
end
|
131
|
+
```
|
92
132
|
|
93
133
|
This spares one from having to figure out the correct escaping sequences for
|
94
134
|
something like "echo(:cat, '...?...', '> /etc/sudoers.d/yolo')".
|
@@ -98,9 +138,11 @@ etc, this will be improved as the library matures, but we're not there yet.
|
|
98
138
|
|
99
139
|
## Upload a directory of files
|
100
140
|
|
101
|
-
|
102
|
-
|
103
|
-
|
141
|
+
```ruby
|
142
|
+
on hosts do |host|
|
143
|
+
upload! '.', '/tmp/mypwd', recursive: true
|
144
|
+
end
|
145
|
+
```
|
104
146
|
|
105
147
|
In this case the `recursive: true` option mirrors the same options which are
|
106
148
|
available to [`Net::{SCP,SFTP}`](http://net-ssh.github.io/net-scp/).
|
@@ -110,25 +152,29 @@ available to [`Net::{SCP,SFTP}`](http://net-ssh.github.io/net-scp/).
|
|
110
152
|
Setting global SSH options, these will be overwritten by options set on the
|
111
153
|
individual hosts:
|
112
154
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
155
|
+
```ruby
|
156
|
+
SSHKit::Backend::Netssh.configure do |ssh|
|
157
|
+
ssh.connection_timeout = 30
|
158
|
+
ssh.ssh_options = {
|
159
|
+
keys: %w(/home/user/.ssh/id_rsa),
|
160
|
+
forward_agent: false,
|
161
|
+
auth_methods: %w(publickey password)
|
162
|
+
}
|
163
|
+
end
|
164
|
+
```
|
121
165
|
|
122
166
|
## Run a command with a different effective group ID
|
123
167
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
end
|
168
|
+
```ruby
|
169
|
+
on hosts do |host|
|
170
|
+
as user: 'www-data', group: 'project-group' do
|
171
|
+
within '/var/log' do
|
172
|
+
execute :touch, 'somefile'
|
173
|
+
execute :ls, '-l'
|
131
174
|
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
```
|
132
178
|
|
133
179
|
One will see that the created file is owned by the user `www-data` and the
|
134
180
|
group `project-group`.
|
@@ -138,14 +184,16 @@ scripts for deployment between team members without sharing logins.
|
|
138
184
|
|
139
185
|
## Stack directory nestings
|
140
186
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
187
|
+
```ruby
|
188
|
+
on hosts do
|
189
|
+
within "/var" do
|
190
|
+
puts capture(:pwd)
|
191
|
+
within :log do
|
192
|
+
puts capture(:pwd)
|
148
193
|
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
```
|
149
197
|
|
150
198
|
This will output:
|
151
199
|
|
@@ -160,17 +208,34 @@ joined according to the expectations of the machine receiving the commands.
|
|
160
208
|
|
161
209
|
## Do not care about the host block
|
162
210
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
211
|
+
```ruby
|
212
|
+
on hosts do
|
213
|
+
# The |host| argument is optional, it will
|
214
|
+
# be nil in the block if not passed
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
## Change the output formatter
|
167
219
|
|
168
|
-
|
220
|
+
```ruby
|
221
|
+
# The default format is pretty, which outputs colored text
|
222
|
+
SSHKit.config.format = :pretty
|
169
223
|
|
170
|
-
|
224
|
+
# Text with no coloring
|
225
|
+
SSHKit.config.format = :simpletext
|
226
|
+
|
227
|
+
# Red / Green dots for each completed step
|
228
|
+
SSHKit.config.format = :dot
|
229
|
+
|
230
|
+
# No output
|
231
|
+
SSHKit.config.format = :blackhole
|
232
|
+
```
|
171
233
|
|
172
234
|
## Implement a dirt-simple formatter class
|
173
235
|
|
236
|
+
```ruby
|
237
|
+
module SSHKit
|
238
|
+
module Formatter
|
174
239
|
class MyFormatter < SSHKit::Formatter::Abstract
|
175
240
|
def write(obj)
|
176
241
|
case obj.is_a? SSHKit::Command
|
@@ -178,40 +243,53 @@ joined according to the expectations of the machine receiving the commands.
|
|
178
243
|
end
|
179
244
|
end
|
180
245
|
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# If your formatter is defined in the SSHKit::Formatter module configure with the format option:
|
250
|
+
SSHKit.config.format = :myformatter
|
181
251
|
|
182
|
-
|
183
|
-
|
184
|
-
|
252
|
+
# Or configure the output directly
|
253
|
+
SSHKit.config.output = MyFormatter.new($stdout)
|
254
|
+
SSHKit.config.output = MyFormatter.new(SSHKit.config.output)
|
255
|
+
SSHKit.config.output = MyFormatter.new(File.open('log/deploy.log', 'wb'))
|
256
|
+
```
|
185
257
|
|
186
258
|
## Set a password for a host.
|
187
259
|
|
188
|
-
|
189
|
-
|
260
|
+
```ruby
|
261
|
+
host = SSHKit::Host.new('user@example.com')
|
262
|
+
host.password = "hackme"
|
190
263
|
|
191
|
-
|
192
|
-
|
193
|
-
|
264
|
+
on host do |host|
|
265
|
+
puts capture(:echo, "I don't care about security!")
|
266
|
+
end
|
267
|
+
```
|
194
268
|
|
195
269
|
## Execute and raise an error if something goes wrong
|
196
270
|
|
197
|
-
|
198
|
-
|
199
|
-
|
271
|
+
```ruby
|
272
|
+
on hosts do |host|
|
273
|
+
execute(:echo, '"Example Message!" 1>&2; false')
|
274
|
+
end
|
275
|
+
```
|
200
276
|
|
201
277
|
This will raise `SSHKit::Command::Failed` with the `#message` "Example Message!"
|
202
278
|
which will cause the command to abort.
|
203
279
|
|
204
280
|
## Make a test, or run a command which may fail without raising an error:
|
205
281
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
else
|
212
|
-
execute :git, :clone, 'some-repository', '/opt/sites'
|
213
|
-
end
|
282
|
+
```ruby
|
283
|
+
on hosts do |host|
|
284
|
+
if test "[ -d /opt/sites ]"
|
285
|
+
within "/opt/sites" do
|
286
|
+
execute :git, :pull
|
214
287
|
end
|
288
|
+
else
|
289
|
+
execute :git, :clone, 'some-repository', '/opt/sites'
|
290
|
+
end
|
291
|
+
end
|
292
|
+
```
|
215
293
|
|
216
294
|
The `test()` command behaves exactly the same as execute however will return
|
217
295
|
false if the command exits with a non-zero exit (as `man 1 test` does). As it
|
@@ -219,24 +297,28 @@ returns boolean it can be used to direct the control flow within the block.
|
|
219
297
|
|
220
298
|
## Do something different on one host, or another depending on a host property
|
221
299
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
300
|
+
```ruby
|
301
|
+
host1 = SSHKit::Host.new 'user@example.com'
|
302
|
+
host2 = SSHKit::Host.new 'user@example.org'
|
303
|
+
|
304
|
+
on hosts do |host|
|
305
|
+
target = "/var/www/sites/"
|
306
|
+
if host.hostname =~ /org/
|
307
|
+
target += "dotorg"
|
308
|
+
else
|
309
|
+
target += "dotcom"
|
310
|
+
end
|
311
|
+
execute! :git, :clone, "git@git.#{host.hostname}", target
|
312
|
+
end
|
313
|
+
```
|
234
314
|
|
235
315
|
## Connect to a host in the easiest possible way
|
236
316
|
|
237
|
-
|
238
|
-
|
239
|
-
|
317
|
+
```ruby
|
318
|
+
on 'example.com' do |host|
|
319
|
+
execute :uptime
|
320
|
+
end
|
321
|
+
```
|
240
322
|
|
241
323
|
This will resolve the `example.com` hostname into a `SSHKit::Host` object, and
|
242
324
|
try to pull up the correct configuration for it.
|
@@ -247,13 +329,15 @@ try to pull up the correct configuration for it.
|
|
247
329
|
If the command you attempt to call contains a space character it won't be
|
248
330
|
mapped:
|
249
331
|
|
250
|
-
|
251
|
-
|
252
|
-
|
332
|
+
```ruby
|
333
|
+
Command.new(:git, :push, :origin, :master).to_s
|
334
|
+
# => /usr/bin/env git push origin master
|
335
|
+
# (also: execute(:git, :push, :origin, :master)
|
253
336
|
|
254
|
-
|
255
|
-
|
256
|
-
|
337
|
+
Command.new("git push origin master").to_s
|
338
|
+
# => git push origin master
|
339
|
+
# (also: execute("git push origin master"))
|
340
|
+
```
|
257
341
|
|
258
342
|
This can be used to access shell builtins (such as `if` and `test`)
|
259
343
|
|
@@ -262,14 +346,16 @@ This can be used to access shell builtins (such as `if` and `test`)
|
|
262
346
|
|
263
347
|
An extension of the behaviour above, if you write a command like this:
|
264
348
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
349
|
+
```ruby
|
350
|
+
c = Command.new <<-EOCOMMAND
|
351
|
+
if test -d /var/log
|
352
|
+
then echo "Directory Exists"
|
353
|
+
fi
|
354
|
+
EOCOMMAND
|
355
|
+
c.to_s
|
356
|
+
# => if test -d /var/log; then echo "Directory Exists; fi
|
357
|
+
# (also: execute <<- EOCOMMAND........))
|
358
|
+
```
|
273
359
|
|
274
360
|
**Note:** The logic which reformats the script into a oneliner may be naïve, but in all
|
275
361
|
known test cases, it works. The key thing is that `if` is not mapped to
|
@@ -279,31 +365,35 @@ known test cases, it works. The key thing is that `if` is not mapped to
|
|
279
365
|
|
280
366
|
Into the `Rakefile` simply put something like:
|
281
367
|
|
282
|
-
|
368
|
+
```ruby
|
369
|
+
require 'sshkit/dsl'
|
283
370
|
|
284
|
-
|
371
|
+
SSHKit.config.command_map[:rake] = "./bin/rake"
|
285
372
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
end
|
296
|
-
end
|
373
|
+
desc "Deploy the site, pulls from Git, migrate the db and precompile assets, then restart Passenger."
|
374
|
+
task :deploy do
|
375
|
+
on "example.com" do |host|
|
376
|
+
within "/opt/sites/example.com" do
|
377
|
+
execute :git, :pull
|
378
|
+
execute :bundle, :install, '--deployment'
|
379
|
+
execute :rake, 'db:migrate'
|
380
|
+
execute :rake, 'assets:precompile'
|
381
|
+
execute :touch, 'tmp/restart.txt'
|
297
382
|
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
```
|
298
386
|
|
299
387
|
## Using without the DSL
|
300
388
|
|
301
389
|
The *Coordinator* will resolve all hosts into *Host* objects, you can mix and
|
302
390
|
match.
|
303
391
|
|
304
|
-
|
305
|
-
|
306
|
-
|
392
|
+
```ruby
|
393
|
+
Coordinator.new("one.example.com", SSHKit::Host.new('two.example.com')).each in: :sequence do
|
394
|
+
puts capture :uptime
|
395
|
+
end
|
396
|
+
```
|
307
397
|
|
308
398
|
You might also look at `./lib/sshkit/dsl.rb` where you can see almost the
|
309
399
|
exact code as above, which implements the `on()` method.
|
@@ -312,23 +402,25 @@ exact code as above, which implements the `on()` method.
|
|
312
402
|
|
313
403
|
Implemented since `v0.0.6`
|
314
404
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
405
|
+
```ruby
|
406
|
+
servers = %w{one.example.com two.example.com
|
407
|
+
three.example.com four.example.com}.collect do |s|
|
408
|
+
h = SSHKit::Host.new(s)
|
409
|
+
if s.match /(one|two)/
|
410
|
+
h.properties.roles = [:web]
|
411
|
+
else
|
412
|
+
h.properties.roles = [:app]
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
on servers do |host|
|
417
|
+
if host.properties.roles.include?(:web)
|
418
|
+
# Do something pertinent to web servers
|
419
|
+
elsif host.properties.roles.include?(:app)
|
420
|
+
# Do something pertinent to application servers
|
421
|
+
end
|
422
|
+
end
|
423
|
+
```
|
332
424
|
|
333
425
|
The `SSHKit::Host#properties` is an [`OpenStruct`](http://ruby-doc.org/stdlib-1.9.3/libdoc/ostruct/rdoc/OpenStruct.html)
|
334
426
|
which is not verified or validated in any way, it is up to you, or your
|
@@ -338,16 +430,20 @@ library to attach meanings or conventions to this mechanism.
|
|
338
430
|
|
339
431
|
Replace `on` with `run_locally`
|
340
432
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
433
|
+
```ruby
|
434
|
+
run_locally do
|
435
|
+
within '/tmp' do
|
436
|
+
execute :whoami
|
437
|
+
end
|
438
|
+
end
|
439
|
+
```
|
346
440
|
|
347
441
|
You can achieve the same thing with `on(:local)`
|
348
442
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
443
|
+
```ruby
|
444
|
+
on(:local) do
|
445
|
+
within '/tmp' do
|
446
|
+
execute :whoami
|
447
|
+
end
|
448
|
+
end
|
449
|
+
```
|