shexy 0.2 → 0.3
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.
- data/CHANGELOG.md +9 -0
- data/README.md +38 -0
- data/lib/shexy.rb +112 -22
- data/spec/spec_helper.rb +2 -0
- metadata +5 -5
- data/test/helper.rb +0 -18
- data/test/test_shexy.rb +0 -7
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -26,10 +26,48 @@ and added them to the SSH agent (ssh-add ~/.ssh/my-priv-key):
|
|
26
26
|
end
|
27
27
|
Shexy.exe 'echo hello' # no need to add host/user again
|
28
28
|
|
29
|
+
|
30
|
+
Specify key to use:
|
31
|
+
|
32
|
+
Shexy.key = '~/.ssh/id_rsa'
|
33
|
+
out, err, exit_code = Shexy.exe 'test@test-host', 'ls -la'
|
34
|
+
|
29
35
|
Copying files (local -> remote):
|
30
36
|
|
31
37
|
Shexy.copy_to 'test@test-host', '/home/rubiojr/my-uber-file', '/tmp/'
|
32
38
|
|
39
|
+
Batch mode:
|
40
|
+
|
41
|
+
Shexy.batch do
|
42
|
+
script <<-EOH
|
43
|
+
echo > /tmp/foo
|
44
|
+
ls -la
|
45
|
+
sed -i s/foo/bar/ /etc/foo
|
46
|
+
EOH
|
47
|
+
end
|
48
|
+
|
49
|
+
Use sudo:
|
50
|
+
|
51
|
+
Shexy.use_sudo
|
52
|
+
# sudo will be used to run the commands
|
53
|
+
Shexy.exe 'test@foobar.com', 'echo | cat' # => sudo echo | sudo cat
|
54
|
+
|
55
|
+
Query the server OS:
|
56
|
+
|
57
|
+
Shexy.distro # => :ubuntu, :redhat, :centos, :fedora, :debian
|
58
|
+
Shexy.distro_release # => 12.04, 5.8, etc.
|
59
|
+
|
60
|
+
More helpers:
|
61
|
+
|
62
|
+
Shexy.user = 'rubiojr'
|
63
|
+
Shexy.password = 'secret'
|
64
|
+
Shexy.host = 'foo.com'
|
65
|
+
# Copy the key to /home/rubiojr/.ssh/authorized_keys in remote server
|
66
|
+
Shexy.copy_ssh_pubkey '~/.ssh/id_rsa.pub'
|
67
|
+
# Set PermitRootLogin to without-password in /etc/ssh/sshd_config
|
68
|
+
# requires sudo in remote server (unless using root user).
|
69
|
+
Shexy.permit_root_login 'without-password'
|
70
|
+
|
33
71
|
## Caution
|
34
72
|
|
35
73
|
I was bored writing net-ssh boilerplate, so I created this highly
|
data/lib/shexy.rb
CHANGED
@@ -30,40 +30,76 @@ require 'net/scp'
|
|
30
30
|
#
|
31
31
|
# Shexy.copy_to 'test@test-host', '/home/rubiojr/my-uber-file', '/tmp/'
|
32
32
|
#
|
33
|
+
|
33
34
|
module Shexy
|
35
|
+
|
36
|
+
VERSION = '0.3'
|
34
37
|
|
35
|
-
|
38
|
+
[:user, :password, :key, :cmd, :host].each do |n|
|
39
|
+
instance_eval %{
|
40
|
+
def #{n}; Thread.current[:shexy_#{n}]; end
|
41
|
+
def #{n}=(v); Thread.current[:shexy_#{n}] = v; end
|
42
|
+
}
|
43
|
+
end
|
36
44
|
|
37
|
-
|
45
|
+
def self.flags=(f);Thread.current[:shexy_flags] = f;end
|
46
|
+
def self.flags; Thread.current[:shexy_flags] ||= {} ; end
|
47
|
+
def self.sudo?;Thread.current[:shexy_use_sudo]; end
|
48
|
+
def self.use_sudo(v = true); Thread.current[:shexy_use_sudo] = v; end
|
38
49
|
|
39
|
-
def self.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
def self.wait_for_ssh(timeout = 60)
|
51
|
+
Timeout.timeout(timeout) do
|
52
|
+
begin
|
53
|
+
sleep(1) until tcp_test_ssh(host) do
|
54
|
+
end
|
55
|
+
rescue Errno::ECONNRESET
|
56
|
+
# safe to ignore, we need to retry all the time.
|
57
|
+
end
|
58
|
+
end
|
59
|
+
true
|
60
|
+
rescue Exception => e
|
61
|
+
$stderr.puts e.message
|
62
|
+
false
|
63
|
+
end
|
45
64
|
|
46
|
-
|
47
|
-
|
48
|
-
|
65
|
+
def self.tcp_test_ssh
|
66
|
+
tcp_socket = TCPSocket.new(host, 22)
|
67
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
68
|
+
if readable
|
69
|
+
yield
|
70
|
+
true
|
71
|
+
else
|
72
|
+
false
|
73
|
+
end
|
74
|
+
rescue Errno::ETIMEDOUT, Errno::EPERM
|
75
|
+
false
|
76
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
77
|
+
sleep 2
|
78
|
+
false
|
79
|
+
ensure
|
80
|
+
tcp_socket && tcp_socket.close
|
49
81
|
end
|
50
82
|
|
51
83
|
def self.exe(*args)
|
52
84
|
args.flatten!
|
53
85
|
if args.size > 1
|
54
|
-
|
55
|
-
if
|
56
|
-
|
57
|
-
end
|
58
|
-
@cmd = args[1]
|
86
|
+
self.host = args[0]
|
87
|
+
self.user, self.host = self.host.split '@' if self.host =~ /@/
|
88
|
+
self.cmd = args[1]
|
59
89
|
else
|
60
|
-
|
90
|
+
self.cmd = args[0]
|
61
91
|
end
|
62
|
-
|
92
|
+
self.flags[:password] = self.password if self.password
|
93
|
+
self.flags[:keys] = [self.key] if self.key
|
94
|
+
Net::SSH.start(self.host, self.user, self.flags) do |sh|
|
63
95
|
sh.open_channel do |ch|
|
64
96
|
if sudo?
|
65
97
|
ch.request_pty
|
66
|
-
|
98
|
+
if cmd =~ /(&&|\|\||&|\|)/
|
99
|
+
self.cmd = cmd.gsub(/(&&|\|\||&|\|)/, $1 + 'sudo')
|
100
|
+
end
|
101
|
+
self.cmd = "sudo #{cmd}"
|
102
|
+
puts "SHEXY: #{cmd}" if $DEBUG
|
67
103
|
end
|
68
104
|
ch.exec cmd do
|
69
105
|
# FIXME: I don't think it's a good idea
|
@@ -95,6 +131,25 @@ module Shexy
|
|
95
131
|
end
|
96
132
|
end
|
97
133
|
|
134
|
+
def self.batch(&block)
|
135
|
+
require 'tempfile'
|
136
|
+
out, err = nil,nil
|
137
|
+
def self.script(script)
|
138
|
+
f = Tempfile.new 'shexy'
|
139
|
+
begin
|
140
|
+
f.puts script
|
141
|
+
f.flush
|
142
|
+
copy_to f.path, "#{f.path}.remote"
|
143
|
+
out, err = exe "/bin/bash #{f.path}.remote"
|
144
|
+
ensure
|
145
|
+
f.close
|
146
|
+
f.unlink
|
147
|
+
end
|
148
|
+
return out, err
|
149
|
+
end
|
150
|
+
instance_eval &block
|
151
|
+
end
|
152
|
+
|
98
153
|
#
|
99
154
|
# Shexy.copy_to 'root@foobar.com', 'source_file', 'dest_file'
|
100
155
|
#
|
@@ -113,9 +168,9 @@ module Shexy
|
|
113
168
|
|
114
169
|
if args.size > 2
|
115
170
|
# First arg assumed to be foo@host.net
|
116
|
-
|
117
|
-
if
|
118
|
-
|
171
|
+
self.host = args[0]
|
172
|
+
if self.host =~ /@/
|
173
|
+
self.user, self.host = self.host.split '@'
|
119
174
|
end
|
120
175
|
from = args[1]
|
121
176
|
to = args[2]
|
@@ -125,6 +180,7 @@ module Shexy
|
|
125
180
|
from = args[0]
|
126
181
|
to = args[1]
|
127
182
|
end
|
183
|
+
self.flags[:password] = self.password if self.password
|
128
184
|
from = File.expand_path from
|
129
185
|
Net::SCP.start(host, user, flags) do |scp|
|
130
186
|
scp.upload! from, to, opts
|
@@ -165,4 +221,38 @@ module Shexy
|
|
165
221
|
issue
|
166
222
|
end
|
167
223
|
|
224
|
+
def self.copy_ssh_pubkey(path, dest_dir = '~/.ssh')
|
225
|
+
path = File.expand_path path
|
226
|
+
raise ArgumentError.new("Invalid key file") unless File.exist?(path)
|
227
|
+
key = File.read path
|
228
|
+
batch do
|
229
|
+
script <<-EOH
|
230
|
+
mkdir -p #{dest_dir} && chmod 700 #{dest_dir}
|
231
|
+
echo '#{key}' >> #{dest_dir}/authorized_keys
|
232
|
+
EOH
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
#
|
237
|
+
# Set PermitRootLogin to value in /etc/ssh/sshd_config
|
238
|
+
# value accepted: yes,now, without-password
|
239
|
+
#
|
240
|
+
def self.permit_root_login(value)
|
241
|
+
value = value.to_s
|
242
|
+
unless value =~ /^(yes|no|without-password)$/
|
243
|
+
raise ArgumentError.new "Argument should be yes|no|without-password"
|
244
|
+
end
|
245
|
+
using_sudo = Shexy.sudo?
|
246
|
+
Shexy.use_sudo
|
247
|
+
out, err = batch do
|
248
|
+
script <<-EOH
|
249
|
+
sed -i 's/^#\?PermitRootLogin.*$/PermitRootLogin\ #{value}/' /etc/ssh/sshd_config
|
250
|
+
test -f /etc/init.d/ssh && /etc/init.d/ssh restart
|
251
|
+
test -f /etc/init.d/sshd && /etc/init.d/sshd restart
|
252
|
+
EOH
|
253
|
+
end
|
254
|
+
Shexy.use_sudo(false) unless using_sudo
|
255
|
+
return out, err
|
256
|
+
end
|
257
|
+
|
168
258
|
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shexy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-ssh
|
@@ -132,13 +132,13 @@ extra_rdoc_files:
|
|
132
132
|
- README.md
|
133
133
|
files:
|
134
134
|
- .document
|
135
|
+
- CHANGELOG.md
|
135
136
|
- Gemfile
|
136
137
|
- LICENSE.txt
|
137
138
|
- README.md
|
138
139
|
- Rakefile
|
139
140
|
- lib/shexy.rb
|
140
|
-
-
|
141
|
-
- test/test_shexy.rb
|
141
|
+
- spec/spec_helper.rb
|
142
142
|
homepage: http://github.com/rubiojr/shexy
|
143
143
|
licenses:
|
144
144
|
- MIT
|
@@ -154,7 +154,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
154
|
version: '0'
|
155
155
|
segments:
|
156
156
|
- 0
|
157
|
-
hash:
|
157
|
+
hash: 130145655460833176
|
158
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
159
|
none: false
|
160
160
|
requirements:
|
data/test/helper.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'test/unit'
|
11
|
-
require 'shoulda'
|
12
|
-
|
13
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
-
require 'shexy'
|
16
|
-
|
17
|
-
class Test::Unit::TestCase
|
18
|
-
end
|