scutil 0.2.3 → 0.2.4

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/CHANGELOG CHANGED
@@ -1,6 +1,13 @@
1
1
 
2
2
  ==Changelog
3
3
 
4
+ ===0.2.4 | 2011-10-02
5
+
6
+ * More verbose logging.
7
+ * Better error handling.
8
+ * Minor bug fixes.
9
+ * Documentation corrections.
10
+
4
11
  ===0.2.3 | 2011-09-27
5
12
 
6
13
  * Fixed bug in Scutil.clear!
data/README CHANGED
@@ -28,9 +28,8 @@ PTYs is beyond the scope of this documentation.
28
28
  The "_automatic_" part of PTY requests comes from a regex in
29
29
  Scutil.exec_command. Basically, if _sudo_ is at the start of the
30
30
  command to be executed, scutil will request a PTY. This regex is
31
- configurable through +:scutil_pty_regex+. In a near future release it
32
- will be. You can force a PTY request by specifying
33
- +:scutil_force_pty+ in the various _options_ arguments.
31
+ configurable through +:scutil_pty_regex+. You can force a PTY request
32
+ by specifying +:scutil_force_pty+ in the various _options_ arguments.
34
33
 
35
34
  All of this syntactic sugar can be used as a simple class method with
36
35
  Scutil.exec_command, as an instantiable class with Scutil::Exec, or as
data/THANKS CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  ===Thanks
3
3
 
4
- * Kevin McAllister <kevin@mcallister.com> for the name and much
4
+ * Kevin McAllister <kevin@mcallister.ws> for the name and much
5
5
  feedback and discussion.
6
6
 
7
7
  * Jamis Buck <jamis@37signals.com> for writing Net::SSH, on which
data/lib/scutil.rb CHANGED
@@ -30,14 +30,14 @@ require 'scutil/connection_cache'
30
30
  require 'scutil/system_connection'
31
31
 
32
32
  module Scutil
33
- SCUTIL_VERSION = '0.2.3'
33
+ SCUTIL_VERSION = '0.2.4'
34
34
  # By default, buffer 10M of data before writing.
35
35
  DEFAULT_OUTPUT_BUFFER_SIZE = 0xA00000
36
36
  # Checks for a command starting with _sudo_ by default.
37
37
  DEFAULT_PTY_REGEX = /^\s*sudo/
38
38
  @connection_cache = ConnectionCache.new
39
39
  @output_buffer_size = DEFAULT_OUTPUT_BUFFER_SIZE
40
-
40
+
41
41
  class << self
42
42
  # All successfully established connections end up here for reuse
43
43
  # later.
@@ -45,7 +45,7 @@ module Scutil
45
45
  # Set to 10M by default, this can be adjusted to tell scutil when
46
46
  # to write command output to _output_.
47
47
  attr_accessor :output_buffer_size
48
-
48
+
49
49
  # Should we request a PTY? Uses custom regex if defined in
50
50
  # +:scutil_pty_regex+.
51
51
  #
@@ -86,7 +86,7 @@ module Scutil
86
86
  # open file handle.* Finally, if _output_ is omitted, or an empty
87
87
  # string, all command output will be directed to _$stdout_.
88
88
  #
89
- # <em>**NB:* This isn't actually true. The only check made is to
89
+ # <em>*NB:* This isn't actually true. The only check made is to
90
90
  # see if _output_ responds to +:write+. The idea being that not
91
91
  # only will a file handle have a +write+ method, but also
92
92
  # something like +StringIO+. Using +StringIO+ here makes it easy
@@ -94,17 +94,15 @@ module Scutil
94
94
  # better way to do this are definitely welcome.</em>
95
95
  #
96
96
  # Scutil will automatically request a PTY if _sudo_ is at the
97
- # start of _cmd_. Right now the regex that drives this isn't
98
- # configurable. In a near future release it will be. You can
99
- # force a PTY request by specifying +:scutil_force_pty+ in
100
- # _options_.
97
+ # start of _cmd_. This is driven by a regex which is customizable
98
+ # via the option +:scutil_pty_regex+. You can also force a PTY
99
+ # request by specifying +:scutil_force_pty+ in _options_.
101
100
  #
102
101
  # Scutil.exec_command takes the following options:
103
102
  #
104
103
  # * :scutil_verbose => Extra output.
105
104
  # * :scutil_force_pty => Force a PTY request (or not) for every channel.
106
- # * :scutil_pty_regex => Specific a custom regex here for use when
107
- # scutil decides whether or not to request a PTY.
105
+ # * :scutil_pty_regex => Specific a custom regex here for use when scutil decides whether or not to request a PTY.
108
106
  #
