relay 0.0.1 → 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Michel Martens and Damian Janowski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ Relay
2
+ =====
3
+
4
+ Relay commands over SSH.
5
+
6
+ Description
7
+ -----------
8
+
9
+ Relay is a simple library that allows you to send commands over SSH.
10
+ It uses your own SSH, not a Ruby version, so you can profit from your
11
+ settings and public/private keys.
12
+
13
+ Usage
14
+ -----
15
+
16
+ To send a command to a server called `myserver`:
17
+
18
+ $ relay execute "ls -al" myserver
19
+ $ relay execute "cd foo; ls" myserver
20
+
21
+ If you want to send more commands, you can write a shell script:
22
+
23
+ $ cat recipe.sh
24
+ cd foo
25
+ ls
26
+ mkdir -p bar/baz
27
+
28
+ $ relay recipe.sh myserver
29
+
30
+ It will execute those commands on `myserver` and show the output.
31
+
32
+ This last form accepts one file as the recipe and one or many servers:
33
+
34
+ $ relay recipe.sh server1 server2 server3
35
+
36
+ You can also add your public key to a remote server's authorized keys file:
37
+
38
+ $ relay identify myserver
39
+
40
+ Installation
41
+ ------------
42
+
43
+ $ sudo gem install relay
44
+
45
+ License
46
+ -------
47
+
48
+ Copyright (c) 2009 Michel Martens and Damian Janowski
49
+
50
+ Permission is hereby granted, free of charge, to any person
51
+ obtaining a copy of this software and associated documentation
52
+ files (the "Software"), to deal in the Software without
53
+ restriction, including without limitation the rights to use,
54
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
55
+ copies of the Software, and to permit persons to whom the
56
+ Software is furnished to do so, subject to the following
57
+ conditions:
58
+
59
+ The above copyright notice and this permission notice shall be
60
+ included in all copies or substantial portions of the Software.
61
+
62
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
63
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
64
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
65
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
66
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
67
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
68
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
69
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ task :test do
2
+ system "cd test && ruby relay_test.rb"
3
+ end
4
+
5
+ task :default => :test
@@ -0,0 +1,21 @@
1
+ #! /usr/bin/env ruby -rubygems
2
+
3
+ require File.join(File.dirname(__FILE__), "..", "lib", "relay")
4
+
5
+ # A way to extend Relay is to write tasks in a Thorfile in the project's root directory.
6
+ # Relay loads the Thorfile if there is one, and all the tasks that are declared in the
7
+ # class Relay become available.
8
+ if File.exists?("Thorfile")
9
+ load("Thorfile")
10
+ end
11
+
12
+ # Start the relay tasks.
13
+ if ARGV[0] && File.exists?(ARGV[0])
14
+ file = ARGV.shift
15
+
16
+ ARGV.each do |server|
17
+ Relay.new.recipe(file, server)
18
+ end
19
+ else
20
+ Relay.start
21
+ end
@@ -0,0 +1,71 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require "thor"
4
+ require "open3"
5
+
6
+ class Ssh
7
+ def initialize(server)
8
+ @server = server
9
+ end
10
+
11
+ def start
12
+ Open3.popen3("ssh -T #{@server}") do |stdin, stdout, stderr|
13
+ threads = []
14
+
15
+ @stdin, @stdout, @stderr = stdin, stdout, stderr
16
+
17
+ threads << Thread.new do
18
+ while line = stderr.gets
19
+ $stderr.puts(line)
20
+ end
21
+ end
22
+
23
+ threads << Thread.new do
24
+ while line = stdout.gets
25
+ $stdout.puts(line)
26
+ end
27
+ end
28
+
29
+ yield(self)
30
+ stdin.close
31
+ threads.each {|t| t.join }
32
+ end
33
+ end
34
+
35
+ def run(command)
36
+ puts "\e[1m\e[33m$ #{command.strip}\e[0m"
37
+ @stdin.puts(command)
38
+ end
39
+ end
40
+
41
+ class Relay < Thor
42
+
43
+ desc "identify SERVER", "Copies your public key to a remote server"
44
+ method_option :key, :type => :string, :aliases => "-k"
45
+ method_option :path, :type => :string, :aliases => "-p"
46
+ def identify(server)
47
+ path = options[:path] || "~/.ssh/authorized_keys"
48
+ keys = [options[:key], "~/.ssh/id_rsa.pub", "~/.ssh/id_dsa.pub"].compact
49
+ key = keys.find { |k| File.exists?(File.expand_path(k)) }
50
+
51
+ if system %Q{cat #{key} | ssh #{server} "cat >> #{path}"}
52
+ say_status :copied, "#{key} to #{server}:#{path}"
53
+ end
54
+ end
55
+
56
+ desc "recipe RECIPE SERVER", "Execute commands contained in RECIPE in the context of SERVER"
57
+ def recipe(recipe, server)
58
+ Ssh.new(server).start do |session|
59
+ File.readlines(recipe).each do |command|
60
+ session.run(command)
61
+ end
62
+ end
63
+ end
64
+
65
+ desc "execute COMMAND SERVER", "Execute COMMAND in the context of SERVER"
66
+ def execute(command, server)
67
+ Ssh.new(server).start do |session|
68
+ session.run(command)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "relay"
3
+ s.version = "0.0.2"
4
+ s.summary = "Relay commands over SSH"
5
+ s.description = "Relay allows you to execute remote commands via SSH with ease."
6
+ s.authors = ["Damian Janowski", "Michel Martens"]
7
+ s.email = ["djanowski@dimaion.com", "michel@soveran.com"]
8
+ s.homepage = "http://github.com/soveran/relay"
9
+
10
+ s.rubyforge_project = "relay"
11
+
12
+ s.executables << "relay"
13
+
14
+ s.add_dependency("thor", "~> 0.11")
15
+
16
+ s.files = ["LICENSE", "README.markdown", "Rakefile", "bin/relay", "lib/relay.rb", "relay.gemspec", "test/commands.rb", "test/relay_test.rb", "test/test_helper.rb"]
17
+ end
@@ -0,0 +1,72 @@
1
+ require "open3"
2
+ require "socket"
3
+
4
+ module Test::Commands
5
+ def sh(cmd)
6
+ out, err = nil
7
+
8
+ Open3.popen3(cmd) do |_in, _out, _err|
9
+ out = _out.read
10
+ err = _err.read
11
+ end
12
+
13
+ [out, err]
14
+ end
15
+
16
+ # Runs a command in the background, silencing all output.
17
+ # For debugging purposes, set the environment variable VERBOSE.
18
+ def sh_bg(cmd)
19
+ if ENV["VERBOSE"]
20
+ streams_to_silence = []
21
+ else
22
+ streams_to_silence = [$stdout, $stderr]
23
+ cmd = "#{cmd} 2>&1>/dev/null"
24
+ end
25
+
26
+ silence_stream(*streams_to_silence) do
27
+ (pid = fork) ? Process.detach(pid) : exec(cmd)
28
+ end
29
+ end
30
+
31
+ def listening?(host, port)
32
+ begin
33
+ socket = TCPSocket.new(host, port)
34
+ socket.close unless socket.nil?
35
+ true
36
+ rescue Errno::ECONNREFUSED,
37
+ Errno::EBADF, # Windows
38
+ Errno::EADDRNOTAVAIL # Windows
39
+ false
40
+ end
41
+ end
42
+
43
+ def wait_for_service(host, port, timeout = 3)
44
+ start_time = Time.now
45
+
46
+ until listening?(host, port)
47
+ if timeout && (Time.now > (start_time + timeout))
48
+ raise SocketError.new("Socket #{host}:#{port} did not open within #{timeout} seconds")
49
+ end
50
+ end
51
+
52
+ true
53
+ end
54
+
55
+ def suspects(port)
56
+ list = sh("lsof -i :#{port}").first.split("\n")[1..-1] || []
57
+ list.map {|s| s[/^.+? (\d+)/, 1] }
58
+ end
59
+
60
+ def silence_stream(*streams) #:yeild:
61
+ on_hold = streams.collect{ |stream| stream.dup }
62
+ streams.each do |stream|
63
+ stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
64
+ stream.sync = true
65
+ end
66
+ yield
67
+ ensure
68
+ streams.each_with_index do |stream, i|
69
+ stream.reopen(on_hold[i])
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class TestRelay < Test::Unit::TestCase
4
+ context "relay identify SERVER" do
5
+ should "copy the public key to SERVER" do
6
+ Dir.chdir(root("test", "tmp")) do
7
+ out, err = relay("identify localhost --path #{root("test", "tmp", "authorized_keys")}")
8
+
9
+ assert_match /copied/, out
10
+ assert File.exists?("authorized_keys")
11
+ assert File.read("authorized_keys")[/^ssh-/]
12
+ end
13
+ end
14
+
15
+ should "send a command to SERVER" do
16
+ Dir.chdir(root("test", "tmp")) do
17
+ FileUtils.touch("foobar")
18
+
19
+ out, err = relay("execute \"ls #{root("test", "tmp")}\" localhost")
20
+
21
+ assert_match /foobar/, out
22
+ end
23
+ end
24
+
25
+ should "relay a recipe of commands to SERVER" do
26
+ Dir.chdir(root("test", "tmp")) do
27
+ File.open("recipe.sh", "w") do |file|
28
+ file.puts "cd #{root("test", "tmp")}"
29
+ file.puts "ls -al > list"
30
+ file.puts "cat list"
31
+ end
32
+
33
+ out, err = relay("recipe.sh localhost")
34
+
35
+ assert out["$ cd #{root("test", "tmp")}"]
36
+ assert out["$ ls -al > list"]
37
+ assert out["$ cat list"]
38
+ assert out["recipe.sh"]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,33 @@
1
+ require "rubygems"
2
+ require "contest"
3
+ require "fileutils"
4
+
5
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
6
+
7
+ $:.unshift ROOT
8
+
9
+ require "test/commands"
10
+
11
+ class Test::Unit::TestCase
12
+ include Test::Commands
13
+
14
+ def root(*args)
15
+ File.join(ROOT, *args)
16
+ end
17
+
18
+ def setup
19
+ Dir[root("test", "tmp", "*")].each do |file|
20
+ FileUtils.rm(file)
21
+ end
22
+ end
23
+
24
+ def teardown
25
+ Dir[root("test", "tmp", "*")].each do |file|
26
+ FileUtils.rm(file)
27
+ end
28
+ end
29
+
30
+ def relay(args = nil)
31
+ sh("ruby -rubygems #{root "bin/relay"} #{args}")
32
+ end
33
+ end
metadata CHANGED
@@ -1,30 +1,50 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
- - TBD
7
+ - Damian Janowski
8
+ - Michel Martens
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-08-07 00:00:00 -03:00
13
+ date: 2009-11-21 00:00:00 -03:00
13
14
  default_executable:
14
- dependencies: []
15
-
16
- description: TBD
17
- email: TBD
18
- executables: []
19
-
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: thor
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: "0.11"
25
+ version:
26
+ description: Relay allows you to execute remote commands via SSH with ease.
27
+ email:
28
+ - djanowski@dimaion.com
29
+ - michel@soveran.com
30
+ executables:
31
+ - relay
20
32
  extensions: []
21
33
 
22
34
  extra_rdoc_files: []
23
35
 
24
- files: []
25
-
36
+ files:
37
+ - LICENSE
38
+ - README.markdown
39
+ - Rakefile
40
+ - bin/relay
41
+ - lib/relay.rb
42
+ - relay.gemspec
43
+ - test/commands.rb
44
+ - test/relay_test.rb
45
+ - test/test_helper.rb
26
46
  has_rdoc: true
27
- homepage:
47
+ homepage: http://github.com/soveran/relay
28
48
  licenses: []
29
49
 
30
50
  post_install_message:
@@ -46,10 +66,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
66
  version:
47
67
  requirements: []
48
68
 
49
- rubyforge_project:
69
+ rubyforge_project: relay
50
70
  rubygems_version: 1.3.5
51
71
  signing_key:
52
72
  specification_version: 3
53
- summary: TBD
73
+ summary: Relay commands over SSH
54
74
  test_files: []
55
75