remote_executor 0.6.0 → 0.9.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 +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 )
|