109
107
  # In addition, any other options passed Scutil.exec_command will
110
108
  # be passed on to Net::SSH, _except_ those prefixed with
@@ -126,17 +124,19 @@ module Scutil
126
124
  begin
127
125
  if (Scutil.connection_cache.exists?(hostname))
128
126
  sys_conn = Scutil.connection_cache.fetch(hostname)
129
- $stderr.print "[#{hostname}] Using existing connection\n" if options[:scutil_verbose]
127
+ print "[#{hostname}] Using existing connection\n" if options[:scutil_verbose]
130
128
  conn = sys_conn.get_connection(hostname, username, pty_needed, options)
131
129
  else
132
130
  sys_conn = SystemConnection.new(hostname)
133
131
  # Call get_connection first. Don't add to cache unless established.
134
132
  conn = sys_conn.get_connection(hostname, username, pty_needed, options)
135
- $stderr.print "[#{hostname}] Adding new connection to cache\n" if options[:scutil_verbose]
133
+ print "[#{hostname}] Adding new connection to cache\n" if options[:scutil_verbose]
136
134
  Scutil.connection_cache << sys_conn
137
135
  end
138
136
  rescue Net::SSH::AuthenticationFailed => err
139
137
  raise Scutil::Error.new("Error: Authenication failed for user: #{username}", hostname)
138
+ rescue SocketError => err
139
+ raise Scutil::Error.new("Error: " + err.message, hostname)
140
140
  end
141
141
 
142
142
  fh = $stdout
@@ -156,9 +156,9 @@ module Scutil
156
156
  edata = ""
157
157
  exit_status = 0
158
158
  chan = conn.open_channel do |channel|
159
- $stderr.print "[#{conn.host}:#{channel.local_id}] Setting up callbacks...\n" if options[:scutil_verbose]
159
+ print "[#{conn.host}:#{channel.local_id}] Setting up callbacks...\n" if options[:scutil_verbose]
160
160
  if (pty_needed)
161
- $stderr.print "[#{conn.host}:#{channel.local_id}] Requesting PTY...\n" if options[:scutil_verbose]
161
+ print "[#{conn.host}:#{channel.local_id}] Requesting PTY...\n" if options[:scutil_verbose]
162
162
  # OPOST is necessary, CS8 makes sense. Revisit after broader testing.
163
163
  channel.request_pty(:modes => { Net::SSH::Connection::Term::CS8 => 1, Net::SSH::Connection::Term::OPOST => 0 } ) do |ch, success|
164
164
  raise Scutil::Error.new("Failed to get a PTY", hostname) if !success
@@ -166,9 +166,9 @@ module Scutil
166
166
  end
167
167
 
168
168
  channel.on_data do |ch, data|
169
- # $stderr.print "on_data: #{data.size}\n" if options[:scutil_verbose]
169
+ # print "on_data: #{data.size}\n" if options[:scutil_verbose]
170
170
  odata += data
171
-
171
+
172
172
  # Only buffer some of the output before writing to disk (10M by default).
173
173
  if (odata.size >= Scutil.output_buffer_size)
174
174
  fh.write odata
@@ -177,26 +177,23 @@ module Scutil
177
177
  end
178
178
 
179
179
  channel.on_extended_data do |ch, type, data|
180
- # $stderr.print "on_extended_data: #{data.size}\n" if options[:scutil_verbose]
180
+ # print "on_extended_data: #{data.size}\n" if options[:scutil_verbose]
181
181
  edata += data
182
182
  end
183
183
 
184
184
  channel.on_close do |ch|
185
- $stderr.print "[#{conn.host}:#{channel.local_id}] on_close\n" if options[:scutil_verbose]
185
+ print "[#{conn.host}:#{channel.local_id}] on_close\n" if options[:scutil_verbose]
186
186
  end
187
187
 
188
188
  channel.on_open_failed do |ch, code, desc|
189
189
  raise Scutil::Error.new("Failed to open channel: #{desc}", hostname, code) if !success
190
190
  end
191
-
191
+
192
192
  channel.on_request("exit-status") do |ch, data|
193
193
  exit_status = data.read_long
194
+ print "[#{conn.host}:#{channel.local_id}] on_request(\"exit-status\"): #{exit_status}\n" if options[:scutil_verbose]
194
195
  end
195
196
 
196
- # channel.on_open_failed do |ch, code, desc|
197
- #
198
- # end
199
-
200
197
  channel.exec(cmd)
201
198
  # channel.wait
202
199
  end
@@ -29,7 +29,11 @@ module Scutil
29
29
  end
30
30
  false
31
31
  end
32
-
32
+
33
+ def remove_all
34
+ @cache = []
35
+ end
36
+
33
37
  # Remove all instances of _hostname_.
