remote_executor 0.6.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +7 -18
- data/bin/remote_executor +10 -20
- data/lib/loader.rb +9 -0
- data/lib/remote_executor/cli_application.rb +58 -0
- data/lib/remote_executor/options_parser.rb +44 -32
- data/lib/remote_executor/system.rb +24 -10
- data/lib/remote_executor/systems.rb +50 -0
- data/lib/remote_executor/version.rb +10 -12
- data/test/test_system.rb +82 -0
- data/test/test_systems.rb +67 -0
- metadata +49 -45
- data/lib/remote_executor.rb +0 -7
- data/lib/remote_executor/app.rb +0 -5
- data/lib/remote_executor/cli.rb +0 -20
- data/lib/remote_executor/config.rb +0 -53
- data/lib/remote_executor/system_config.rb +0 -20
- data/test/unit/tc_cli.rb +0 -18
- data/test/unit/tc_config.rb +0 -44
- data/test/unit/tc_system.rb +0 -35
- data/test/unit/tc_system_config.rb +0 -35
- data/test/unit/ts_all.rb +0 -24
data/README.rdoc
CHANGED
@@ -2,36 +2,35 @@
|
|
2
2
|
|
3
3
|
A simplistic remote command launcher over SSH conections
|
4
4
|
|
5
|
-
|
6
5
|
== Installing
|
7
6
|
|
8
|
-
The latest stable version is published in
|
7
|
+
The latest stable version is published in rubygems.
|
9
8
|
|
10
|
-
gem source --add http://
|
9
|
+
gem source --add http://rubygems.org
|
11
10
|
gem install remote_executor
|
12
11
|
|
13
|
-
|
14
12
|
== Notes
|
15
13
|
|
16
14
|
At the moment the gem have a strong dependency of your local SSH configuration, commonly located at ${HOME}/.ssh/config, this is only
|
17
15
|
a very simple mechanism for keep safe your private data, but this need a ugly configuration with a fake user name in the connection
|
18
16
|
process. I provide a basic SSH config if your aren´t familiar with this configuration stuff
|
19
17
|
|
20
|
-
|
21
18
|
=== How to use
|
22
19
|
|
23
20
|
An example may be the next. Launch the command 'hostname' over your production farm system named 'myFarm' configured in your home
|
24
21
|
directory into the file ${HOME}/.remoteexecutorrc like this:
|
25
22
|
|
26
23
|
---
|
27
|
-
- :name: 'myFarm
|
24
|
+
- :name: 'myFarm'
|
25
|
+
:environment: 'development'
|
28
26
|
:user: 'admin'
|
29
27
|
:hosts:
|
30
28
|
- 'myHost1'
|
31
29
|
- 'myHost2'
|
32
30
|
- 'myHost3'
|
33
31
|
- 'myHost4'
|
34
|
-
- :name: 'myFarm
|
32
|
+
- :name: 'myFarm'
|
33
|
+
:environment: 'production'
|
35
34
|
:user: 'admin'
|
36
35
|
:hosts:
|
37
36
|
- 'myHost1'
|
@@ -60,20 +59,10 @@ with this line:
|
|
60
59
|
|
61
60
|
remote_executor --system=myFarmID --command='hostname'
|
62
61
|
|
63
|
-
|
64
|
-
=== Configuration
|
65
|
-
|
66
|
-
The configuration for this gem is divided in 3 levels
|
67
|
-
|
68
|
-
* Via --config command option
|
69
|
-
* Via your shell environment with the variable REMOTEEXECUTOR (export REMOTEEXECUTOR="${HOME}/configs/remote_executor_settins.yml")
|
70
|
-
* Via your user preferences located in the ${HOME}/.remoteexecutorrc file
|
71
|
-
|
72
|
-
|
62
|
+
|
73
63
|
== TODO
|
74
64
|
|
75
65
|
* Document all this stuff in english... I promise
|
76
|
-
* Write some test could be a gread idea
|
77
66
|
* Take decisions about user by hosts or user by farm
|
78
67
|
* Pullrequests are welcome... of course
|
79
68
|
|
data/bin/remote_executor
CHANGED
@@ -1,23 +1,13 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby -W0
|
2
|
+
# encoding: utf-8
|
2
3
|
|
3
|
-
$:.unshift File.join( File.dirname( __FILE__ ), %w[.. lib] )
|
4
|
+
$:.unshift( File.join( File.dirname( __FILE__ ), %w[.. lib] ) )
|
4
5
|
|
5
|
-
require '
|
6
|
-
require 'remote_executor'
|
6
|
+
require 'loader'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Choice.choices[:environment],
|
15
|
-
Choice.choices[:command]
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
##
|
22
|
-
# ::Main::
|
23
|
-
RemoteExecutor::CLIApplication.run
|
8
|
+
RemoteExecutor::CliApplication.run(
|
9
|
+
Choice.choices[:config],
|
10
|
+
Choice.choices[:log],
|
11
|
+
Choice.choices[:threaded],
|
12
|
+
Choice.choices[:system],
|
13
|
+
Choice.choices[:commands] )
|
data/lib/loader.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mini_logger'
|
3
|
+
require 'net/ssh'
|
4
|
+
|
5
|
+
|
6
|
+
module RemoteExecutor
|
7
|
+
##
|
8
|
+
# CLI Application a simple point of entry
|
9
|
+
class CliApplication
|
10
|
+
|
11
|
+
COMMAND_SEPARATOR = ";"
|
12
|
+
|
13
|
+
|
14
|
+
def self.execute_commands( server, user, commands, ssh_options={ :config=>true } )
|
15
|
+
|
16
|
+
Net::SSH.start( server, user, ssh_options ) do |ssh|
|
17
|
+
|
18
|
+
commands.split( COMMAND_SEPARATOR ).each do |command|
|
19
|
+
|
20
|
+
MiniLogger.debug( "Executing command #{user}@#{server} '#{command}'")
|
21
|
+
ssh.exec( "#{command}" )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def self.process_system( system, commands, threaded )
|
28
|
+
|
29
|
+
if( threaded )
|
30
|
+
|
31
|
+
threads = []
|
32
|
+
|
33
|
+
system.hosts.each do |server|
|
34
|
+
|
35
|
+
threads << Thread.new( server ) { |t| execute_commands( server, system.user, commands ) }
|
36
|
+
end
|
37
|
+
|
38
|
+
threads.each { |t| t.join }
|
39
|
+
else
|
40
|
+
|
41
|
+
system.hosts.each do |server|
|
42
|
+
execute_commands( server, system.user, commands )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def self.run( systems_config, log, threaded, name, commands )
|
49
|
+
|
50
|
+
MiniLogger.configure( :log_channel=>log, :log_level=>::Logger::DEBUG )
|
51
|
+
process_system( Systems.new( systems_config ).find_by_name( name ), commands, threaded )
|
52
|
+
rescue SystemsFileError =>sfe
|
53
|
+
MiniLogger.error( sfe.message )
|
54
|
+
rescue SystemNotFound =>snf
|
55
|
+
MiniLogger.error( snf.message )
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,38 +2,50 @@ require 'rubygems'
|
|
2
2
|
require 'choice'
|
3
3
|
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
long '--help'
|
34
|
-
desc "Show this screen"
|
35
|
-
end
|
5
|
+
Choice.options do
|
6
|
+
header ''
|
7
|
+
header ' Specific options:'
|
8
|
+
|
9
|
+
option :config, :required=>true do
|
10
|
+
short '-c'
|
11
|
+
long '--config'
|
12
|
+
desc 'The YAML config file'
|
13
|
+
end
|
14
|
+
|
15
|
+
option :system, :required=>true do
|
16
|
+
short '-s'
|
17
|
+
long '--system'
|
18
|
+
desc 'The System name'
|
19
|
+
end
|
20
|
+
|
21
|
+
option :commands, :required=>true do
|
22
|
+
short '-c'
|
23
|
+
long '--commands'
|
24
|
+
desc 'The Command chain cmd1;cmd2;cmd3'
|
25
|
+
end
|
26
|
+
|
27
|
+
option :log, :required=>false do
|
28
|
+
short '-l'
|
29
|
+
long '--log'
|
30
|
+
desc 'The log file'
|
31
|
+
default '/tmp/remote_executor.log'
|
32
|
+
end
|
36
33
|
|
37
|
-
|
34
|
+
option :threaded, :required=>false do
|
35
|
+
short '-t'
|
36
|
+
long '--threaded'
|
37
|
+
desc 'value: true | false, executes the commands over a server in paralel or not'
|
38
|
+
default 'true'
|
39
|
+
end
|
40
|
+
|
41
|
+
separator ''
|
42
|
+
separator ' Common options:'
|
43
|
+
|
44
|
+
option :help do
|
45
|
+
short '-h'
|
46
|
+
long '--help'
|
47
|
+
desc "Show this screen"
|
38
48
|
end
|
49
|
+
|
50
|
+
separator ''
|
39
51
|
end
|
@@ -1,17 +1,31 @@
|
|
1
1
|
module RemoteExecutor
|
2
|
-
|
2
|
+
|
3
|
+
##
|
4
|
+
# System represents a set of hosts that implement a service
|
5
|
+
class System
|
3
6
|
|
4
|
-
|
7
|
+
attr_reader :name, :environment, :user, :hosts
|
8
|
+
|
9
|
+
private
|
10
|
+
def self.validate_parameters( parameters )
|
11
|
+
|
12
|
+
raise ArgumentError.new( "Parameters must be a Hash" ) unless parameters.instance_of?( Hash )
|
13
|
+
raise ArgumentError.new( "Some parameters are not present" ) unless( parameters[:name] && parameters[:user] && parameters[:hosts] && parameters[:environment] )
|
14
|
+
end
|
15
|
+
|
16
|
+
public
|
17
|
+
def initialize( parameters )
|
5
18
|
|
6
|
-
|
7
|
-
fail "Bad parameters"
|
8
|
-
end
|
19
|
+
System.validate_parameters( parameters )
|
9
20
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
21
|
+
@name = parameters[:name]
|
22
|
+
@environment = parameters[:environment]
|
23
|
+
@user = parameters[:user]
|
24
|
+
@hosts = parameters[:hosts]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{@user}\@#{@name}.#{@environment}: #{@hosts.inspect}"
|
15
29
|
end
|
16
30
|
end
|
17
31
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'remote_executor/system'
|
4
|
+
|
5
|
+
|
6
|
+
module RemoteExecutor
|
7
|
+
|
8
|
+
##
|
9
|
+
# Utility exception
|
10
|
+
class SystemNotFound < StandardError
|
11
|
+
end
|
12
|
+
|
13
|
+
class SystemsFileError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# A collection of System
|
18
|
+
class Systems
|
19
|
+
|
20
|
+
def find_by_name( name )
|
21
|
+
|
22
|
+
@systems.each do |entry|
|
23
|
+
|
24
|
+
return SystemFactory.create( entry ) if( name == entry[:name] )
|
25
|
+
end
|
26
|
+
|
27
|
+
raise SystemNotFound.new( "System: '#{name}' not found" )
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize( system_file )
|
31
|
+
|
32
|
+
@systems = YAML::load_file( system_file )
|
33
|
+
rescue Exception => e
|
34
|
+
raise SystemsFileError.new( e.message )
|
35
|
+
else
|
36
|
+
self
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# A simple factory
|
42
|
+
module SystemFactory
|
43
|
+
extend self
|
44
|
+
|
45
|
+
def create( entry )
|
46
|
+
|
47
|
+
return System.new( entry )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,14 +1,12 @@
|
|
1
|
-
module RemoteExecutor
|
1
|
+
module RemoteExecutor
|
2
2
|
module Version
|
3
|
+
INFO = {
|
4
|
+
:major =>0,
|
5
|
+
:minor =>9,
|
6
|
+
:patch =>0
|
7
|
+
}
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
9
|
-
end
|
10
|
-
|
11
|
-
NAME = 'remote_executor'
|
12
|
-
VERSION = Version::STRING
|
13
|
-
COMPLETE_NAME = "#{NAME}-#{VERSION}"
|
14
|
-
end
|
9
|
+
NAME = 'remote_executor'
|
10
|
+
NUMBER = INFO.values.join( '.' )
|
11
|
+
end
|
12
|
+
end
|
data/test/test_system.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
$:.unshift( File.join( File.dirname( __FILE__ ), %w[.. lib] ) )
|
2
|
+
|
3
|
+
#require 'test/unit'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'shoulda'
|
6
|
+
require 'remote_executor/system'
|
7
|
+
|
8
|
+
|
9
|
+
class SystemTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
context "System" do
|
12
|
+
|
13
|
+
TEST_SYSTEM_NAME = 'server'
|
14
|
+
TEST_SYSTEM_ENVIRONMENT = 'production'
|
15
|
+
TEST_SYSTEM_USER = 'user'
|
16
|
+
TEST_SYSTEM_HOSTS = [
|
17
|
+
'server1.system.environment',
|
18
|
+
'server2.system.environment',
|
19
|
+
'server3.system.environment',
|
20
|
+
'server4.system.environment'
|
21
|
+
]
|
22
|
+
TEST_PARAMS = {
|
23
|
+
:name =>TEST_SYSTEM_NAME,
|
24
|
+
:environment => TEST_SYSTEM_ENVIRONMENT,
|
25
|
+
:user =>TEST_SYSTEM_USER,
|
26
|
+
:hosts =>TEST_SYSTEM_HOSTS
|
27
|
+
}
|
28
|
+
|
29
|
+
setup do
|
30
|
+
@test_system = RemoteExecutor::System.new( TEST_PARAMS )
|
31
|
+
end
|
32
|
+
|
33
|
+
should "raise ArgumentError for a no hash parameter" do
|
34
|
+
|
35
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( 1 ) }
|
36
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( :foo ) }
|
37
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( "foo" ) }
|
38
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( [1,2,3] ) }
|
39
|
+
end
|
40
|
+
|
41
|
+
should "raise ArgumentError for empty hash" do
|
42
|
+
assert_raise( ArgumentError ) { RemoteExecutor::System.new( { } ) }
|
43
|
+
end
|
44
|
+
|
45
|
+
should "raise ArgumentError for empty hosts" do
|
46
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( { :name=>TEST_SYSTEM_NAME, :environment=>TEST_SYSTEM_ENVIRONMENT, :user=>TEST_SYSTEM_USER } ) }
|
47
|
+
end
|
48
|
+
|
49
|
+
should "raise ArgumentError for empty user" do
|
50
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( { :name=>TEST_SYSTEM_NAME, :environment=>TEST_SYSTEM_ENVIRONMENT, :hosts=>TEST_SYSTEM_HOSTS } ) }
|
51
|
+
end
|
52
|
+
|
53
|
+
should "raise ArgumentError for empty environment" do
|
54
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( { :name=>TEST_SYSTEM_NAME, :user=>TEST_SYSTEM_USER, :hosts=>TEST_SYSTEM_HOSTS } ) }
|
55
|
+
end
|
56
|
+
|
57
|
+
should "raise ArgumentError for empty name" do
|
58
|
+
assert_raises( ArgumentError ) { RemoteExecutor::System.new( { :environment=>TEST_SYSTEM_ENVIRONMENT, :user=>TEST_SYSTEM_USER, :hosts=>TEST_SYSTEM_HOSTS } ) }
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
should "create a System object" do
|
63
|
+
assert_instance_of( RemoteExecutor::System, @test_system )
|
64
|
+
end
|
65
|
+
|
66
|
+
should "create a valid System object" do
|
67
|
+
assert( @test_system.name && @test_system.user && @test_system.hosts )
|
68
|
+
end
|
69
|
+
|
70
|
+
should "the name equal" do
|
71
|
+
assert_equal( TEST_SYSTEM_NAME, @test_system.name )
|
72
|
+
end
|
73
|
+
|
74
|
+
should "the user equal" do
|
75
|
+
assert_equal( TEST_SYSTEM_USER, @test_system.user )
|
76
|
+
end
|
77
|
+
|
78
|
+
should "the hosts equal" do
|
79
|
+
assert_equal( TEST_SYSTEM_HOSTS, @test_system.hosts )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
$:.unshift( File.join( File.dirname( __FILE__ ), %w[.. .. lib] ) )
|
2
|
+
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'shoulda'
|
7
|
+
require 'remote_executor/system'
|
8
|
+
require 'remote_executor/systems'
|
9
|
+
|
10
|
+
|
11
|
+
class SystemsTest < Test::Unit::TestCase
|
12
|
+
|
13
|
+
context "Systems" do
|
14
|
+
|
15
|
+
TEST_SYSTEM_NAME = 'server'
|
16
|
+
TEST_SYSTEM_ENVIRONMENT = 'environment'
|
17
|
+
TEST_SYSTEM_USER = 'user'
|
18
|
+
TEST_SYSTEM_HOSTS = [
|
19
|
+
'server1.system.environment',
|
20
|
+
'server2.system.environment',
|
21
|
+
'server3.system.environment',
|
22
|
+
'server4.system.environment'
|
23
|
+
]
|
24
|
+
TEST_PARAMS = {
|
25
|
+
:name =>TEST_SYSTEM_NAME,
|
26
|
+
:environment =>TEST_SYSTEM_ENVIRONMENT,
|
27
|
+
:user =>TEST_SYSTEM_USER,
|
28
|
+
:hosts =>TEST_SYSTEM_HOSTS
|
29
|
+
}
|
30
|
+
|
31
|
+
setup do
|
32
|
+
|
33
|
+
@fake_systems_file = "fakeSystemsFile.yml"
|
34
|
+
@systems_file = File.join( File.dirname( __FILE__ ), %w[fixtures systems.yml] )
|
35
|
+
@systems = RemoteExecutor::Systems.new( @systems_file )
|
36
|
+
end
|
37
|
+
|
38
|
+
should "the systems file do not exist" do
|
39
|
+
assert_raises( RemoteExecutor::SystemsFileError ) { RemoteExecutor::Systems.new( @fake_systems_file ) }
|
40
|
+
end
|
41
|
+
|
42
|
+
should "load systems from file" do
|
43
|
+
assert( File.exist?( @systems_file ) )
|
44
|
+
assert( @systems )
|
45
|
+
end
|
46
|
+
|
47
|
+
should "find some system by name" do
|
48
|
+
assert_instance_of( RemoteExecutor::System, @systems.find_by_name( TEST_SYSTEM_NAME ) )
|
49
|
+
end
|
50
|
+
|
51
|
+
should "find system by name equals name" do
|
52
|
+
assert_equal( TEST_SYSTEM_NAME, @systems.find_by_name( TEST_SYSTEM_NAME ).name )
|
53
|
+
end
|
54
|
+
|
55
|
+
should "find system by name equals user" do
|
56
|
+
assert_equal( TEST_SYSTEM_USER, @systems.find_by_name( TEST_SYSTEM_NAME ).user )
|
57
|
+
end
|
58
|
+
|
59
|
+
should "find system by name equals hosts" do
|
60
|
+
assert_equal( TEST_SYSTEM_HOSTS, @systems.find_by_name( TEST_SYSTEM_NAME ).hosts )
|
61
|
+
end
|
62
|
+
|
63
|
+
should "find system by name raises exception" do
|
64
|
+
assert_raises( RemoteExecutor::SystemNotFound ) { @systems.find_by_name( 'thisSystemDoNotExist' ) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remote_executor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 6
|
9
|
-
- 0
|
10
|
-
version: 0.6.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.9.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Javier Juarez
|
@@ -15,43 +10,66 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date:
|
13
|
+
date: 2011-03-05 00:00:00 +01:00
|
19
14
|
default_executable: remote_executor
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
22
17
|
name: choice
|
23
|
-
prerelease: false
|
24
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
19
|
none: false
|
26
20
|
requirements:
|
27
21
|
- - ">="
|
28
22
|
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
- 1
|
33
|
-
- 0
|
34
|
-
version: 0.1.0
|
23
|
+
version: "0"
|
35
24
|
type: :runtime
|
25
|
+
prerelease: false
|
36
26
|
version_requirements: *id001
|
37
27
|
- !ruby/object:Gem::Dependency
|
38
28
|
name: net-ssh
|
39
|
-
prerelease: false
|
40
29
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
30
|
none: false
|
42
31
|
requirements:
|
43
32
|
- - ">="
|
44
33
|
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
segments:
|
47
|
-
- 2
|
48
|
-
- 0
|
49
|
-
- 0
|
50
|
-
version: 2.0.0
|
34
|
+
version: "0"
|
51
35
|
type: :runtime
|
36
|
+
prerelease: false
|
52
37
|
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: mini_logger
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: choice
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: net-ssh
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 2.0.0
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *id005
|
53
71
|
description: A little remote command launcher over SSH connections
|
54
|
-
email: javier.
|
72
|
+
email: javier.juarez@gmail.com
|
55
73
|
executables:
|
56
74
|
- remote_executor
|
57
75
|
extensions: []
|
@@ -60,20 +78,15 @@ extra_rdoc_files:
|
|
60
78
|
- README.rdoc
|
61
79
|
files:
|
62
80
|
- bin/remote_executor
|
63
|
-
- lib/
|
64
|
-
- lib/remote_executor/
|
65
|
-
- lib/remote_executor/cli.rb
|
66
|
-
- lib/remote_executor/config.rb
|
81
|
+
- lib/loader.rb
|
82
|
+
- lib/remote_executor/cli_application.rb
|
67
83
|
- lib/remote_executor/options_parser.rb
|
68
84
|
- lib/remote_executor/system.rb
|
69
|
-
- lib/remote_executor/
|
85
|
+
- lib/remote_executor/systems.rb
|
70
86
|
- lib/remote_executor/version.rb
|
71
87
|
- README.rdoc
|
72
|
-
- test/
|
73
|
-
- test/
|
74
|
-
- test/unit/tc_system.rb
|
75
|
-
- test/unit/tc_system_config.rb
|
76
|
-
- test/unit/ts_all.rb
|
88
|
+
- test/test_system.rb
|
89
|
+
- test/test_systems.rb
|
77
90
|
has_rdoc: true
|
78
91
|
homepage: http://github.com/jjuarez/remote_executor
|
79
92
|
licenses:
|
@@ -88,29 +101,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
101
|
requirements:
|
89
102
|
- - ">="
|
90
103
|
- !ruby/object:Gem::Version
|
91
|
-
hash: 3
|
92
|
-
segments:
|
93
|
-
- 0
|
94
104
|
version: "0"
|
95
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
106
|
none: false
|
97
107
|
requirements:
|
98
108
|
- - ">="
|
99
109
|
- !ruby/object:Gem::Version
|
100
|
-
hash: 3
|
101
|
-
segments:
|
102
|
-
- 0
|
103
110
|
version: "0"
|
104
111
|
requirements: []
|
105
112
|
|
106
113
|
rubyforge_project: http://github.com/jjuarez/remote_executor
|
107
|
-
rubygems_version: 1.
|
114
|
+
rubygems_version: 1.5.2
|
108
115
|
signing_key:
|
109
116
|
specification_version: 3
|
110
117
|
summary: A very simple gem that helps to launch remote commands over SSH connections
|
111
118
|
test_files:
|
112
|
-
- test/
|
113
|
-
- test/
|
114
|
-
- test/unit/tc_system.rb
|
115
|
-
- test/unit/tc_system_config.rb
|
116
|
-
- test/unit/ts_all.rb
|
119
|
+
- test/test_system.rb
|
120
|
+
- test/test_systems.rb
|
data/lib/remote_executor.rb
DELETED
data/lib/remote_executor/app.rb
DELETED
data/lib/remote_executor/cli.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'net/ssh'
|
3
|
-
|
4
|
-
|
5
|
-
module RemoteExecutor
|
6
|
-
class Cli
|
7
|
-
|
8
|
-
DEFAULT_SSH_OPTIONS = { :config=>true }
|
9
|
-
|
10
|
-
def self.execute( name, environment, command, ssh_options=DEFAULT_SSH_OPTIONS )
|
11
|
-
|
12
|
-
system = System.new( SystemConfig.instance.find_system( name ) )
|
13
|
-
|
14
|
-
system.hosts.each do |host|
|
15
|
-
|
16
|
-
Net::SSH.start( host, system.user, ssh_options ) { |ssh| ssh.exec( "#{command}" ) }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'choice'
|
3
|
-
require 'yaml'
|
4
|
-
require 'app'
|
5
|
-
|
6
|
-
|
7
|
-
module RemoteExecutor
|
8
|
-
|
9
|
-
class YAMLFileNotFound < Exception
|
10
|
-
end
|
11
|
-
|
12
|
-
class ConfigurationNotLoaded < Exception
|
13
|
-
end
|
14
|
-
|
15
|
-
class ConfigurationError < Exception
|
16
|
-
end
|
17
|
-
|
18
|
-
class Config
|
19
|
-
|
20
|
-
def load_config( config_file )
|
21
|
-
|
22
|
-
@config = YAML.load_file( config_file )
|
23
|
-
rescue Exception => e
|
24
|
-
raise YAMLFileNotFound.new( e.message )
|
25
|
-
end
|
26
|
-
|
27
|
-
public
|
28
|
-
def initialize
|
29
|
-
|
30
|
-
cli_cfn = Choice.choices[:config]
|
31
|
-
if( cli_cfn )
|
32
|
-
|
33
|
-
load_config( cli_cfn )
|
34
|
-
else
|
35
|
-
environment_cfn = ENV[CLIApplication::NAME.upcase]
|
36
|
-
|
37
|
-
if( environment_cfn && '' != environment_cfn )
|
38
|
-
|
39
|
-
load_config( environment_cfn )
|
40
|
-
else
|
41
|
-
user_cfn = "#{ENV['HOME']}/.#{CLIApplication::NAME.downcase}rc"
|
42
|
-
|
43
|
-
if( user_cfn && '' != user_cfn && File.exist?( user_cfn ) )
|
44
|
-
|
45
|
-
load_config( user_cfn )
|
46
|
-
else
|
47
|
-
raise ConfigurationNotLoaded.new( "Configuration not loaded" )
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
require 'config'
|
3
|
-
|
4
|
-
|
5
|
-
module RemoteExecutor
|
6
|
-
|
7
|
-
class SystemConfig < Config
|
8
|
-
include Singleton
|
9
|
-
|
10
|
-
def find_system( system_name )
|
11
|
-
|
12
|
-
@config.each do |system|
|
13
|
-
|
14
|
-
return system if( system[:name] == system_name )
|
15
|
-
end
|
16
|
-
|
17
|
-
raise ConfigurationError.new( "System: '#{system_name}' not found" )
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/test/unit/tc_cli.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
$:.unshift File.join( File.dirname( __FILE__ ), %w[.. .. lib remote_executor] )
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'cli'
|
5
|
-
|
6
|
-
|
7
|
-
class TC_Cli < Test::Unit::TestCase
|
8
|
-
# def setup
|
9
|
-
# end
|
10
|
-
#
|
11
|
-
# def teardown
|
12
|
-
# end
|
13
|
-
|
14
|
-
def test_execute
|
15
|
-
true
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
data/test/unit/tc_config.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
$:.unshift File.join( File.dirname( __FILE__ ), %w[.. .. lib remote_executor] )
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'config'
|
6
|
-
|
7
|
-
|
8
|
-
class TC_Config < Test::Unit::TestCase
|
9
|
-
|
10
|
-
def setup
|
11
|
-
@fixtures_file = '../fixtures/settings.yml'
|
12
|
-
@test_file = '/tmp/settings.yml'
|
13
|
-
@rc_file = "#{ENV['HOME']}/.#{RemoteExecutor::CLIApplication::NAME.downcase}rc"
|
14
|
-
end
|
15
|
-
|
16
|
-
def teardown
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_initialize()
|
20
|
-
assert_raises( RemoteExecutor::YAMLFileNotFound ) { RemoteExecutor::Config.new( "AppFoo" ) }
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_initialize_environment
|
24
|
-
|
25
|
-
FileUtils.cp( @fixtures_file, @test_file )
|
26
|
-
ENV[RemoteExecutor::CLIApplication::NAME.upcase] = @test_file
|
27
|
-
|
28
|
-
assert_instance_of( RemoteExecutor::Config, RemoteExecutor::Config.new )
|
29
|
-
|
30
|
-
ENV[RemoteExecutor::CLIApplication::NAME.upcase] = ""
|
31
|
-
FileUtils.rm( @test_file )
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_initialize_rcfile
|
35
|
-
# File not found
|
36
|
-
assert_raises( RemoteExecutor::ConfigurationNotLoaded ) { RemoteExecutor::Config.new }
|
37
|
-
|
38
|
-
FileUtils.cp( @fixtures_file, @rc_file )
|
39
|
-
|
40
|
-
assert_instance_of( RemoteExecutor::Config, RemoteExecutor::Config.new )
|
41
|
-
|
42
|
-
FileUtils.remove( @rc_file )
|
43
|
-
end
|
44
|
-
end
|
data/test/unit/tc_system.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
$:.unshift File.join( File.dirname( __FILE__ ), %w[.. .. lib remote_executor] )
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'system'
|
5
|
-
|
6
|
-
|
7
|
-
class TC_System < Test::Unit::TestCase
|
8
|
-
|
9
|
-
TEST_SYSTEM_NAME = 'wi.pro'
|
10
|
-
TEST_SYSTEM_USER = 'root'
|
11
|
-
TEST_SYSTEM_HOSTS = [ 'lr1.wi.pro', 'lr2.wi.pro', 'alf1.wi.pro', 'alf2.wi.pro' ]
|
12
|
-
TEST_PARAMS = {
|
13
|
-
:name=>TEST_SYSTEM_NAME,
|
14
|
-
:user=>TEST_SYSTEM_USER,
|
15
|
-
:hosts=>TEST_SYSTEM_HOSTS
|
16
|
-
}
|
17
|
-
|
18
|
-
def setup
|
19
|
-
end
|
20
|
-
|
21
|
-
def teardown
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_initialize
|
25
|
-
assert_raise( RuntimeError) { RemoteExecutor::System.new( "foo" ) }
|
26
|
-
|
27
|
-
test_system = RemoteExecutor::System.new( TEST_PARAMS )
|
28
|
-
|
29
|
-
assert_instance_of( RemoteExecutor::System, test_system )
|
30
|
-
assert_equal( TEST_SYSTEM_NAME, test_system.name)
|
31
|
-
assert_equal( TEST_SYSTEM_USER, test_system.user )
|
32
|
-
assert_equal( TEST_SYSTEM_HOSTS, test_system.hosts )
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
$:.unshift File.join( File.dirname( __FILE__ ), %w[.. .. lib remote_executor] )
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'system_config'
|
5
|
-
require 'fileutils'
|
6
|
-
|
7
|
-
|
8
|
-
class TC_SystemConfig < Test::Unit::TestCase
|
9
|
-
|
10
|
-
TEST_GOOD_SYSTEM_ID = 'wi.pro'
|
11
|
-
TEST_SYSTEM_USER = 'root'
|
12
|
-
TEST_SYSTEM_HOSTS = [ 'lr1.wi.pro', 'lr2.wi.pro', 'alf1.wi.pro', 'alf2.wi.pro' ]
|
13
|
-
|
14
|
-
def setup
|
15
|
-
@fixtures_file = "../fixtures/settings.yml"
|
16
|
-
@test_file = "/tmp/settings.yml"
|
17
|
-
|
18
|
-
FileUtils.copy( @fixtures_file, @test_file )
|
19
|
-
ENV[RemoteExecutor::CLIApplication::NAME.upcase] = @test_file
|
20
|
-
@system_config = RemoteExecutor::SystemConfig.instance( @test_file )
|
21
|
-
end
|
22
|
-
|
23
|
-
def teardown
|
24
|
-
FileUtils.remove( @test_file )
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_find_system
|
28
|
-
|
29
|
-
assert_instance_of( Hash, @system_config.find_system( TEST_GOOD_SYSTEM_ID ))
|
30
|
-
assert_equal( TEST_GOOD_SYSTEM_ID, @system_config.find_system( TEST_GOOD_SYSTEM_ID )[:name] )
|
31
|
-
assert_equal( TEST_SYSTEM_USER, @system_config.find_system( TEST_GOOD_SYSTEM_ID )[:user] )
|
32
|
-
assert_equal( TEST_SYSTEM_HOSTS, @system_config.find_system( TEST_GOOD_SYSTEM_ID )[:hosts] )
|
33
|
-
assert_raise( RemoteExecutor::ConfigurationError ) { @system_config.find_system( 'fooSystem' ) }
|
34
|
-
end
|
35
|
-
end
|
data/test/unit/ts_all.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'test/unit/testsuite'
|
2
|
-
require 'test/unit/ui/console/testrunner'
|
3
|
-
require 'tc_config'
|
4
|
-
require 'tc_system_config'
|
5
|
-
require 'tc_system'
|
6
|
-
require 'tc_cli'
|
7
|
-
|
8
|
-
|
9
|
-
class TS_RemoteExecutorTests
|
10
|
-
|
11
|
-
def self.suite
|
12
|
-
suite = Test::Unit::TestSuite.new
|
13
|
-
|
14
|
-
suite << TC_Config.suite
|
15
|
-
suite << TC_SystemConfig.suite
|
16
|
-
suite << TC_System.suite
|
17
|
-
suite << TC_Cli.suite
|
18
|
-
|
19
|
-
return suite
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
Test::Unit::UI::Console::TestRunner.run( TS_RemoteExecutorTests )
|