sshkit 0.0.7 → 0.0.8

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.md CHANGED
@@ -3,6 +3,29 @@
3
3
  This file is written in reverse chronological order, newer releases will
4
4
  appear at the top.
5
5
 
6
+ ## 0.0.8
7
+
8
+ * Added DSL method `background()` this sends a task to the background using
9
+ `nohup` and redirects it's output to `/dev/null` so as to avoid littering
10
+ the filesystem with `nohup.out` files.
11
+
12
+ **Note:** Backgrounding a task won't work as you expect if you give it a
13
+ string, that is you must do `background(:sleep, 5)` and not `background("sleep 5")`
14
+ according to the rules by which a command is not processed in any way **if it
15
+ contains a spaca character in it's first argument**.
16
+
17
+ Usage Example:
18
+
19
+ on hosts do
20
+ background :rake, "assets:precompile" # typically takes 5 minutes!
21
+ end
22
+
23
+ **Further:** Many programs are badly behaved and no not work well with `nohup`
24
+ it has to do with the way nohup works, reopening the processe's file
25
+ descriptors and redirecting them. Programs that re-open, or otherwise
26
+ manipulate their own file descriptors may lock up when the SSH session is
27
+ disconnected, often they block writing to, or reading from stdin/out.
28
+
6
29
  ## 0.0.7
7
30
 
8
31
  * DSL method `execute()` will now raise `SSHKit::Command::Failed` when the
data/EXAMPLES.md CHANGED
@@ -65,6 +65,25 @@ leading slashes. It may be misleading as the `File.join()` is performed on the
65
65
  machine running the code, if that's a Windows box, the paths may be incorrectly
66
66
  joined according to the expectations of the machine receiving the commands.
67
67
 
68
+ ## Running a task in the background
69
+
70
+ on hosts do
71
+ in '/opt/sites/example.com' do
72
+ background :rails, :server
73
+ end
74
+ end
75
+
76
+ This will run something like `nohup /usr/bin/env rails server > /dev/null &`,
77
+ backgrounding the Rails process, and making sure we don't leave nohup log
78
+ files littering the filesystem.
79
+
80
+ **Note:** The `background()` method won't do what you expect if you pass a
81
+ string `sleep 5`, according to the rules of processing commands, you must call
82
+ `background(:sleep, "5")` (that is, command: sleep, args: 5).
83
+
84
+ **Further Note:** The background() task wraps the given command in `nohup .... &` under some
85
+ circumstances the program will hang anyway when the SSH session exits.
86
+
68
87
  ## Do not care about the host block
69
88
 
70
89
  on hosts do
data/README.md CHANGED
@@ -178,8 +178,8 @@ should be printed.
178
178
 
179
179
  * No handling of slow / timed out connections
180
180
  * No handling of slow / hung remote commands
181
- * No built-in way to background() something (execute and background the
182
- process).
181
+ * ~~No built-in way to background() something (execute and background the
182
+ process).~~
183
183
  * No environment handling (sshkit might not need to care)
184
184
  * ~~No arbitrary `Host` properties (example storing `roles` on servers, or other
185
185
  metadata that might be useful in the `on()` block)~~
@@ -190,10 +190,10 @@ should be printed.
190
190
  * No verbosity control, commands should have a `Logger::LEVEL` on them,
191
191
  user-generated should be at a high level, the commands auto-generated from
192
192
  the guards and checks from as() and within() should have a lower level.
193
- * Decide if `execute()` (and friends) should raise on non-zero exit statuses or
193
+ * ~~Decide if `execute()` (and friends) should raise on non-zero exit statuses or
194
194
  not, perhaps a family of similarly named bang methods should be the ones to
195
195
  raise. (Perhaps `test()` should be a way to `execute()` without raising, and
196
- `execute()` and friends should always raise)
196
+ `execute()` and friends should always raise)~~
197
197
  * It would be nice to be able to say `SSHKit.config.formatter = :pretty` and
198
198
  have that method setter do the legwork of updating `SSHKit.config.output` to