34
38
  def remove(hostname)
35
39
  @cache.delete_if { |c| c.hostname == hostname }
data/lib/scutil/exec.rb CHANGED
@@ -33,5 +33,6 @@ module Scutil
33
33
  @options.merge!(options)
34
34
  Scutil.exec_command(@hostname, @username, cmd, output, @options)
35
35
  end
36
+ # TODO: options should be customizable via an instance method.
36
37
  end
37
38
  end
@@ -25,23 +25,23 @@ module Scutil
25
25
  if (pty_needed)
26
26
  if !@pty_connection.nil?
27
27
  # Existing PTY connection
28
- $stderr.print "[#{hostname}] Using existing connection (pty)\n" if @options[:scutil_verbose]
28
+ print "[#{hostname}] Using existing connection (pty)\n" if @options[:scutil_verbose]
29
29
  return @pty_connection
30
30
  end
31
31
 
32
32
  # New PTY connection
33
- $stderr.print "[#{hostname}] Opening new channel (pty) to system...\n" if @options[:scutil_verbose]
33
+ print "[#{hostname}] Opening new channel (pty) to system...\n" if @options[:scutil_verbose]
34
34
  conn = Net::SSH.start(hostname, username, @options)
35
35
  @pty_connection = conn
36
36
  else
37
37
  if !@connection.nil?
38
38
  # Existing non-PTY connection
39
- $stderr.print "[#{hostname}] Using existing connection (non-pty)\n" if @options[:scutil_verbose]
39
+ print "[#{hostname}] Using existing connection (non-pty)\n" if @options[:scutil_verbose]
40
40
  return @connection
41
41
  end
42
42
 
43
43
  # New non-PTY connection
44
- $stderr.print "[#{hostname}] Opening channel (non-pty) to system...\n" if @options[:scutil_verbose]
44
+ print "[#{hostname}] Opening channel (non-pty) to system...\n" if @options[:scutil_verbose]
45
45
  conn = Net::SSH.start(hostname, username, @options)
46
46
  @connection = conn
47
47
  end
@@ -57,7 +57,7 @@ module Scutil
57
57
  end
58
58
 
59
59
  def to_s
60
- "#{self.class}: #{@name}, @connection = #{@connection}, @pty_connection = #{@pty_connection}"
60
+ "#{self.class}: #{@hostname}, @connection = #{@connection}, @pty_connection = #{@pty_connection}"
61
61
  end
62
62
  end
63
63
  end
data/scutil.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'scutil'
3
- s.version = '0.2.3'
4
- s.date = '2011-09-27'
3
+ s.version = '0.2.4'
4
+ s.date = '2011-10-02'
5
5
  s.summary = 'SSH Command UTILity'
6
6
  s.description = <<-EOF
7
7
  Scutil is a library for conveniently executing commands
data/test/test_scutil.rb CHANGED
@@ -1,50 +1,138 @@
1
- #!/usr/bin/ruby -I../lib -w
1
+ #!/usr/bin/ruby -I../lib -I. -w
2
2
 
3
3
  require 'test/unit'
4
4
  require 'scutil'
5
5
  require 'stringio'
6
6
 
7
7
  class TestScutil < Test::Unit::TestCase
8
- def setup
9
- @hostname = ARGV[0]
10
- @port = ARGV[1]
11
- @user = 'mas'
12
- @exec = Scutil::Exec.new(@hostname, @user,
13
- { :port => @port,
14
- # :keys => '~mas/.ssh/id_rsa',
15
- })
16
- @output = nil
17
- @t_output = nil
8
+ TRUE_COMMAND = '/bin/true'
9
+ FALSE_COMMAND = '/bin/false'
10
+ FAKE_COMMAND = '/bin/no_such_command'
11
+
12
+ @hostname = nil
13
+ @port = nil
14
+ @user = nil
15
+
16
+ class << self
17
+ attr_accessor :hostname,:port,:user
18
18
  end
19
19
 
20
20
  def divert_stdout
21
- @t_output = $stdout
21
+ @tmp_output = $stdout
22
22
  $stdout = StringIO.new
23
23
  end
24
24
 
25
25
  def revert_stdout
26
26
  @output = $stdout
27
- $stdout = @t_output
27
+ $stdout = @tmp_output
28
+ end
29
+
30
+ def setup
31
+ @output = nil
32
+ @tmp_output = nil
33
+ @exec = Scutil::Exec.new(TestScutil.hostname, TestScutil.user,
34
+ { :port => TestScutil.port,
35
+ :scutil_verbose => false })
36
+ end
37
+
38
+ def teardown
39
+ @exec = nil
40
+ Scutil.connection_cache.remove_all
28
41
  end
