remote_executor 0.4.0 → 0.6.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.
- data/README.rdoc +8 -7
- data/bin/remote_executor +11 -11
- data/lib/remote_executor.rb +2 -8
- data/lib/remote_executor/app.rb +5 -0
- data/lib/remote_executor/cli.rb +7 -12
- data/lib/remote_executor/config.rb +39 -20
- data/lib/remote_executor/options_parser.rb +4 -7
- data/lib/remote_executor/system.rb +4 -9
- data/lib/remote_executor/system_config.rb +9 -5
- data/lib/remote_executor/version.rb +8 -7
- data/test/unit/tc_cli.rb +18 -0
- data/test/unit/tc_config.rb +44 -0
- data/test/unit/tc_system.rb +35 -0
- data/test/unit/tc_system_config.rb +35 -0
- data/test/unit/ts_all.rb +24 -0
- metadata +24 -10
data/README.rdoc
CHANGED
@@ -24,17 +24,15 @@ An example may be the next. Launch the command 'hostname' over your production f
|
|
24
24
|
directory into the file ${HOME}/.remoteexecutorrc like this:
|
25
25
|
|
26
26
|
---
|
27
|
-
- :name: 'myFarm'
|
28
|
-
:
|
29
|
-
:user: admin
|
27
|
+
- :name: 'myFarm.development'
|
28
|
+
:user: 'admin'
|
30
29
|
:hosts:
|
31
30
|
- 'myHost1'
|
32
31
|
- 'myHost2'
|
33
32
|
- 'myHost3'
|
34
33
|
- 'myHost4'
|
35
|
-
- :name: 'myFarm'
|
36
|
-
:
|
37
|
-
:user: admin
|
34
|
+
- :name: 'myFarm.production'
|
35
|
+
:user: 'admin'
|
38
36
|
:hosts:
|
39
37
|
- 'myHost1'
|
40
38
|
- 'myHost2'
|
@@ -45,10 +43,13 @@ you need this minimal SSH configuration (${HOME}/.ssh/config) for the example
|
|
45
43
|
|
46
44
|
Host myHost1
|
47
45
|
HostName myhost1.example.com
|
46
|
+
|
48
47
|
Host myHost2
|
49
48
|
HostName myhost2.example.com
|
49
|
+
|
50
50
|
Host myHost3
|
51
51
|
HostName myhost3.example.com
|
52
|
+
|
52
53
|
Host myHost4
|
53
54
|
HostName myhost4.example.com
|
54
55
|
|
@@ -57,7 +58,7 @@ you need this minimal SSH configuration (${HOME}/.ssh/config) for the example
|
|
57
58
|
|
58
59
|
with this line:
|
59
60
|
|
60
|
-
remote_executor --system=
|
61
|
+
remote_executor --system=myFarmID --command='hostname'
|
61
62
|
|
62
63
|
|
63
64
|
=== Configuration
|
data/bin/remote_executor
CHANGED
@@ -5,19 +5,19 @@ $:.unshift File.join( File.dirname( __FILE__ ), %w[.. lib] )
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'remote_executor'
|
7
7
|
|
8
|
-
module
|
8
|
+
module RemoteExecutor
|
9
|
+
module CLIApplication
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
11
|
+
def self.run
|
12
|
+
Cli::execute(
|
13
|
+
Choice.choices[:system],
|
14
|
+
Choice.choices[:environment],
|
15
|
+
Choice.choices[:command]
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
19
|
end
|
20
20
|
|
21
21
|
##
|
22
22
|
# ::Main::
|
23
|
-
CLIApplication.
|
23
|
+
RemoteExecutor::CLIApplication.run
|
data/lib/remote_executor.rb
CHANGED
@@ -1,13 +1,7 @@
|
|
1
|
-
|
2
|
-
%w[rubygems yaml singleton choice net/ssh].each { |gem| require gem }
|
3
|
-
rescue LoadError => e
|
4
|
-
fail "Some gem dependencies can not be loaded: #{e.message}"
|
5
|
-
end
|
6
|
-
|
7
|
-
$:.unshift File.join( File.dirname( __FILE__), 'remote_executor' )
|
1
|
+
$:.unshift File.join( File.dirname( __FILE__ ), 'remote_executor' )
|
8
2
|
|
9
3
|
begin
|
10
|
-
%w[version config system_config system
|
4
|
+
%w[version app options_parser cli config system_config system cli].each { |lib| require lib }
|
11
5
|
rescue LoadError => e
|
12
6
|
fail "Some lib dependencies can not be loaded: #{e.message}"
|
13
7
|
end
|
data/lib/remote_executor/cli.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
|
5
|
+
module RemoteExecutor
|
6
6
|
class Cli
|
7
7
|
|
8
8
|
DEFAULT_SSH_OPTIONS = { :config=>true }
|
@@ -11,14 +11,9 @@ module RemoteExecutor
|
|
11
11
|
|
12
12
|
system = System.new( SystemConfig.instance.find_system( name ) )
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
system.hosts.each do |host|
|
14
|
+
system.hosts.each do |host|
|
17
15
|
|
18
|
-
|
19
|
-
end
|
20
|
-
else
|
21
|
-
raise BadEnvironment.new( "Bad environment: '#{system.environment}' for target: '#{system.name}'..." )
|
16
|
+
Net::SSH.start( host, system.user, ssh_options ) { |ssh| ssh.exec( "#{command}" ) }
|
22
17
|
end
|
23
18
|
end
|
24
19
|
end
|
@@ -1,34 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'choice'
|
3
|
+
require 'yaml'
|
4
|
+
require 'app'
|
5
|
+
|
6
|
+
|
1
7
|
module RemoteExecutor
|
2
8
|
|
3
9
|
class YAMLFileNotFound < Exception
|
4
10
|
end
|
11
|
+
|
12
|
+
class ConfigurationNotLoaded < Exception
|
13
|
+
end
|
14
|
+
|
15
|
+
class ConfigurationError < Exception
|
16
|
+
end
|
5
17
|
|
6
18
|
class Config
|
7
|
-
|
8
|
-
|
9
|
-
# Get the default configuration over Choice, environment and user default settings
|
10
|
-
def self.get_config_file( config_key )
|
19
|
+
|
20
|
+
def load_config( config_file )
|
11
21
|
|
12
|
-
|
13
|
-
|
14
|
-
|
22
|
+
@config = YAML.load_file( config_file )
|
23
|
+
rescue Exception => e
|
24
|
+
raise YAMLFileNotFound.new( e.message )
|
25
|
+
end
|
15
26
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
27
|
+
public
|
28
|
+
def initialize
|
19
29
|
|
20
|
-
|
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]
|
21
36
|
|
22
|
-
|
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
|
23
50
|
end
|
24
|
-
|
25
|
-
raise YAMLFileNotFound.new( "Configuration not found" )
|
26
51
|
end
|
27
|
-
|
28
|
-
def initialize()
|
29
|
-
@config = YAML.load_file( Config.get_config_file( CLIApplication::NAME ) )
|
30
|
-
rescue Exception => e
|
31
|
-
raise YAMLFileNotFound.new( e.message )
|
32
|
-
end
|
33
52
|
end
|
34
53
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'choice'
|
3
|
+
|
4
|
+
|
1
5
|
module RemoteExecutor
|
2
6
|
Choice.options do
|
3
7
|
header ''
|
@@ -9,13 +13,6 @@ module RemoteExecutor
|
|
9
13
|
desc 'The YAML config file'
|
10
14
|
end
|
11
15
|
|
12
|
-
option :environment, :required=>true do
|
13
|
-
short '-e'
|
14
|
-
long '--environment=value'
|
15
|
-
desc 'The Environment name'
|
16
|
-
valid %w[development preproduction production]
|
17
|
-
end
|
18
|
-
|
19
16
|
option :system, :required=>true do
|
20
17
|
short '-s'
|
21
18
|
long '--system=value'
|
@@ -1,20 +1,15 @@
|
|
1
|
-
module RemoteExecutor
|
2
|
-
|
3
|
-
class System < Struct.new( :name, :environment, :user, :hosts )
|
1
|
+
module RemoteExecutor
|
2
|
+
class System < Struct.new( :name, :user, :hosts )
|
4
3
|
|
5
|
-
public
|
6
4
|
def initialize( params )
|
7
5
|
|
8
6
|
unless params && params.class == Hash
|
9
7
|
fail "Bad parameters"
|
10
8
|
end
|
11
9
|
|
12
|
-
if( params[:name]
|
13
|
-
params[:environment] &&
|
14
|
-
params[:user] &&
|
15
|
-
params[:hosts] )
|
10
|
+
if( params[:name] && params[:user] && params[:hosts] )
|
16
11
|
|
17
|
-
super( params[:name], params[:
|
12
|
+
super( params[:name], params[:user], params[:hosts] )
|
18
13
|
self
|
19
14
|
end
|
20
15
|
end
|
@@ -1,16 +1,20 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'config'
|
3
|
+
|
4
|
+
|
1
5
|
module RemoteExecutor
|
2
6
|
|
3
|
-
class ConfigurationError < Exception
|
4
|
-
end
|
5
|
-
|
6
7
|
class SystemConfig < Config
|
7
8
|
include Singleton
|
8
9
|
|
9
10
|
def find_system( system_name )
|
10
11
|
|
11
|
-
@config.each
|
12
|
+
@config.each do |system|
|
13
|
+
|
14
|
+
return system if( system[:name] == system_name )
|
15
|
+
end
|
12
16
|
|
13
|
-
raise ConfigurationError.new( "System: '#{system_name}' not found
|
17
|
+
raise ConfigurationError.new( "System: '#{system_name}' not found" )
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module RemoteExecutor
|
2
2
|
module Version
|
3
3
|
|
4
|
-
MAJOR
|
5
|
-
MINOR
|
6
|
-
PATCH
|
7
|
-
|
8
|
-
STRING =
|
4
|
+
MAJOR = 0
|
5
|
+
MINOR = 6
|
6
|
+
PATCH = 0
|
7
|
+
|
8
|
+
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
9
9
|
end
|
10
10
|
|
11
|
-
NAME
|
12
|
-
VERSION
|
11
|
+
NAME = 'remote_executor'
|
12
|
+
VERSION = Version::STRING
|
13
|
+
COMPLETE_NAME = "#{NAME}-#{VERSION}"
|
13
14
|
end
|
data/test/unit/tc_cli.rb
ADDED
@@ -0,0 +1,18 @@
|
|
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
|
@@ -0,0 +1,44 @@
|
|
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
|
@@ -0,0 +1,35 @@
|
|
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
|
@@ -0,0 +1,35 @@
|
|
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
ADDED
@@ -0,0 +1,24 @@
|
|
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 )
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remote_executor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.6.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Javier Juarez
|
@@ -26,10 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 27
|
30
30
|
segments:
|
31
31
|
- 0
|
32
|
-
|
32
|
+
- 1
|
33
|
+
- 0
|
34
|
+
version: 0.1.0
|
33
35
|
type: :runtime
|
34
36
|
version_requirements: *id001
|
35
37
|
- !ruby/object:Gem::Dependency
|
@@ -40,14 +42,16 @@ dependencies:
|
|
40
42
|
requirements:
|
41
43
|
- - ">="
|
42
44
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
45
|
+
hash: 15
|
44
46
|
segments:
|
47
|
+
- 2
|
48
|
+
- 0
|
45
49
|
- 0
|
46
|
-
version:
|
50
|
+
version: 2.0.0
|
47
51
|
type: :runtime
|
48
52
|
version_requirements: *id002
|
49
53
|
description: A little remote command launcher over SSH connections
|
50
|
-
email: javier.
|
54
|
+
email: javier.juarez_AT_gmail_DOT_com
|
51
55
|
executables:
|
52
56
|
- remote_executor
|
53
57
|
extensions: []
|
@@ -57,6 +61,7 @@ extra_rdoc_files:
|
|
57
61
|
files:
|
58
62
|
- bin/remote_executor
|
59
63
|
- lib/remote_executor.rb
|
64
|
+
- lib/remote_executor/app.rb
|
60
65
|
- lib/remote_executor/cli.rb
|
61
66
|
- lib/remote_executor/config.rb
|
62
67
|
- lib/remote_executor/options_parser.rb
|
@@ -64,6 +69,11 @@ files:
|
|
64
69
|
- lib/remote_executor/system_config.rb
|
65
70
|
- lib/remote_executor/version.rb
|
66
71
|
- README.rdoc
|
72
|
+
- test/unit/tc_cli.rb
|
73
|
+
- test/unit/tc_config.rb
|
74
|
+
- test/unit/tc_system.rb
|
75
|
+
- test/unit/tc_system_config.rb
|
76
|
+
- test/unit/ts_all.rb
|
67
77
|
has_rdoc: true
|
68
78
|
homepage: http://github.com/jjuarez/remote_executor
|
69
79
|
licenses:
|
@@ -98,5 +108,9 @@ rubygems_version: 1.3.7
|
|
98
108
|
signing_key:
|
99
109
|
specification_version: 3
|
100
110
|
summary: A very simple gem that helps to launch remote commands over SSH connections
|
101
|
-
test_files:
|
102
|
-
|
111
|
+
test_files:
|
112
|
+
- test/unit/tc_cli.rb
|
113
|
+
- test/unit/tc_config.rb
|
114
|
+
- test/unit/tc_system.rb
|
115
|
+
- test/unit/tc_system_config.rb
|
116
|
+
- test/unit/ts_all.rb
|