sshkit 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  *.gem
2
+ .yardoc
2
3
  .vagrant
3
4
  test/tmp
data/.yardopts CHANGED
@@ -1 +1 @@
1
- --no-private - README.md CHANGELOG.md FAQ.md LICENSE.md EXAMPLES.md
1
+ --no-private - README.md CHANGELOG.md FAQ.md LICENSE.md EXAMPLES.md CONTRIBUTING.md RELEASING.md
data/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  This file is written in reverse chronological order, newer releases will
4
4
  appear at the top.
5
5
 
6
+ ## 0.0.3
7
+
8
+ * Refactor the runner classes into an abstract heirarchy.
9
+
6
10
  ## 0.0.2
7
11
 
8
12
  * Include a *Pretty* formatter
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,4 @@
1
+ # Contributing to SSHKit
2
+
3
+ * [**Don't** push your pull request](http://www.igvita.com/2011/12/19/dont-push-your-pull-requests/)
4
+ * [**Do** write a good commit message](http://365git.tumblr.com/post/3308646748/writing-git-commit-messages)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sshkit (0.0.1)
4
+ sshkit (0.0.2)
5
5
  net-ssh
6
6
  term-ansicolor
7
7
 
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
- ![SSHKit Logo](/Users/leehambley/Projects/deployrb-deploy/assets/images/logo.png)
2
-
1
+ ![SSHKit Logo](https://raw.github.com/wacku/sshkit/master/assets/images/logo.png)
3
2
 
4
3
  **SSHKit** is a toolkit for running commands in a structured way on one or
5
4
  more servers.
@@ -48,7 +47,7 @@ the raised error.
48
47
  Helpers such as `runner()` and `rake()` which expand to `execute(:rails, "runner", ...)` and
49
48
  `execute(:rake, ...)` are convenience helpers for Ruby, and Rails based apps.
50
49
 
51
- ## Parallel
50
+ ## Parallel
52
51
 
53
52
  Notice on the `on()` call the `in: :sequence` option, the following will do
54
53
  what you might expect:
@@ -156,6 +155,8 @@ first argument before attempting to find it in the *command map*.
156
155
 
157
156
  ## Output Handling
158
157
 
158
+ ![Example Output](https://raw.github.com/wacku/sshkit/master/assets/images/example_output.png)
159
+
159
160
  The output handling comprises two objects, first is the output itself, by
160
161
  default this is *$stdout*, but can be any object responding to a
161
162
  *StringIO*-like interface. The second part is the *formatter*.
@@ -173,9 +174,30 @@ should be printed.
173
174
  ## Known Issues
174
175
 
175
176
  * No handling of slow / timed out connections
176
- * No handling ot slow / hung remote commands
177
+ * No handling of slow / hung remote commands
177
178
  * No built-in way to background() something (execute and background the
178
- process)
179
- * No environment handling
180
- * No arbitrary `Host` properties
181
-
179
+ process).
180
+ * No environment handling (sshkit might not need to care)
181
+ * No arbitrary `Host` properties (example storing `roles` on servers, or other
182
+ metadata that might be useful in the `on()` block)
183
+ * No log/warning facility (passing Log messages to the output would work)
184
+ A log object could be made available globally which would emit a LogMessage
185
+ type object which would be recognised by the formatters that need to care
186
+ about them.
187
+ * No verbosity control, commands should have a `Logger::LEVEL` on them,
188
+ user-generated should be at a high level, the commands auto-generated from
189
+ the guards and checks from as() and within() should have a lower level.
190
+ * Decide if `execute()` (and friends) should raise on non-zero exit statuses or
191
+ not, perhaps a family of similarly named bang methods should be the ones to
192
+ raise. (Perhaps `test()` should be a way to `execute()` without raising, and
193
+ `execute()` and friends should always raise)
194
+ * It would be nice to be able to say `SSHKit.config.formatter = :pretty` and
195
+ have that method setter do the legwork of updating `SSHKit.config.output` to
196
+ be an instance of the correct formatter class wrapping the existing output
197
+ stream.
198
+ * No closing of connections, the abstract backend class should include a
199
+ cleanup method which is empty but can be overriden by
200
+ * No conncetion pooling, the `connection` method of the NetSSH backend could
201
+ easily be modified to look into some connection factory for it's objects,
202
+ saving half a second when running lots of `on()` blocks.
203
+ * Documentation! (YARD style)
data/RELEASING.md ADDED
@@ -0,0 +1,10 @@
1
+ # Releasing
2
+
3
+ * **Ensure the tests are passing.**
4
+ * Determine which would be the correct next version number according to [semver](http://semver.org/).
5
+ * Update the version in `./lib/sshkit/version.rb`.
6
+ * Update the `CHANGELOG`.
7
+ * Commit the changelog and version in a single commit, the message should be "Preparing vX.Y.Z"
8
+ * Tag the commit `git tag vX.Y.Z` (if tagging a historical commit, `git tag` can take a *SHA1* after the tag name)
9
+ * Push new commits, and tags to Github.
10
+ * Push the gem to [rubygems](http://rubygems.org).
Binary file
data/lib/sshkit/all.rb CHANGED
@@ -11,6 +11,7 @@ require_relative 'connection_manager'
11
11
  require_relative 'formatters/abstract'
12
12
  require_relative 'formatters/black_hole'
13
13
  require_relative 'formatters/pretty'
14
+ require_relative 'formatters/dot'
14
15
 
15
16
  require_relative 'backends/abstract'
16
17
  require_relative 'backends/printer'
@@ -10,7 +10,7 @@ module SSHKit
10
10
  end
11
11
 
12
12
  def execute(*args)
13
- output << command(*args)
13
+ output << String(command(*args)) + "\n"
14
14
  end
15
15
 
16
16
  def capture(command, args=[])
@@ -1,54 +1,68 @@
1
1
  require 'timeout'
2
2
 
3
- class Runner
3
+ module SSHKit
4
4
 
5
- attr_reader :hosts, :block
5
+ module Runner
6
6
 
7
- def initialize(hosts, &block)
8
- @hosts = Array(hosts)
9
- @block = block
10
- end
7
+ class Abstract
11
8
 
12
- end
9
+ attr_reader :hosts, :block
10
+
11
+ def initialize(hosts, &block)
12
+ @hosts = Array(hosts)
13
+ @block = block
14
+ end
15
+
16
+ private
13
17
 
14
- class ParallelRunner < Runner
15
- def execute
16
- threads = []
17
- hosts.each do |host|
18
- threads << Thread.new(host) do |h|
19
- SSHKit.config.backend.new(host, &block).run
18
+ def backend(host, &block)
19
+ SSHKit.config.backend.new(host, &block)
20
20
  end
21
+
21
22
  end
22
- threads.map(&:join)
23
- end
24
- end
25
23
 
26
- class SequentialRunner < Runner
27
- attr_writer :wait_interval
28
- def execute
29
- hosts.each do |host|
30
- SSHKit.config.backend.new(host, &block).run
31
- sleep wait_interval
24
+ class Parallel < Abstract
25
+ def execute
26
+ threads = []
27
+ hosts.each do |host|
28
+ threads << Thread.new(host) do |h|
29
+ backend(host, &block).run
30
+ end
31
+ end
32
+ threads.map(&:join)
33
+ end
34
+ end
35
+
36
+ class Sequential < Abstract
37
+ attr_writer :wait_interval
38
+ def execute
39
+ hosts.each do |host|
40
+ backend(host, &block).run
41
+ sleep wait_interval
42
+ end
43
+ end
44
+ private
45
+ def wait_interval
46
+ @wait_interval ||= 2
47
+ end
48
+ end
49
+
50
+ class Group < Sequential
51
+ attr_writer :group_size
52
+ def execute
53
+ hosts.each_slice(group_size).collect do |group_hosts|
54
+ Parallel.new(group_hosts, &block).execute
55
+ sleep wait_interval
56
+ end.flatten
57
+ end
58
+ private
59
+ def group_size
60
+ @group_size ||= 2
61
+ end
32
62
  end
33
- end
34
- private
35
- def wait_interval
36
- @wait_interval ||= 2
37
- end
38
- end
39
63
 
40
- class GroupRunner < SequentialRunner
41
- attr_writer :group_size
42
- def execute
43
- hosts.each_slice(group_size).collect do |group_hosts|
44
- ParallelRunner.new(group_hosts, &block).execute
45
- sleep wait_interval
46
- end.flatten
47
- end
48
- private
49
- def group_size
50
- @group_size ||= 2
51
64
  end
65
+
52
66
  end
53
67
 
54
68
  module SSHKit
@@ -68,9 +82,9 @@ module SSHKit
68
82
  def each(options={}, &block)
69
83
  options = default_options.merge(options)
70
84
  case options[:in]
71
- when :parallel then ParallelRunner
72
- when :sequence then SequentialRunner
73
- when :groups then GroupRunner
85
+ when :parallel then Runner::Parallel
86
+ when :sequence then Runner::Sequential
87
+ when :groups then Runner::Group
74
88
  else
75
89
  raise RuntimeError, "Don't know how to handle run style #{options[:in].inspect}"
76
90
  end.new(hosts, &block).execute
@@ -0,0 +1,28 @@
1
+ require 'term/ansicolor'
2
+
3
+ module SSHKit
4
+
5
+ module Formatter
6
+
7
+ class Dot < Abstract
8
+
9
+ def write(obj)
10
+ if obj.is_a? SSHKit::Command
11
+ if obj.finished?
12
+ original_output << (obj.failure? ? c.red('.') : c.green('.'))
13
+ end
14
+ end
15
+ end
16
+ alias :<< :write
17
+
18
+ private
19
+
20
+ def c
21
+ @c ||= Term::ANSIColor
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -1,3 +1,3 @@
1
1
  module SSHKit
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -4,18 +4,6 @@ module SSHKit
4
4
 
5
5
  module Backend
6
6
 
7
- class ToSIoFormatter < StringIO
8
- extend Forwardable
9
- attr_reader :original_output
10
- def_delegators :@original_output, :read, :rewind
11
- def initialize(oio)
12
- @original_output = oio
13
- end
14
- def write(obj)
15
- original_output.write "> Executing #{obj}\n"
16
- end
17
- end
18
-
19
7
  class TestPrinter < UnitTest
20
8
 
21
9
  def block_to_run
@@ -39,19 +27,19 @@ module SSHKit
39
27
  end
40
28
 
41
29
  def test_simple_printing
42
- sio = ToSIoFormatter.new(StringIO.new)
30
+ sio = StringIO.new
43
31
  SSHKit.capture_output(sio) do
44
32
  printer.run
45
33
  end
46
34
  sio.rewind
47
35
  result = sio.read
48
36
  assert_equal <<-EOEXPECTED.unindent, result
49
- > Executing if test ! -d /opt/sites/example.com; then echo "Directory does not exist '/opt/sites/example.com'" 1>&2; false; fi
50
- > Executing cd /opt/sites/example.com && /usr/bin/env date
51
- > Executing cd /opt/sites/example.com && /usr/bin/env ls -l /some/directory
52
- > Executing if test ! -d /opt/sites/example.com/tmp; then echo "Directory does not exist '/opt/sites/example.com/tmp'" 1>&2; false; fi
53
- > Executing if ! sudo su root -c whoami > /dev/null; then echo "You cannot switch to user 'root' using sudo, please check the sudoers file" 1>&2; false; fi
54
- > Executing cd /opt/sites/example.com/tmp && ( RAILS_ENV=production sudo su root -c /usr/bin/env touch restart.txt )
37
+ if test ! -d /opt/sites/example.com; then echo "Directory does not exist '/opt/sites/example.com'" 1>&2; false; fi
38
+ cd /opt/sites/example.com && /usr/bin/env date
39
+ cd /opt/sites/example.com && /usr/bin/env ls -l /some/directory
40
+ if test ! -d /opt/sites/example.com/tmp; then echo "Directory does not exist '/opt/sites/example.com/tmp'" 1>&2; false; fi
41
+ if ! sudo su root -c whoami > /dev/null; then echo "You cannot switch to user 'root' using sudo, please check the sudoers file" 1>&2; false; fi
42
+ cd /opt/sites/example.com/tmp && ( RAILS_ENV=production sudo su root -c /usr/bin/env touch restart.txt )
55
43
  EOEXPECTED
56
44
  end
57
45
 
@@ -1,3 +1,4 @@
1
+ require 'time'
1
2
  require 'helper'
2
3
 
3
4
  module SSHKit
@@ -5,7 +6,18 @@ module SSHKit
5
6
  class TestConnectionManager < UnitTest
6
7
 
7
8
  def setup
8
- SSHKit.config.backend = SSHKit::Backend::Abstract
9
+ @s = String.new
10
+ SSHKit.config.backend = SSHKit::Backend::Printer
11
+ end
12
+
13
+ def tearddown
14
+ @s = nil
15
+ end
16
+
17
+ def block_to_run
18
+ lambda do |host|
19
+ execute "echo #{Time.now}"
20
+ end
9
21
  end
10
22
 
11
23
  def test_connection_manager_handles_a_single_argument
@@ -26,40 +38,38 @@ module SSHKit
26
38
  end
27
39
 
28
40
  def test_the_connection_manager_yields_the_host_to_each_connection_instance
29
- spy = lambda do |host, connection|
30
- assert_equal host, Host.new("1.example.com")
41
+ spy = lambda do |host|
42
+ execute "echo #{host.hostname}"
43
+ end
44
+ String.new.tap do |str|
45
+ SSHKit.capture_output str do
46
+ ConnectionManager.new(%w{1.example.com}).each &spy
47
+ end
48
+ assert_equal "echo 1.example.com", str.strip
31
49
  end
32
- ConnectionManager.new(%w{1.example.com}).each &spy
33
50
  end
34
51
 
35
52
  def test_the_connection_manaager_runs_things_in_parallel_by_default
36
- results = []
37
- command = lambda do |host,connection|
38
- results << Time.now
53
+ SSHKit.capture_output @s do
54
+ ConnectionManager.new(%w{1.example.com 2.example.com}).each &block_to_run
39
55
  end
40
- ConnectionManager.new(%w{1.example.com 2.example.com}).each &command
41
56
  assert_equal 2, results.length
42
57
  assert_equal *results.map(&:to_i)
43
58
  end
44
59
 
45
60
  def test_the_connection_manager_can_run_things_in_sequence
46
- results = []
47
- command = lambda do |host,connection|
48
- results << Time.now
61
+ SSHKit.capture_output @s do
62
+ ConnectionManager.new(%w{1.example.com 2.example.com}).each in: :sequence, &block_to_run
49
63
  end
50
- ConnectionManager.new(%w{1.example.com 2.example.com}).each(in: :sequence, &command)
51
64
  assert_equal 2, results.length
52
65
  assert_operator results.first.to_i, :<, results.last.to_i
53
66
  end
54
67
 
55
68
  def test_the_connection_manager_can_run_things_in_groups
56
- results = []
57
- command = lambda do |host,connection|
58
- debugger
59
- results << Time.now
69
+ SSHKit.capture_output @s do
70
+ ConnectionManager.new(%w{1.example.com 2.example.com 3.example.com
71
+ 4.example.com 5.example.com 6.example.com}).each in: :groups, &block_to_run
60
72
  end
61
- ConnectionManager.new(%w{1.example.com 2.example.com 3.example.com
62
- 4.example.com 5.example.com 6.example.com}).each(in: :groups, &command)
63
73
  assert_equal 6, results.length
64
74
  assert_equal *results[0..1].map(&:to_i)
65
75
  assert_equal *results[2..3].map(&:to_i)
@@ -68,9 +78,12 @@ module SSHKit
68
78
  assert_operator results[3].to_i, :<, results[4].to_i
69
79
  end
70
80
 
71
- def test_slow_host_timeout
72
- # Ensure that we throw an error and rollback if one host takes an
73
- # exceptional length of time longer than the others
81
+ private
82
+
83
+ def results
84
+ @s.lines.collect do |line|
85
+ Time.parse(line.split[1..-1].join(' '))
86
+ end
74
87
  end
75
88
 
76
89
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sshkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-01-16 00:00:00.000000000 Z
13
+ date: 2013-01-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: net-ssh
@@ -221,20 +221,19 @@ extra_rdoc_files: []
221
221
  files:
222
222
  - .gitignore
223
223
  - .travis.yml
224
- - .yardoc/checksums
225
- - .yardoc/object_types
226
- - .yardoc/objects/root.dat
227
- - .yardoc/proxy_types
228
224
  - .yardopts
229
225
  - CHANGELOG.md
226
+ - CONTRIBUTING.md
230
227
  - EXAMPLES.md
231
228
  - FAQ.md
232
229
  - Gemfile
233
230
  - Gemfile.lock
234
231
  - LICENSE.md
235
232
  - README.md
233
+ - RELEASING.md
236
234
  - Rakefile
237
235
  - Vagrantfile
236
+ - assets/images/example_output.png
238
237
  - assets/images/logo.png
239
238
  - example.rb
240
239
  - lib/core_ext/array.rb
@@ -250,6 +249,7 @@ files:
250
249
  - lib/sshkit/dsl.rb
251
250
  - lib/sshkit/formatters/abstract.rb
252
251
  - lib/sshkit/formatters/black_hole.rb
252
+ - lib/sshkit/formatters/dot.rb
253
253
  - lib/sshkit/formatters/pretty.rb
254
254
  - lib/sshkit/host.rb
255
255
  - lib/sshkit/version.rb
data/.yardoc/checksums DELETED
@@ -1,13 +0,0 @@
1
- lib/deploy.rb 8f584561b611345114f38176ec53bf00f9d5550f
2
- lib/deploy/all.rb 9fc0b15f0968612fbd2ffaf0bba9dff6f788e3d1
3
- lib/deploy/host.rb 777a8deedcdd5b41dceab8773c992bafa5ee9f92
4
- lib/core_ext/hash.rb b7a0f0d1ab3b83f6b251e2f865ad6fa3766124a0
5
- lib/deploy/command.rb 1a04acc7d5abd1b288bbea3676c287434849ef05
6
- lib/core_ext/array.rb 3d495a96a0d1566877bf2ebb70ab9ea10a7d32e1
7
- lib/deploy/version.rb 30e41688e07f7ee74377aaef147250340df4a3f0
8
- lib/deploy/configuration.rb 3e9f042e0e9e9860d3950a1406a988586434de16
9
- lib/deploy/backends/netssh.rb c931441edd28ba7e134b0d3ae2fbf40efb347b81
10
- lib/deploy/backends/printer.rb db41b51e9624105efd7cb7f1fef426b506ebadaa
11
- lib/deploy/backends/abstract.rb 74260020d3a6c4913f7a3d9294968e1b2a1304a9
12
- lib/deploy/connection_manager.rb 28c8ef12a8a5923aeaa497ed02fd22869f57186b
13
- lib/deploy/dsl.rb a487b4e65ab52955b12a5fe55bda99dec61e16b9
data/.yardoc/object_types DELETED
Binary file
Binary file
data/.yardoc/proxy_types DELETED
Binary file