29
42
 
30
- def test_initialize_exec_object
43
+ def test_object_initialized
31
44
  assert_not_nil @exec
32
45
  end
33
46
 
34
- def test_is_correct_instance
47
+ def test_object_is_correct_class
35
48
  assert_instance_of Scutil::Exec, @exec
36
49
  end
37
50
 
38
- def test_run_command
51
+ def test_exec_doesnt_raise_an_exception
52
+ assert_nothing_raised do
53
+ @exec.exec_command(TRUE_COMMAND)
54
+ end
55
+ end
56
+
57
+ def test_run_successful_command
58
+ retval = @exec.exec_command(TRUE_COMMAND)
59
+ assert_equal 0, retval
60
+ end
61
+
62
+ def test_run_failed_command
63
+ retval = @exec.exec_command(FALSE_COMMAND)
64
+ assert_not_equal 0, retval
65
+ end
66
+
67
+ def test_added_to_cache
68
+ @exec.exec_command(TRUE_COMMAND)
69
+ assert(Scutil.connection_cache.exists?(TestScutil.hostname))
70
+ end
71
+
72
+ def test_exec_command_output
39
73
  divert_stdout
40
- retval = @exec.exec_command('echo "alpha"')
74
+ @exec.exec_command('echo "alpha"')
75
+ # Scutil.exec_command(TestScutil.hostname, TestScutil.user, 'echo "alpha"', nil, { :port => TestScutil.port })
41
76
  revert_stdout
42
77
  assert_equal "alpha", @output.string.chomp
43
- assert_equal 0, retval
78
+ end
79
+
80
+ def test_clear_connection
81
+ @exec.exec_command(TRUE_COMMAND)
82
+ Scutil.clear!(TestScutil.hostname)
83
+ assert(!Scutil.connection_cache.exists?(TestScutil.hostname))
84
+ end
85
+
86
+ def test_exception_raised
87
+ assert_raises(Scutil::Error) do
88
+ @exec.exec_command(FAKE_COMMAND)
89
+ end
90
+ end
91
+
92
+ def test_pty_not_requested
93
+ @exec.exec_command(TRUE_COMMAND)
94
+ conn = Scutil.connection_cache.fetch(TestScutil.hostname)
95
+ assert_not_nil(conn.connection)
96
+ assert_instance_of(Net::SSH::Connection::Session, conn.connection)
97
+ assert_nil(conn.pty_connection)
98
+ end
99
+
100
+ def test_pty_requested
101
+ @exec.exec_command("sudo " + TRUE_COMMAND)
102
+ conn = Scutil.connection_cache.fetch(TestScutil.hostname)
103
+ assert_not_nil(conn.pty_connection)
104
+ assert_instance_of(Net::SSH::Connection::Session, conn.pty_connection)
105
+ assert_nil(conn.connection)
106
+ end
107
+
108
+ def test_option_pty_regex
109
+ @exec.exec_command("env " + TRUE_COMMAND, nil, { :scutil_pty_regex => /^env / })
110
+ conn = Scutil.connection_cache.fetch(TestScutil.hostname)
111
+ assert_not_nil(conn.pty_connection)
112
+ assert_instance_of(Net::SSH::Connection::Session, conn.pty_connection)
113
+ assert_nil(conn.connection)
114
+ end
115
+
116
+ def test_option_verbose_set_and_local_options_take_precedence
117
+ divert_stdout
118
+ @exec.exec_command(TRUE_COMMAND, nil, { :scutil_verbose => true })
119
+ revert_stdout
120
+ assert_match(/\[#{TestScutil.hostname}\]/, @output.string)
121
+ end
122
+
123
+ def test_option_force_pty
124
+ @exec.exec_command(TRUE_COMMAND, nil, { :scutil_force_pty => true })
125
+ conn = Scutil.connection_cache.fetch(TestScutil.hostname)
126
+ assert_not_nil(conn.pty_connection)
127
+ assert_instance_of(Net::SSH::Connection::Session, conn.pty_connection)
128
+ assert_nil(conn.connection)
44
129
  end
45
130
  end
46
131
 
47
- if ARGV[1].nil?
48
- puts "Usage: #{$0} host1 [host2 host3] port"
132
+ if ARGV[0].nil?
133
+ puts "Usage: #{$0} host[:port]"
49
134
  exit(1)
50
135
  end
136
+
137
+ (TestScutil.hostname, TestScutil.port) = ARGV[0].split(':')
138
+ TestScutil.user = 'mas'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: scutil
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.3
5
+ version: 0.2.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Marc Soda
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-09-27 00:00:00 Z
13
+ date: 2011-10-02 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: net-ssh