elsewhere 0.0.1
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +20 -0
- data/Rakefile +1 -0
- data/elsewhere.gemspec +28 -0
- data/lib/elsewhere.rb +6 -0
- data/lib/elsewhere/remote_run.rb +111 -0
- data/lib/elsewhere/version.rb +3 -0
- metadata +86 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#Elsewhere
|
2
|
+
|
3
|
+
###Simple wrapper for Ruby Net::SSH for running commands remotely
|
4
|
+
|
5
|
+
#Why?
|
6
|
+
This was abstracted from a larger project. There are many solutions out there that already do or require this paradigm like Capistrano or RemoteRun for Rake. But this code exists and
|
7
|
+
Is used in several active projects so I thought it might be useful to others.
|
8
|
+
|
9
|
+
#Usage:
|
10
|
+
```Ruby
|
11
|
+
r = Elsewhere::RemoteRun.new("www.example.com","app_user")
|
12
|
+
r.commands << "source /etc/profile"
|
13
|
+
r.commands << "cd ~/current"
|
14
|
+
r.commands << "rake do:something:useful"
|
15
|
+
|
16
|
+
r.execute
|
17
|
+
```
|
18
|
+
|
19
|
+
#Notes:
|
20
|
+
I'm still in the process of adding some tests and porting this over to a gem but the core library is used in a working project
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/elsewhere.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "elsewhere/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "elsewhere"
|
7
|
+
s.version = Elsewhere::VERSION
|
8
|
+
s.authors = ["Bill Chapman"]
|
9
|
+
s.email = ["bchapman@academicmanagement.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{ Simple wrapper for Net SSH to run a list of commands remotely }
|
12
|
+
s.description = %q{ Yet another way to run stuff remotely }
|
13
|
+
|
14
|
+
s.rubyforge_project = "elsewhere"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
s.add_runtime_dependency 'minitest'
|
25
|
+
s.add_runtime_dependency 'net-ssh'
|
26
|
+
s.add_runtime_dependency 'net-ssh-gateway'
|
27
|
+
|
28
|
+
end
|
data/lib/elsewhere.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module Elsewhere
|
2
|
+
|
3
|
+
# Execute commands on a remote server
|
4
|
+
# I know capistrano already does this
|
5
|
+
# This was abstracted from a more specific solution that we already had in place and I thought it was worth sharing
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# r = RemoteRun.new("hostname","username")
|
10
|
+
# r.commands << "source /etc/profile"
|
11
|
+
# r.commands << "cd ~/current"
|
12
|
+
# r.commands << "rake extractor:run cas=3 users=12550"
|
13
|
+
#
|
14
|
+
# r.execute
|
15
|
+
#
|
16
|
+
require 'net/ssh'
|
17
|
+
require 'net/ssh/gateway'
|
18
|
+
require 'yaml'
|
19
|
+
class RemoteRun
|
20
|
+
|
21
|
+
#TODO: move to remote_run/exceptions.rb when we gemify this
|
22
|
+
class RemoteRunError < StandardError; end
|
23
|
+
|
24
|
+
attr_accessor :hosts, :gateway_address, :gateway_user, :commands
|
25
|
+
|
26
|
+
def initialize(hosts,user, options={})
|
27
|
+
@hosts = [hosts].flatten #accept a single host or an array of hosts
|
28
|
+
@gateway_address = options[:gateway_address]
|
29
|
+
@gateway_user = options[:gateway_user]
|
30
|
+
@user = user
|
31
|
+
@commands = []
|
32
|
+
end
|
33
|
+
|
34
|
+
#expects the config file to be formatted as yaml as follows
|
35
|
+
#environment:
|
36
|
+
# group:
|
37
|
+
# user: username
|
38
|
+
# host: hostname
|
39
|
+
def self.initialize_from_config(config_file,environment,group,options={})
|
40
|
+
config_file = YAML.load_file(config_file)
|
41
|
+
env_config = config_file[environment][group]
|
42
|
+
options[:gateway_address] ||= env_config["gateway"]["host"] unless env_config["gateway"].nil?
|
43
|
+
options[:gateway_user] ||= env_config["gateway"]["user"] unless env_config["gateway"].nil?
|
44
|
+
new(env_config["host"],env_config["user"],options)
|
45
|
+
end
|
46
|
+
|
47
|
+
#gateway wrapper when a gateway is specified
|
48
|
+
def gateway_wrapper
|
49
|
+
@gateway_host ||= if(@gateway_addr && @gateway_user)
|
50
|
+
Net::SSH::Gateway.new(@gateway_addr, @gateway_user, {:forward_agent => true})
|
51
|
+
else
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def ssh_wrapper(host,command)
|
57
|
+
output = nil
|
58
|
+
Net::SSH.start(host, @user) do |ssh|
|
59
|
+
output = execute_over_ssh(ssh,command)
|
60
|
+
end
|
61
|
+
output
|
62
|
+
end
|
63
|
+
|
64
|
+
# Run all of the items in the commands hash
|
65
|
+
# The joined_by paramenter dictates how to join the commands before execution
|
66
|
+
# Returns: A hash of the responses for each specified host
|
67
|
+
def execute(joined_by = " && ")
|
68
|
+
run_me = @commands.join(joined_by)
|
69
|
+
output = {}
|
70
|
+
|
71
|
+
if @gateway_host
|
72
|
+
gateway_wrapper.ssh(host, @user, {:forward_agent => true}) do |gateway|
|
73
|
+
@hosts.uniq.each do |h|
|
74
|
+
gateway.ssh(host, options[:gateway_user], {:forward_agent => true}) do |ssh|
|
75
|
+
output[h] = execute_over_ssh(ssh, run_me)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
@hosts.uniq.each{ |h| output[h] = ssh_wrapper(h,run_me) }
|
81
|
+
end
|
82
|
+
|
83
|
+
return output
|
84
|
+
end
|
85
|
+
|
86
|
+
#execute the given commend for the Net::SSH instance
|
87
|
+
#return the data or raise an error depending on which stream is returned
|
88
|
+
def execute_over_ssh(ssh,command)
|
89
|
+
stdout = ""
|
90
|
+
ssh.exec!(command) do |channel,stream,data|
|
91
|
+
case stream
|
92
|
+
when :stderr
|
93
|
+
raise RemoteRunError, data
|
94
|
+
else
|
95
|
+
stdout = data
|
96
|
+
end
|
97
|
+
end
|
98
|
+
return stdout
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if __FILE__ == $0
|
106
|
+
host = ""
|
107
|
+
user = ""
|
108
|
+
r = RemoteRun.new(host,user)
|
109
|
+
r.commands << "ls"
|
110
|
+
puts r.execute
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elsewhere
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bill Chapman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-01 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: minitest
|
16
|
+
requirement: &2169024520 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2169024520
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: net-ssh
|
27
|
+
requirement: &2169024100 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2169024100
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: net-ssh-gateway
|
38
|
+
requirement: &2169023680 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2169023680
|
47
|
+
description: ! ' Yet another way to run stuff remotely '
|
48
|
+
email:
|
49
|
+
- bchapman@academicmanagement.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- Gemfile
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- elsewhere.gemspec
|
59
|
+
- lib/elsewhere.rb
|
60
|
+
- lib/elsewhere/remote_run.rb
|
61
|
+
- lib/elsewhere/version.rb
|
62
|
+
homepage: ''
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project: elsewhere
|
82
|
+
rubygems_version: 1.8.10
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Simple wrapper for Net SSH to run a list of commands remotely
|
86
|
+
test_files: []
|