199
199
  be an instance of the correct formatter class wrapping the existing output
@@ -204,3 +204,6 @@ should be printed.
204
204
  easily be modified to look into some connection factory for it's objects,
205
205
  saving half a second when running lots of `on()` blocks.
206
206
  * Documentation! (YARD style)
207
+ * Wrap all commands in a known shell, that is that `execute('uptime')` should
208
+ be converted into `sh -c 'uptime'` to ensure that we have a consistent shell
209
+ experience.
@@ -25,6 +25,10 @@ module SSHKit
25
25
  raise MethodUnavailableError
26
26
  end
27
27
 
28
+ def background(command, args=[])
29
+ raise MethodUnavailableError
30
+ end
31
+
28
32
  def test(command, args=[])
29
33
  raise MethodUnavailableError
30
34
  end
@@ -20,6 +20,11 @@ module SSHKit
20
20
  _execute(*args).success?
21
21
  end
22
22
 
23
+ def background(*args)
24
+ options = args.extract_options!.merge(run_in_background: true)
25
+ _execute(*[*args, options]).success?
26
+ end
27
+
23
28
  def capture(*args)
24
29
  _execute(*args).stdout.strip
25
30
  end
@@ -128,11 +128,17 @@ module SSHKit
128
128
  if options[:user]
129
129
  cs << "sudo su #{options[:user]} -c "
130
130
  end
131
+ if options[:run_in_background]
132
+ cs << 'nohup '
133
+ end
131
134
  cs << SSHKit.config.command_map[command.to_sym]
132
135
  if args.any?
133
136
  cs << ' '
134
137
  cs << args.join(' ')
135
138
  end
139
+ if options[:run_in_background]
140
+ cs << ' > /dev/null &'
141
+ end
136
142
  if options[:env]
137
143
  cs << ' )'
138
144
  end
@@ -142,7 +148,7 @@ module SSHKit
142
148
  private
143
149
 
144
150
  def default_options
145
- { raise_on_non_zero_exit: true }
151
+ { raise_on_non_zero_exit: true, run_in_background: false }
146
152
  end
147
153
 
148
154
  def sanitize_command!
@@ -1,3 +1,3 @@
1
1
  module SSHKit
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -1,22 +1,10 @@
1
1
  require 'helper'
2
+ require 'benchmark'
2
3
 
3
4
  module SSHKit
4
5
 
5
6
  module Backend
6
7
 
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
- warn "What: #{obj.to_hash}"
16
- original_output.write "> Executing #{obj}\n"
17
- end
18
- end
19
-
20
8
  class TestNetssh < FunctionalTest
21
9
 
22
10
  def setup
@@ -47,19 +35,18 @@ module SSHKit
47
35
  end
48
36
 
49
37
  def simple_netssh
50
- sio = ToSIoFormatter.new(StringIO.new)
51
38
  SSHKit.capture_output(sio) do
52
39
  printer.run
53
40
  end
54
41
  sio.rewind
55
42
  result = sio.read
56
43
  assert_equal <<-EOEXPECTED.unindent, result
57
- > Executing if test ! -d /opt/sites/example.com; then echo "Directory does not exist '/opt/sites/example.com'" 2>&1; false; fi
58
- > Executing cd /opt/sites/example.com && /usr/bin/env date
59
- > Executing cd /opt/sites/example.com && /usr/bin/env ls -l /some/directory
60
- > Executing if test ! -d /opt/sites/example.com/tmp; then echo "Directory does not exist '/opt/sites/example.com/tmp'" 2>&1; false; fi
61
- > Executing if ! sudo su -u root whoami > /dev/null; then echo "You cannot switch to user 'root' using sudo, please check the sudoers file" 2>&1; false; fi
62
- > Executing cd /opt/sites/example.com/tmp && ( RAILS_ENV=production ( sudo su -u root /usr/bin/env touch restart.txt ) )
44
+ if test ! -d /opt/sites/example.com; then echo "Directory does not exist '/opt/sites/example.com'" 2>&1; false; fi
45
+ cd /opt/sites/example.com && /usr/bin/env date
46
+ cd /opt/sites/example.com && /usr/bin/env ls -l /some/directory
47
+ if test ! -d /opt/sites/example.com/tmp; then echo "Directory does not exist '/opt/sites/example.com/tmp'" 2>&1; false; fi
48
+ if ! sudo su -u root whoami > /dev/null; then echo "You cannot switch to user 'root' using sudo, please check the sudoers file" 2>&1; false; fi
49
+ cd /opt/sites/example.com/tmp && ( RAILS_ENV=production ( sudo su -u root /usr/bin/env touch restart.txt ) )
63
50
  EOEXPECTED
