1
2
3
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#!/usr/bin/env ruby
# (C) 2015 by Paul Buetow
require "getoptlong"
require "json"
require "net/http"
require "net/ssh"
require "pp"
require "thread"
class Rubyfy
def initialize(opts)
@args = Hash.new
@log_mutex = Mutex.new
opts.each do |opt, arg|
@args[opt] = arg
end
log(:DEBUG, @args) if @args["--debug"]
end
def run
servers, jobs = [], []
STDIN.read.split("\n").each { |s| servers << s }
work_q = Queue.new
servers.each do |server|
job = {
:SERVER => server,
:COMMAND => @args["--command"],
:ROOT => @args["--root"],
:STATUS => :NONE,
}
jobs << job
work_q.push(job)
end
parallel = @args["--parallel"].to_i
threads = (1..parallel).map do
Thread.new do
begin
while job = work_q.pop(true)
run_job(job)
end
rescue ThreadError => e
rescue => e
log(:ERROR, "#{job[:SERVER]}::#{e.message}")
log(:ERROR, "#{job[:SERVER]}::#{e.inspect}")
end
end
end
threads.map(&:join)
log(:INFO, "-::Done processing all servers")
jobs.each do |job|
if job[:STATUS] != :OK
log(:WARN,"#{job[:SERVER]}::No job result")
end
end
end
private
def log(severity, message)
return if severity == :VERBOSE and not @args["--verbose"]
@log_mutex.synchronize do
puts "#{severity}::#{message}"
end
end
def run_command(server, command="uptime", root=false, user=ENV["USER"])
log(:VERBOSE,"#{server}::Connecting")
sudo = root ? "sudo " : ""
Net::SSH.start(server, user) do |session|
log(:VERBOSE, "#{server}::Executing #{sudo}#{command}")
session.exec!("#{sudo}#{command}") do |channel, stream, data|
log(:OUT, "#{server}::#{data}") unless @args["--silent"]
end
end
end
def run_job(job)
server = job[:SERVER]
command = job[:COMMAND]
root = job[:ROOT]
log(:VERBOSE, "#{server}::Running job #{job}")
if File.exists?("#{server}.ignore")
log(:INFO, "#{server}::Ignoring this server")
else
run_command server, command, root
end
job[:STATUS] = :OK
end
def http_get(uri_str, content_type="application/json")
uri = URI.parse(uri_str)
req = Net::HTTP::Get.new(uri.path)
req.[]=("Accept", content_type)
http = Net::HTTP.new(uri.host, uri.port)
http.request(req).body
end
end
begin
opts = GetoptLong.new(
[ "--command", "-c", GetoptLong::REQUIRED_ARGUMENT ],
[ "--debug", "-d", GetoptLong::OPTIONAL_ARGUMENT ],
[ "--parallel", "-p", GetoptLong::OPTIONAL_ARGUMENT ],
[ "--root", "-r", GetoptLong::OPTIONAL_ARGUMENT ],
[ "--silent", "-s", GetoptLong::OPTIONAL_ARGUMENT ],
[ "--verbose", "-v", GetoptLong::OPTIONAL_ARGUMENT ],
)
rubyfy = Rubyfy.new(opts)
rubyfy.run
end
|