Skip to content

Commit 8bee64c

Browse files
committed
aks: added ssh-utils; some cosmetic updates to cmd-utils
1 parent 07a2a63 commit 8bee64c

File tree

4 files changed

+169
-31
lines changed

4 files changed

+169
-31
lines changed

Gemspec

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
Gem::Specification.new do |s|
22
s.name = 'cmd-utils'
3-
s.version = '1.0.12'
4-
s.date = '2013-09-11'
3+
s.version = '1.1.0'
4+
s.date = '2014-02-27'
55
s.summary = "Utilities for ruby command line scripts"
66
s.description = "Some handy utilities for writing command line scripts in ruby."
77
s.author = "Alan K. Stebbens"
88
s.email = '[email protected]'
9-
s.files = ["lib/cmd-utils.rb", "lib/lookup.rb"]
9+
s.files = ["lib/cmd-utils.rb", "lib/lookup.rb", "lib/ssh-utils.rb"]
1010
s.test_files = ['tests/test-cmd-utils.rb', 'tests/test-lookup.rb']
11-
s.homepage = 'http://gitlab.com/as/cmd-utils'
11+
s.homepage = 'http://bitbucket.org/aks_/cmd-utils'
1212
s.license = 'GPL-2'
1313
end

README.md

+89-3
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ Installation:
1010
Usage:
1111

1212
require 'cmd-utils'
13+
require 'ssh-utils'
1314
require 'lookup'
1415

1516
This gem provides:
1617

1718
* routines for output on `$stderr`, controlled by several global variables
1819
* error-reporting-and-exit
1920
* system call handling, with verbose or debug output, error and "ok" message handling
21+
* remote system command invocation (based on ssh)
2022
* ambiguous, case-insensitive string lookups in arrays or hashs, with error handling
2123

2224
talk, dtalk, qtalk, vtalk, nrtalk, nvtalk
@@ -92,7 +94,8 @@ Error output:
9294
The `error` routine take an optional numeric first argument which is used to
9395
set the exit code. If not given, the exit code is 1.
9496

95-
`cmd_run` ========
97+
`cmd_run`
98+
--------
9699

97100
cmd_run cmd
98101
cmd_run { cmd }
@@ -111,8 +114,8 @@ and the method returns without invoking `cmd`.
111114
When `$norun` is false, and if `$verbose` is set, the `cmd` is displayed with
112115
a prefix of `">> "` before executing it.
113116

114-
If result of invoking `system(cmd)` is an error (non-zero exit code), then an
115-
error is printed on `$stderr`, possibly preceded by the command itself if it
117+
If the result of invoking `system(cmd)` is an error (non-zero exit code), then
118+
an error is printed on `$stderr`, possibly preceded by the command itself if it
116119
was not already printed.
117120

118121
Note that when using the block forms of run (e.g., `run { cmd }`), the result
@@ -131,6 +134,89 @@ command evaluation with the `$verbose` treatment.
131134
safe_run { cmd }
132135
safe_run {[cmd, errmsg, okmsg]}
133136

137+
ssh-utils
138+
=========
139+
140+
A module to define some routines for running commands across many systems using
141+
ssh. Environment variables can be specified (PATH is used by default).
142+
143+
Usage:
144+
145+
require 'ssh-utils'
146+
147+
on serverlist, :debug = true do |server|
148+
as user do
149+
with PATH
150+
remote_run :whoami
151+
end
152+
end
153+
end
154+
155+
Method Descriptions
156+
-------------------
157+
158+
on SERVERLIST, OPTIONSHASH |server|
159+
BLOCK-TO-EXECUTE-FOR-EACH-SERVER
160+
end
161+
162+
The `on` method specifies a list of servers, with an optional hash of
163+
options. The supported options are: `:debug`, `:verbose`, `:with`,
164+
`:without`, and `:as`
165+
166+
:with => ENVARS
167+
168+
`ENVARS` is an array of environment symbol names (or strings) that will
169+
be included on the `ssh` command that is used to run remote commands.
170+
171+
:without => ENVARS
172+
173+
`ENVARS` is an array of environment symbol names (or strings) that will *not*
174+
be included on the `ssh` command that is used to run remote commands. This
175+
option is useful when overriding the default inclusion of `PATH`. For example:
176+
177+
on backupserver, :without => :PATH
178+
remote_run "/bin/tar", "-cf", source_path, dest_path
179+
end
180+
181+
:as => USER
182+
183+
Specifies the user to be used for the subsequent invocations. By default,
184+
the current user is used implicitly.
185+
186+
:debug => [true | false]
187+
188+
Sets the `:debug` flag for use within the associated block. The `$debug` flag
189+
is globally available, but the `:debug` option is a block-local specification.
190+
191+
:verbose => [true | false]
192+
193+
Sets the `:verbose` flag for use within the associated block. The `$verbose` flag
194+
is globally available, but the `:verbose` option is a block-local specification.
195+
196+
197+
as USERLIST, OPTIONSHASH
198+
BLOCK-TO-EXECUTE-FOR-EACH-USER
199+
end
200+
201+
The `as` method is optional, and if absent causes the current user to
202+
be used by default (unless overridden by the `~/.ssh/config` file).
203+
204+
The `as` method allows the embedded block to be repeated for each given user.
205+
If there only one user, it can be specified on the `on` method with an `:as`
206+
option. For example, the following two sections are equivalent:
207+
208+
on someserver
209+
as root
210+
remote_run :whoami
211+
end
212+
end
213+
214+
on someserver, :as => 'root'
215+
remote_run :whoami
216+
end
217+
218+
219+
134220
lookup
135221
======
136222

