rye 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +6 -0
- data/README.rdoc +30 -145
- data/bin/rye +7 -6
- data/lib/rye.rb +9 -1
- data/lib/rye/box.rb +1 -0
- data/rye.gemspec +1 -1
- metadata +2 -2
data/CHANGES.txt
CHANGED
@@ -4,6 +4,12 @@ TODO
|
|
4
4
|
|
5
5
|
* Fingerprints: ssh-keygen -l -f id_rsa_repos.pub
|
6
6
|
|
7
|
+
#### 0.6.1 (2009-04-29) #############################
|
8
|
+
|
9
|
+
* ADDED: Prints message to STDERR when passwordless login fails.
|
10
|
+
* ADDED: Highline 1.5.1 to vendor to fix the Ruby 1.9 issue (Highline
|
11
|
+
1.5.1 is not released as a gem yet)
|
12
|
+
* CHANGE: Cleaned examples and links in README
|
7
13
|
|
8
14
|
#### 0.6.0 (2009-04-28) #############################
|
9
15
|
|
data/README.rdoc
CHANGED
@@ -4,7 +4,6 @@ Safely run SSH commands on a bunch of machines at the same time (from Ruby).
|
|
4
4
|
|
5
5
|
Rye is similar to Rush[http://rush.heroku.com] but everything happens over SSH (no HTTP daemon) and the default settings are less powerful (for safety). For example, file globs and the "rm" command are disabled so unless otherwise specified, you can't do this: <tt>rbox.rm('-rf', '/etc/**/*')</tt>.
|
6
6
|
|
7
|
-
See the examples below (which are taken from bin/try).
|
8
7
|
|
9
8
|
== Installation
|
10
9
|
|
@@ -15,85 +14,35 @@ One of:
|
|
15
14
|
$ git clone git://github.com/delano/rye.git
|
16
15
|
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
rbox = Rye::Box.new('localhost')
|
21
|
-
|
22
|
-
# Commands are run as methods on the Rye::Box object
|
23
|
-
puts rbox.uptime # => 11:02 up 16:01, 3 users
|
24
|
-
|
25
|
-
# The response value for all commands is a Rye::Rap object. The rap is a
|
26
|
-
# subclass of Array so you can treat it as an Array, but it can also act
|
27
|
-
# like a String if there's only one element.
|
28
|
-
puts rbox.ls('rye.test') # => ""
|
29
|
-
puts rbox.ls('rye.test').stderr # => ls: rye.test: No such file or directory
|
30
|
-
|
31
|
-
puts rbox.touch('rye.test') # => ""
|
32
|
-
puts rbox.rm('rye.test') # => ""
|
33
|
-
|
34
|
-
# You can change directories
|
35
|
-
puts rbox.pwd # => /home/rye
|
36
|
-
puts rbox['/usr/bin'].pwd # => /usr/bin
|
37
|
-
puts rbox.pwd # => /usr/bin
|
38
|
-
puts rbox.cd('/home/rye').pwd # => /home/rye
|
39
|
-
|
40
|
-
# You can specify environment variables
|
41
|
-
rbox.setenv(:RYE, "Forty Creek")
|
42
|
-
rbox.env # => ['HOME=/home/rye', 'RYE=Forty Creek', ...]
|
43
|
-
|
44
|
-
# The commands method returns an Array of available commands:
|
45
|
-
puts rbox.commands.join(', ') # => pwd, touch, echo, wc, ...
|
46
|
-
|
47
|
-
# When you're done you can disconnect explicitly.
|
48
|
-
# (Although Rye does this automatically at exit.)
|
49
|
-
rbox.disconnect
|
50
|
-
|
17
|
+
See bin/try for examples!
|
51
18
|
|
52
|
-
== EXAMPLE 2 -- Disabling Safe-Mode
|
53
19
|
|
54
|
-
|
55
|
-
rbox_wild = Rye::Box.new('localhost', :safe => false)
|
20
|
+
== EXAMPLE 1 -- SSH Authorization
|
56
21
|
|
57
|
-
|
58
|
-
# arguments are thoroughly escaped. This prevents access to
|
59
|
-
# environment variables and file globs (among other things).
|
60
|
-
p rbox_safe.echo('$HOME') # => "$HOME"
|
61
|
-
p rbox_safe['/etc'].ls('host*') rescue Rye::CommandError # Doesn't exist
|
62
|
-
p rbox_safe.ls('-l | wc -l') rescue Rye::CommandError # => '|' is not a valid ls arg
|
22
|
+
Does it annoy you to manually authorize remote SSH accounts? Rye can help!
|
63
23
|
|
64
|
-
|
65
|
-
p rbox_wild.echo('$HOME') # => "/home/rye"
|
66
|
-
p rbox_wild['/etc'].ls('host*') # => ["hostconfig", "hosts"]
|
67
|
-
p rbox_wild.ls('-l | wc -l') # => 110
|
68
|
-
p rbox_wild.echo('$HOME > /tmp/rye-home') # =>
|
69
|
-
p rbox_wild.cat('/tmp/rye-home') # => "/home/rye"
|
24
|
+
Enable passwordless logins to HOST1 and HOST2:
|
70
25
|
|
26
|
+
$ rye authorize HOST1 HOST2
|
71
27
|
|
72
|
-
|
28
|
+
This will copy your public SSH keys to the <tt>~/.ssh/authorized_keys</tt> and <tt>~/.ssh/authorized_keys2</tt> files on the remote machine(s).
|
73
29
|
|
74
|
-
|
75
|
-
rbox.add_keys('/private/key/path') # Specify additional private keys
|
30
|
+
See <tt>rye -h</tt> for more info
|
76
31
|
|
77
|
-
# There's currently no rye900 command
|
78
|
-
p rbox.commands.member?('rye9000') # => false
|
79
32
|
|
80
|
-
|
81
|
-
# automatically become available to all Rye::Box objects.
|
82
|
-
module Rye::Cmd
|
83
|
-
def rye9000(*args)
|
84
|
-
run_command("ls", args)
|
85
|
-
end
|
86
|
-
def somescript(*args)
|
87
|
-
run_command("/path/to/my/script", args)
|
88
|
-
end
|
89
|
-
end
|
33
|
+
== EXAMPLE 2 -- Basic Usage
|
90
34
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
35
|
+
rbox = Rye::Box.new('localhost')
|
36
|
+
rbox.uptime # => 11:02 up 16:01, 3 users
|
37
|
+
rbox['/usr/bin'].pwd # => /usr/bin
|
38
|
+
|
39
|
+
You can specify environment variables
|
95
40
|
|
96
|
-
|
41
|
+
rbox.setenv(:RYE, "Forty Creek")
|
42
|
+
rbox.env # => ['HOME=/home/rye', 'RYE=Forty Creek', ...]
|
43
|
+
|
44
|
+
|
45
|
+
== EXAMPLE 3 -- Accessing Multiple Machines
|
97
46
|
|
98
47
|
rset = Rye::Set.new
|
99
48
|
rbox = Rye::Box.new
|
@@ -101,59 +50,13 @@ One of:
|
|
101
50
|
rset.add_keys('/private/key/path') # For passwordless logins
|
102
51
|
rset.add_boxes(rbox, 'localhost') # Add boxes as hostnames or objects
|
103
52
|
|
104
|
-
|
105
|
-
|
53
|
+
Calling methods on Rye::Set objects is very similar to calling them on Rye::Box objects. In fact, it's identical:
|
54
|
+
|
106
55
|
p rset.uptime # => [[14:19:02 up 32 days, 19:35 ...], [14:19:02 up 30 days, 01:35]]
|
107
56
|
p rset['/etc'].ls # => [['file1', 'file2', ...], ['life1', 'life2', ...]]
|
108
57
|
|
109
|
-
# Like Rye::Box, the response value is a Rye::Rap object containing the
|
110
|
-
# responses from each box. Each response is itself a Rye::Rap object.
|
111
|
-
unames = rset.uname
|
112
|
-
p unames # => [["Darwin"], ["Darwin"]]
|
113
|
-
puts unames.class # => Rye::Rap
|
114
|
-
|
115
|
-
# The Rye::Rap object also keeps a reference to the object that called the
|
116
|
-
# command. In this case, it will keep a reference to Rye::Set:
|
117
|
-
puts unames.set.class # => Rye::Set
|
118
|
-
puts unames.set == rset # => true
|
119
|
-
puts unames.size # => 2
|
120
|
-
puts unames.first # => Darwin
|
121
|
-
puts unames.first.class # => Rye::Rap
|
122
|
-
puts unames.first.box.class # => Rye::Box
|
123
|
-
puts unames.first.box == rbox # => true
|
124
|
-
|
125
|
-
# Envrionment variables can be set the same way as with Rye::Box
|
126
|
-
rset.setenv(:RYE, "Forty Creek")
|
127
|
-
p rset.env.first.select { |env| env =~ /RYE/ } # => ["RYE=Forty Creek"]
|
128
|
-
|
129
|
-
|
130
|
-
== EXAMPLE 5 -- ERROR HANDLING
|
131
|
-
|
132
|
-
rbox = Rye::Box.new('localhost', :safe => false)
|
133
|
-
|
134
|
-
# Rye follows the standard convention of taking exception to a non-zero
|
135
|
-
# exit code by raising a Rye::CommandError. In this case, rye9000.test
|
136
|
-
# is not found by the ls command.
|
137
|
-
begin
|
138
|
-
rbox.ls('rye9000.test')
|
139
|
-
rescue Rye::CommandError => ex
|
140
|
-
puts ex.exit_code # => 1
|
141
|
-
puts ex.stderr # => ls: rye.test: No such file or directory
|
142
|
-
end
|
143
|
-
|
144
|
-
# The Rye:Rap response objects also give you the STDOUT and STDERR
|
145
|
-
# content separately. Here we redirect STDOUT to STDERR, so this
|
146
|
-
# will return nothing:
|
147
|
-
puts rbox.uname('-a 1>&2').stdout # =>
|
148
|
-
|
149
|
-
# It all went to STDERR:
|
150
|
-
puts rbox.uname('-a 1>&2').stderr # => Darwin ryehost 9.6.0 ...
|
151
|
-
|
152
|
-
# There were no actual error so the exit code should be 0.
|
153
|
-
puts rbox.uname('-a 1>&2').exit_code # => 0
|
154
|
-
|
155
58
|
|
156
|
-
== EXAMPLE
|
59
|
+
== EXAMPLE 4 -- FILE TRANSFERS
|
157
60
|
|
158
61
|
rbox = Rye::Box.new("localhost", :info => true)
|
159
62
|
|
@@ -174,25 +77,6 @@ One of:
|
|
174
77
|
|
175
78
|
p filecontent.read
|
176
79
|
|
177
|
-
== EXAMPLE 7 -- rye
|
178
|
-
|
179
|
-
Rye comes with a command-line utility called <tt>rye</tt>.
|
180
|
-
|
181
|
-
# Prints the paths to your private keys
|
182
|
-
$ rye keys
|
183
|
-
|
184
|
-
# Prints the server host keys (suitable for ~/.ssh/known_hosts)
|
185
|
-
$ rye hostkey HOST1 HOST2
|
186
|
-
|
187
|
-
# Add your public keys to authorized_keys and authorized_keys2
|
188
|
-
# on a remote machine
|
189
|
-
$ rye authorize HOST1 HOST2
|
190
|
-
More info:
|
191
|
-
|
192
|
-
$ rye -h
|
193
|
-
$ rye COMMAND -h
|
194
|
-
$ rye show-commands
|
195
|
-
|
196
80
|
|
197
81
|
== About Safe-Mode
|
198
82
|
|
@@ -221,6 +105,7 @@ Rye permits only a limited number of system commands to be run. This default whi
|
|
221
105
|
* highline
|
222
106
|
* drydock
|
223
107
|
|
108
|
+
|
224
109
|
== Known Issues
|
225
110
|
|
226
111
|
This list will grow. If you find one let me know!
|
@@ -229,20 +114,20 @@ This list will grow. If you find one let me know!
|
|
229
114
|
* Highline 1.5 not working in Ruby 1.9 (password prompts hang)
|
230
115
|
* Rye uses OpenSSL's ssh-agent (if it exists). Rye starts it up as a child process and shuts it down using at_exit. If you have code in an at_exit that rely's on Rye, make sure your code runs before Rye's at_exit block is called. For example, Drydock uses at_exit too which is why in bin/rye you can see that Drydock is called explicitly so that Rye's at_exit is executed after Drydock executes a command.
|
231
116
|
|
117
|
+
|
232
118
|
== Thanks
|
233
119
|
|
234
120
|
* Solutious Incorporated (http://solutious.com) for all the orange juice.
|
235
|
-
* http://
|
236
|
-
* http://github.com/
|
237
|
-
* http://
|
238
|
-
|
239
|
-
* http://paste.lisp.org/display/6912
|
121
|
+
* Kalin Harvey (http://rely.ca)
|
122
|
+
* Rush[http://github.com/adamwiggins/rush]
|
123
|
+
* Capistrano[http://github.com/jamis/capistrano/blob/master/lib/capistrano/shell.rb]
|
124
|
+
|
240
125
|
|
241
126
|
== More Info
|
242
127
|
|
243
|
-
* http://github.com/delano/rye
|
244
|
-
* http://delano.github.com/rye
|
245
|
-
* http://www.youtube.com/watch?v=_StUVh6ENuw
|
128
|
+
* GitHub[http://github.com/delano/rye]
|
129
|
+
* Rdocs[http://delano.github.com/rye]
|
130
|
+
* Inspiration[http://www.youtube.com/watch?v=_StUVh6ENuw]
|
246
131
|
|
247
132
|
== Credits
|
248
133
|
|
data/bin/rye
CHANGED
@@ -35,7 +35,8 @@ after do
|
|
35
35
|
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
about "Add your public keys to one or more remote machines"
|
39
|
+
usage "rye authorize [-u username] host"
|
39
40
|
option :u, :user, String, "Username"
|
40
41
|
argv :hostname
|
41
42
|
command :authorize do |obj|
|
@@ -56,7 +57,7 @@ command :authorize do |obj|
|
|
56
57
|
end
|
57
58
|
command_alias :authorize, :authorise
|
58
59
|
|
59
|
-
|
60
|
+
about "Add your public keys to your current account on this machine"
|
60
61
|
command :authorize_local do |obj|
|
61
62
|
user = Rye.sysinfo.user
|
62
63
|
puts "Authorizing #{user}@localhost"
|
@@ -68,11 +69,11 @@ end
|
|
68
69
|
command_alias :local_authorize, :local_authorise
|
69
70
|
|
70
71
|
|
71
|
-
|
72
|
+
about "Generate a public key from a private key"
|
72
73
|
|
73
74
|
|
74
75
|
|
75
|
-
|
76
|
+
about "Fetch the host keys for remote machines (suitable for your ~/.ssh/known_hosts file)"
|
76
77
|
usage "rye hostkey HOSTNAME [HOSTNAME2 HOSTNAME3 ...]"
|
77
78
|
argv :hostname
|
78
79
|
command :hostkeys do |obj|
|
@@ -84,14 +85,14 @@ end
|
|
84
85
|
command_alias :hostkeys, :hostkey
|
85
86
|
|
86
87
|
|
87
|
-
|
88
|
+
about "Display your private keys"
|
88
89
|
command :keys do |obj|
|
89
90
|
Rye.keys.each do |key|
|
90
91
|
puts key.join(' ')
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
+
about "Display your public SSH keys"
|
95
96
|
usage "rye pubkeys [--pem] [KEYPATH]"
|
96
97
|
option :p, :pem, "Output in PEM format"
|
97
98
|
argv :keypath
|
data/lib/rye.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
# Temporary fix before Highline 1.5.1 is release. This fixes
|
3
|
+
# a the issue with Ruby 1.9 that causes the prompts to hang.
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'vendor', 'highline-1.5.1')
|
3
5
|
|
4
6
|
require 'tempfile'
|
5
7
|
require 'logger'
|
@@ -32,6 +34,12 @@ require 'sys'
|
|
32
34
|
# * See +bin/try+ for a bunch of working examples.
|
33
35
|
# * See Rye::Box#initialize for info about disabling safe-mode.
|
34
36
|
#
|
37
|
+
#--
|
38
|
+
# The following posts were really helpful when I first wrote Rye:
|
39
|
+
# http://www.nofluffjuststuff.com/blog/david_bock/2008/10/ruby_s_closure_cleanup_idiom_and_net_ssh.html
|
40
|
+
# http://groups.google.com/group/ruby-talk-google/browse_thread/thread/674a6f6de15ceb49?pli=1
|
41
|
+
# http://paste.lisp.org/display/6912
|
42
|
+
#++
|
35
43
|
module Rye
|
36
44
|
extend self
|
37
45
|
|
data/lib/rye/box.rb
CHANGED
@@ -182,6 +182,7 @@ module Rye
|
|
182
182
|
print "\a" if retried == 0 && @info # Ring the bell once
|
183
183
|
retried += 1
|
184
184
|
if STDIN.tty? && retried <= 3
|
185
|
+
STDERR.puts "Passwordless login failed for #{@opts[:user]}"
|
185
186
|
@opts[:password] = highline.ask("Password: ") { |q| q.echo = '' }
|
186
187
|
@opts[:auth_methods] ||= []
|
187
188
|
@opts[:auth_methods] << 'password'
|
data/rye.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "rye"
|
3
3
|
s.rubyforge_project = "rye"
|
4
|
-
s.version = "0.6.
|
4
|
+
s.version = "0.6.1"
|
5
5
|
s.summary = "Rye: Safely run SSH commands on a bunch of machines at the same time (from Ruby)."
|
6
6
|
s.description = s.summary
|
7
7
|
s.author = "Delano Mandelbaum"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rye
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-29 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|