64
51
  end
65
52
 
@@ -90,6 +77,21 @@ module SSHKit
90
77
  end.run
91
78
  end
92
79
 
80
+ def test_backgrounding_a_process
81
+ #SSHKit.config.output = SSHKit::Formatter::Pretty.new($stdout)
82
+ process_list = ""
83
+ time = Benchmark.measure do
84
+ Netssh.new(a_host) do
85
+ background :sleep, 5
86
+ end.run
87
+ Netssh.new(a_host) do
88
+ process_list = capture :ps, "aux | grep sleep | grep -v grep; true"
89
+ end.run
90
+ end
91
+ assert_operator time.real, :<, 1
92
+ assert_match "sleep 5", process_list
93
+ end
94
+
93
95
  end
94
96
 
95
97
  end
@@ -51,6 +51,21 @@ module SSHKit
51
51
  assert_equal "sudo su anotheruser -c /usr/bin/env whoami", String(c)
52
52
  end
53
53
 
54
+ def test_backgrounding_a_task
55
+ c = Command.new(:sleep, 15, run_in_background: true)
56
+ assert_equal "nohup /usr/bin/env sleep 15 > /dev/null &", String(c)
57
+ end
58
+
59
+ def test_backgrounding_a_task_as_a_given_user
60
+ c = Command.new(:sleep, 15, run_in_background: true, user: :anotheruser)
61
+ assert_equal "sudo su anotheruser -c nohup /usr/bin/env sleep 15 > /dev/null &", String(c)
62
+ end
63
+
64
+ def test_backgrounding_a_task_as_a_given_user_with_env
65
+ c = Command.new(:sleep, 15, run_in_background: true, user: :anotheruser, env: {a: :b})
66
+ assert_equal "( A=b sudo su anotheruser -c nohup /usr/bin/env sleep 15 > /dev/null & )", String(c)
67
+ end
68
+
54
69
  def test_complete?
55
70
  c = Command.new(:whoami, raise_on_non_zero_exit: false)
56
71
  refute c.complete?
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.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -256,10 +256,10 @@ files:
256
256
  - lib/sshkit/runners/sequential.rb
257
257
  - lib/sshkit/version.rb
258
258
  - sshkit.gemspec
259
+ - test/functional/backends/test_netssh.rb
259
260
  - test/functional/test_coordinator.rb
260
261
  - test/functional/test_ssh_server_comes_up_for_functional_tests.rb
261
262
  - test/helper.rb
262
- - test/integration/backends/test_netssh.rb
263
263
  - test/unit/backends/test_netssh.rb
264
264
  - test/unit/backends/test_printer.rb
265
265
  - test/unit/core_ext/test_string.rb
@@ -292,10 +292,10 @@ signing_key:
292
292
  specification_version: 3
293
293
  summary: SSHKit makes it easy to write structured, testable SSH commands in Ruby
294
294
  test_files:
295
+ - test/functional/backends/test_netssh.rb
295
296
  - test/functional/test_coordinator.rb
296
297
  - test/functional/test_ssh_server_comes_up_for_functional_tests.rb
297
298
  - test/helper.rb
298
- - test/integration/backends/test_netssh.rb
299
299
  - test/unit/backends/test_netssh.rb
300
300
  - test/unit/backends/test_printer.rb
301
301
  - test/unit/core_ext/test_string.rb