lib/cmd-utils.rb

+17-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55
#
66
# require 'cmd-utils'
7-
#
7+
#
88
# Utilities for option-controlled output, and running commands.
99
#
1010
# The output and run methods rely on some external variables:
@@ -14,11 +14,12 @@
1414
# $quiet -- enables qtalk(f) output, and disables talk(f) output
1515
# $debug -- enables dtalk(f) output
1616
#
17-
# These routines provide conditional output. The arguments can be given as part of the
18-
# the function calls, or, can be provided as the return value of a block. The advantage
19-
# of using a block is that the block is not evaluated unless the conditions requiring
20-
# output are met. So, if the expression to compute a value that _might_ be printed is
21-
# expensive, do the computation inside a block.
17+
# These routines provide conditional output. The arguments can be given as
18+
# part of the the function calls, or, can be provided as the return value of a
19+
# block. The advantage of using a block is that the block is not evaluated
20+
# unless the conditions requiring output are met. So, if the expression to
21+
# compute a value that _might_ be printed is expensive, do the computation
22+
# inside a block.
2223
#
2324
##
2425
# talk - Print msg on STDERR unless `$quiet` is set
@@ -62,7 +63,7 @@ def _fmtargs args, flag
6263
end
6364

6465
##
65-
# dtalk - "debug talk"
66+
# dtalk - "debug talk"
6667
# Print msg on STDERR only if `$debug` is set
6768
#
6869
# :call-seq:
@@ -77,9 +78,9 @@ def dtalk *args
7778
end
7879
end
7980

80-
def dtalkf *args
81+
def dtalkf *args
8182
if $debug && (args.size> 0 || block_given?)
82-
$stderr.printf(*_fmtargs(args, block_given?) { yield })
83+
$stderr.printf(*_fmtargs(args, block_given?) { yield })
8384
end
8485
end
8586

@@ -99,7 +100,7 @@ def qtalk *args
99100
end
100101
end
101102

102-
def qtalkf *args
103+
def qtalkf *args
103104
if $quiet && (args.size > 0 || block_given?)
104105
$stderr.printf(*_fmtargs(args, block_given?) { yield } )
105106
end
@@ -222,6 +223,7 @@ def errorf *args
222223
# run { [cmd, errmsg] }
223224
# run { [cmd, errmsg, okmg] }
224225
# run cmd, errmsg, okmsg
226+
#
225227
# safe_run cmd
226228
# safe_run cmd, errmsg
227229
# safe_run cmd, errmsg, okmsg
@@ -238,18 +240,18 @@ def errorf *args
238240
#
239241
# If there is an error, show the command (preceded by `>> `) if `$verbose` is
240242
# not set, then show the error code, followed by the given `errmsg` or the
241-
# default error message.
243+
# default error message.
242244
#
243245
# The `cmd` can be given either as an argument, or as the returned value from a
244-
# block. Important: the block should return a string value to be passed to
246+
# block. Important: the block should return a string value to be passed to
245247
# the system call.
246248

247249
def cmd_run *args
248250
args = _msgargs(args, block_given?) { yield }
249251
if $norun
250252
nrtalk(args.first)
251253
elsif args.size > 0
252-
safe_run(*args)
254+
safe_run *args
253255
end
254256
end
255257

