open4ssh 0.1.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 +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +230 -0
- data/Rakefile +8 -0
- data/lib/open4ssh/version.rb +3 -0
- data/lib/open4ssh.rb +82 -0
- data/open4ssh.gemspec +35 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 78635fba401d382c7a6cf79897cb94e89ec54175
|
4
|
+
data.tar.gz: 3a33cebef1a16d8071d4dc2c7aefa849a6f60888
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f380979bfca37db680e5bf1e0f7ba1c4966279ee5e879caafbc73216d261a48ebab5905f8641ca1c8c9acf09029d5a42420a35f55b90ff975551482f18aa5ed
|
7
|
+
data.tar.gz: 0e11987f6bcdb82f4dd1c3586dade177189dfc8a6495fa89913afb8f72868ed62676c75d0f7129afb577b4b14c85b4238042da2e5d698b19d987c6e60e9f90cb
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Nane Kratzke
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
# Open4ssh
|
2
|
+
|
3
|
+
[Open4ssh](https://github.com/nkratzke/open4ssh) is a small convenience wrapper for [net-ssh](https://rubygems.org/gems/net-ssh).
|
4
|
+
Its intended and primary purpose is to provide pragmatic
|
5
|
+
execution of shell commands on a remote host via SSH.
|
6
|
+
|
7
|
+
It is mainly inspired by [Open3](http://ruby-doc.org/stdlib-2.3.1/libdoc/open3/rdoc/Open3.html) standard library
|
8
|
+
which provides access to exit codes,
|
9
|
+
standard output and standard error messages of executed commands on local host.
|
10
|
+
Open4ssh does the same but in a SSH remote context.
|
11
|
+
Astonishingly, there seems no pragmatic way to figure out exit codes or standard error messages of executed commands
|
12
|
+
with the net-ssh library.
|
13
|
+
Additionally, Open4ssh is able to execute a
|
14
|
+
sequence of commands and returns their exit codes, standard out and standard error messages in a command related list.
|
15
|
+
|
16
|
+
Open4ssh is most useful in remote automation scenarios which are triggered from Ruby environments.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'open4ssh'
|
24
|
+
```
|
25
|
+
|
26
|
+
And then execute:
|
27
|
+
|
28
|
+
$ bundle
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
$ gem install open4ssh
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
### Remote execution of a single command via SSH
|
37
|
+
|
38
|
+
All parameters of the _exec_ command are explained [here](Open4ssh.html#exec-class_method).
|
39
|
+
|
40
|
+
However, the following snippets explain how to use Open4ssh.
|
41
|
+
To execute simply one single command on a remote host, we can do the following:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require 'open4ssh'
|
45
|
+
|
46
|
+
stdout = Open4ssh.exec(
|
47
|
+
host: 'remote.host.io',
|
48
|
+
user: 'nane',
|
49
|
+
pwd: 'secret',
|
50
|
+
cmd: 'ls -la'
|
51
|
+
)
|
52
|
+
puts stdout
|
53
|
+
```
|
54
|
+
|
55
|
+
This will execute the bash command 'ls -la' on host _remote.host.io_ as user _nane_.
|
56
|
+
|
57
|
+
For a lot of cloud scenarios it is more appropriate to support a keybased login. This can be done like that
|
58
|
+
(simply use the key parameter instead of the pwd parameter):
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
require 'open4ssh'
|
62
|
+
|
63
|
+
stdout = Open4ssh.exec(
|
64
|
+
host: 'remote.host.io',
|
65
|
+
user: 'nane',
|
66
|
+
key: '/path/to/your/sshkey.pem',
|
67
|
+
cmd: 'ls -la'
|
68
|
+
)
|
69
|
+
puts stdout
|
70
|
+
```
|
71
|
+
|
72
|
+
### Remote execution of a sequence of commands via SSH
|
73
|
+
|
74
|
+
All parameters of the _exec4_ command are explained [here](Open4ssh.html#exec4-class_method).
|
75
|
+
The following snippets will explain how to use Open4ssh to execute a (sequence) of commands.
|
76
|
+
|
77
|
+
This snippet here will execute five shell commands sequentially
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
require 'open4ssh'
|
81
|
+
require 'pp'
|
82
|
+
|
83
|
+
returns = Open4ssh.exec4(
|
84
|
+
host: 'remote.host.io',
|
85
|
+
user: 'nane',
|
86
|
+
key: '/path/to/your/sshkey.pem',
|
87
|
+
cmd: [
|
88
|
+
"touch helloworld.txt",
|
89
|
+
"cat helloworld.txt",
|
90
|
+
"echo 'Hello World' >> helloworld.txt",
|
91
|
+
"cat helloworld.txt",
|
92
|
+
"rm helloworld.txt"
|
93
|
+
]
|
94
|
+
)
|
95
|
+
pp(returns)
|
96
|
+
```
|
97
|
+
|
98
|
+
and will generate this output.
|
99
|
+
|
100
|
+
[[0, "", "", "touch helloworld.txt"],
|
101
|
+
[0, "", "", "cat helloworld.txt"],
|
102
|
+
[0, "", "", "echo 'Hello World' >> helloworld.txt"],
|
103
|
+
[0, "Hello World\n", "", "cat helloworld.txt"],
|
104
|
+
[0, "", "", "rm helloworld.txt"]]
|
105
|
+
|
106
|
+
So, for each command a list of return values is returned.
|
107
|
+
|
108
|
+
1. exit code of the executed command
|
109
|
+
2. standard out message (might be empty)
|
110
|
+
3. standard error message (might be empty)
|
111
|
+
4. executed command (as passed by the _cmd_ parameter in _exec4_ call.
|
112
|
+
|
113
|
+
However, if we launch a sequence of commands exiting with exit codes not equal 0, this sequence is only executed as long as
|
114
|
+
each command could be successfully processed (exit code 0). So this snippet here
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
require 'open4ssh'
|
118
|
+
require 'pp'
|
119
|
+
|
120
|
+
returns = Open4ssh.exec4(
|
121
|
+
host: 'remote.host.io',
|
122
|
+
user: 'nane',
|
123
|
+
key: '/path/to/your/sshkey.pem',
|
124
|
+
cmd: [
|
125
|
+
"touch helloworld.txt",
|
126
|
+
"cat helloworld.txt",
|
127
|
+
"this will not work",
|
128
|
+
"cat helloworld.txt",
|
129
|
+
"rm helloworld.txt"
|
130
|
+
]
|
131
|
+
)
|
132
|
+
pp(returns)
|
133
|
+
```
|
134
|
+
|
135
|
+
would produce the following output
|
136
|
+
|
137
|
+
[[0, "", "", "touch helloworld.txt"],
|
138
|
+
[0, "", "", "cat helloworld.txt"],
|
139
|
+
[127, "", "bash: this: command not found\n", "this will not work"]]
|
140
|
+
|
141
|
+
and the last two commands would not been executed on the remote host, because the third command failed.
|
142
|
+
|
143
|
+
### How to check whether a sequence of commands was successful?
|
144
|
+
|
145
|
+
Because Open4ssh only executes commands as long as they are returning a exit code of 0, we can check
|
146
|
+
pragmatically whether all commands of a sequence have been executed successfully:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
exit_code, stderr, stdout, command = Open4ssh.exec4(
|
150
|
+
host: 'remote.host.io',
|
151
|
+
user: 'nane',
|
152
|
+
key: '/path/to/your/sshkey.pem',
|
153
|
+
cmd: [
|
154
|
+
"touch helloworld.txt",
|
155
|
+
"cat helloworld.txt",
|
156
|
+
"echo 'Hello World' >> helloworld.txt",
|
157
|
+
"cat helloworld.txt",
|
158
|
+
"rm helloworld.txt"
|
159
|
+
]
|
160
|
+
).last
|
161
|
+
|
162
|
+
if (exit_code == 0 && command == "rm helloworld.txt")
|
163
|
+
puts "Everything worked fine"
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
### What is this good for?
|
168
|
+
|
169
|
+
Just a small example. Assuming your remote host is a Ubuntu 14.04 system we could do something like that:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
exit_code, stdout, stderr, command = Open4ssh.exec4(
|
173
|
+
host: 'remote.host.io',
|
174
|
+
user: 'nane',
|
175
|
+
key: '/path/to/your/sshkey.pem',
|
176
|
+
cmd: [
|
177
|
+
"curl -fsSL https://test.docker.com/ | sh",
|
178
|
+
"sudo docker swarm init"
|
179
|
+
]
|
180
|
+
).last
|
181
|
+
|
182
|
+
if (command == "sudo docker swarm init" && exit_code == 0)
|
183
|
+
puts "You started successfully a new Docker Swarm cluster."
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
This would fire up an initial master for a [Docker Swarm cluster](https://docs.docker.com/engine/swarm/)
|
188
|
+
in a few lines of Ruby code. Be patient. This can take several minutes.
|
189
|
+
Of course, you can do any other tasks as well. This was only one example ;-)
|
190
|
+
|
191
|
+
### Verbose mode
|
192
|
+
|
193
|
+
If you want to know what is happening there you can turn on the verbose mode (mostly useful for debugging).
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
exit_code, stdout, stderr, command = Open4ssh.exec4(
|
197
|
+
host: 'remote.host.io',
|
198
|
+
user: 'nane',
|
199
|
+
key: '/path/to/your/sshkey.pem',
|
200
|
+
cmd: [
|
201
|
+
"curl -fsSL https://test.docker.com/ | sh",
|
202
|
+
"sudo docker swarm init"
|
203
|
+
],
|
204
|
+
verbose: true
|
205
|
+
).last
|
206
|
+
|
207
|
+
if (command == "sudo docker swarm init" && exit_code == 0)
|
208
|
+
puts "You started successfully a new Docker Swarm cluster."
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
This will perform the same install like above but will print all messages of the Docker install script on your console.
|
213
|
+
|
214
|
+
## Development
|
215
|
+
|
216
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
217
|
+
To release a new version, update the version number in `version.rb`,
|
218
|
+
and then run `bundle exec rake release`,
|
219
|
+
which will create a git tag for the version,
|
220
|
+
push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
221
|
+
|
222
|
+
## Contributing
|
223
|
+
|
224
|
+
Bug reports and pull requests are welcome on Github at https://github.com/nkratzke/open4ssh.
|
225
|
+
|
226
|
+
|
227
|
+
## License
|
228
|
+
|
229
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
230
|
+
|
data/Rakefile
ADDED
data/lib/open4ssh.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require "open4ssh/version"
|
2
|
+
require "net/ssh"
|
3
|
+
|
4
|
+
module Open4ssh
|
5
|
+
|
6
|
+
# Executes a shell command on a remote host via SSH and returns the console output.
|
7
|
+
#
|
8
|
+
# @param host [String] DNS name or IP address of the remote host (required)
|
9
|
+
# @param port [Integer] Port (defaults to 22)
|
10
|
+
# @param user [String] User name (required)
|
11
|
+
# @param key [Path] Path to a key file (.pem) if user logs in via keyfile (not required if password is provided)
|
12
|
+
# @param pwd [String] Password of user (not required if key is provided)
|
13
|
+
# @param cmd [String] valid shell command string to be executed on host (required)
|
14
|
+
#
|
15
|
+
# @return [String] console output of executed command (output includes stdout and stderr)
|
16
|
+
#
|
17
|
+
def self.exec(host: '', user: '', port: 22, key: '', pwd: '', cmd: '')
|
18
|
+
stdout = ""
|
19
|
+
keys = [key]
|
20
|
+
|
21
|
+
Net::SSH.start(host, user, port: 22, password: pwd, keys: keys) do |ssh|
|
22
|
+
result = ssh.exec!(cmd)
|
23
|
+
stdout = result
|
24
|
+
end
|
25
|
+
|
26
|
+
return stdout
|
27
|
+
end
|
28
|
+
|
29
|
+
# Executes a list of shell commands on a remote host via SSH and returns their exit codes, stdouts and stderrs.
|
30
|
+
# The commands are executed sequentially until a command terminates with an exit code not equal 0 (no success).
|
31
|
+
#
|
32
|
+
# @param host [String] DNS name or IP address of the remote host (required)
|
33
|
+
# @param port [Integer] Port (defaults to 22)
|
34
|
+
# @param user [String] User name (required)
|
35
|
+
# @param key [Path] Path to a key file (.pem) if user logs in via keyfile (not required if password is provided)
|
36
|
+
# @param pwd [String] Password of user (not required if key is provided)
|
37
|
+
# @param cmd [Array<String>] List of valid shell command strings to be executed on host (required)
|
38
|
+
# @param verbose [Bool] console outputs are plotted to stdout/stderr if set (defaults to false)
|
39
|
+
#
|
40
|
+
# @return [Array<exit_code, stdout, stderr, command>] List of exit_code, stdout, stderr and executed commands
|
41
|
+
#
|
42
|
+
def self.exec4(host: '', user: '', port: 22, key: '', pwd: '', cmd: [], verbose: false)
|
43
|
+
keys = [key]
|
44
|
+
results = []
|
45
|
+
|
46
|
+
Net::SSH.start(host, user, port: port, password: pwd, keys: keys) do |ssh|
|
47
|
+
# Execute command by command
|
48
|
+
for command in cmd
|
49
|
+
stdout = ""
|
50
|
+
stderr = ""
|
51
|
+
code = nil
|
52
|
+
channel = ssh.open_channel do |ch|
|
53
|
+
ch.exec(command) do |c, success|
|
54
|
+
c.close unless success
|
55
|
+
|
56
|
+
c.on_data do |_, data|
|
57
|
+
stdout += data
|
58
|
+
$stdout.puts(data) if verbose
|
59
|
+
end
|
60
|
+
|
61
|
+
c.on_extended_data do |_, _, data|
|
62
|
+
stderr += data
|
63
|
+
$stderr.puts(data) if verbose
|
64
|
+
end
|
65
|
+
|
66
|
+
c.on_request('exit-status') { |_, data| code = data.read_long }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
channel.wait
|
70
|
+
results << [code, stdout, stderr, command]
|
71
|
+
|
72
|
+
# If last command was not successful stop execution
|
73
|
+
if code != 0
|
74
|
+
ssh.close
|
75
|
+
return results
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
return results
|
81
|
+
end
|
82
|
+
end
|
data/open4ssh.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'open4ssh/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "open4ssh"
|
8
|
+
spec.version = Open4ssh::VERSION
|
9
|
+
spec.authors = ["Nane Kratzke"]
|
10
|
+
spec.email = ["nane.kratzke@fh-luebeck.de"]
|
11
|
+
|
12
|
+
spec.summary = %q{Wrapper around net-ssh for plain execution of remote shell commands.}
|
13
|
+
spec.description = %q{Wrapper around net-ssh for plain execution of remote shell commands and painless collection of exit codes, stdout, stderr messages.}
|
14
|
+
spec.homepage = "https://rubygems.org/gems/open4ssh"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.bindir = "bin"
|
27
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
33
|
+
|
34
|
+
spec.add_runtime_dependency "net-ssh", "~> 3.2"
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: open4ssh
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nane Kratzke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: net-ssh
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
69
|
+
description: Wrapper around net-ssh for plain execution of remote shell commands and
|
70
|
+
painless collection of exit codes, stdout, stderr messages.
|
71
|
+
email:
|
72
|
+
- nane.kratzke@fh-luebeck.de
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/open4ssh.rb
|
84
|
+
- lib/open4ssh/version.rb
|
85
|
+
- open4ssh.gemspec
|
86
|
+
homepage: https://rubygems.org/gems/open4ssh
|
87
|
+
licenses:
|
88
|
+
- MIT
|
89
|
+
metadata:
|
90
|
+
allowed_push_host: https://rubygems.org
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.4.5.1
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Wrapper around net-ssh for plain execution of remote shell commands.
|
111
|
+
test_files: []
|
112
|
+
has_rdoc:
|