@@ -259,8 +261,8 @@ def safe_run *args
259261
args = _msgargs(args, block_given?) { yield }
260262
cmd, errmsg, okmsg = args
261263
vtalkf ">> %s\n", cmd
262-
if cmd
263-
if system(cmd) # invoke the command
264+
if cmd
265+
if system cmd # invoke the command
264266
$stderr.puts okmsg if okmsg
265267
return true
266268
else # an error occured

lib/ssh-utils.rb

+59-9
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
#
1212
# on serverlist, :debug = true do |server|
1313
# as user do
14-
# remote_run :whoami
14+
# with PATH
15+
# remote_run :whoami
16+
# end
1517
# end
1618
# end
1719

@@ -25,53 +27,101 @@ module SSH_Utils
2527

2628
@opts = {}
2729
@opts.default = nil
30+
@@default_envars = %w(PATH) # default envarlist
2831

2932
def merge_opts opts = {}
3033
@opts ||= {}
3134
@opts.merge!(opts) unless opts.empty?
3235
end
3336

37+
# merge_env opts
38+
#
39+
# merge envars. :with => ENVARS_TO_ADD, :without => ENVARS_TO_EXCLUDE
40+
# :with => %w(PATH RUBYLIB)
41+
# :without => %w(PATH)
42+
# Removes the :with and :without keys from the opts hash
43+
44+
def merge_env opts
45+
@envars = @@default_envars
46+
if opts.key?(:with)
47+
@envars.concat(opts[:with]).uniq!
48+
opts.delete(:with)
49+
end
50+
if opts.key?(:without)
51+
@envars -= opts[:without]
52+
opts.delete(:without)
53+
end
54+
end
55+
56+
# on SERVERLIST, :with => %w(PATH RUBYLIB), :debug => [true|false], :norun => [true|false]
3457

3558
def on servers, opts = {}
59+
merge_env (opts = opts.dup)
3660
merge_opts opts
3761
(@servers = servers).each do |server|
3862
@server = server
39-
talk("--> Running block for server #{server}..") if @opts[:debug]
63+
talk("--> Running block for server #{server}..") if @opts[:debug] || $debug
4064
yield server
4165
end
4266
end
4367

68+
# as USER, :with => ENVARLIST, :debug => [true|false], :norun => [true|false]
4469

4570
def as user, opts = {}
4671
@user = user
72+
merge_env (opts = opts.dup)
4773
merge_opts opts
4874
yield if block_given?
4975
end
5076

77+
# with ENVARLIST, :VAR1 => value, :debug => ...
5178

52-
def _ssh_command cmd
79+
def with env, opts = {}
80+
merge_env (opts = opts.dup)
81+
merge_opts opts
82+
end
83+
84+
def ssh_command cmd
5385
ssh = "ssh -A"
5486
ssh += " -u #{@user}" unless @user.nil?
5587
ssh += " #{@server}"
88+
@envars.each do |env|
89+
# explicit values in the options list override the environment values
90+
val = @opts.key?(env) ? @opts[env] : ENV[env]
91+
if !(val.nil? || val.empty?)
92+
ssh += sprintf(" %s='%s'", env, val.gsub("'", "\'"))
93+
end
94+
end
5695
ssh += " " + cmd.to_s
5796
ssh
5897
end
5998

99+
def _show_cmd cmd
100+
if @opts[:norun] || $norun
101+
talkf "(norun) %s\n", cmd
102+
elsif @opts[:debug] || $debug || @opts[:verbose] || $verbose
103+
talkf "--> %s\n", cmd
104+
end
105+
end
106+
107+
# remote_run COMMAND
108+
# run the remote command
60109

61110
def remote_run cmd
62-
ssh = _ssh_command(cmd)
63-
talk("--> " + ssh) if @opts[:debug]
64-
system ssh
111+
ssh = ssh_command(cmd)
112+
_show_cmd ssh
113+
system(ssh) unless @opts[:norun] || $norun
65114
end
66115
alias :run_remotely :remote_run
67116

68117

69118
def remote_run_with_output cmd, opts = {}
119+
merge_env (opts = opts.dup)
70120
merge_opts opts
71-
ssh = _ssh_command cmd
72-
talk("--> " + ssh) if @opts[:debug]
121+
ssh = ssh_command cmd
122+
_show_cmd ssh
73123
out = nil
74-
IO.popen(ssh) {|f| out = f.readlines }
124+
IO.popen(ssh) {|f| out = f.read }
75125
out
76126
end
77127
alias :capture :remote_run_with_output

0 commit comments

Comments
 (0)