datacenter 0.3.1 → 0.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 00e4f1db48d930b517c89d8a48f716109e49ac1d
4
- data.tar.gz: cefbf9313f800f8988d5d6b0f6239c24d2c6b8c6
3
+ metadata.gz: 2098304fc0285b30cbe84d111c637bc2f9ed0ca9
4
+ data.tar.gz: 81dbb70a0d7e4a17dd5f1028ebccb97da5627e02
5
5
  SHA512:
6
- metadata.gz: 2fceb78d5755b96ac6762a6d531a125383507a5f138c2b6edaddbdad2c84800615b55e90232bf626d0bebe7854c709f56d7d3d3fc7e73e6851f59f4a3b56ccb4
7
- data.tar.gz: 5904e2beab150fc7552d78fb8f06c3c327f3a2d5cdec823c35b969261fc5855cf3e2cccae866d6fa53b4ac9be1389fb4239a97dbad2a5ac8c55e6a3c2e472e9f
6
+ metadata.gz: d72ca3f494c43436f9eda558deb0f24e0bd163e03581c51ff477db681d7347d4cd62a71681ca6ffd7154d3babb4a00d9ea59878678611d7f8db5330ebefd9350
7
+ data.tar.gz: eabe4a509235bfb64d5dee6f2cfeeb36bac9ead2d6eeec759b11db7cedd60817f37a660c9ae509497fc0568b3ee7712b48f4b64f60efed690655c902548c2db5
data/.travis.yml CHANGED
@@ -4,8 +4,10 @@ rvm:
4
4
  - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
+ - 2.3.0
7
8
  - jruby
8
9
  before_install:
10
+ - gem install bundler
9
11
  - sudo apt-get -y install openssh-server
10
12
  - ssh-keygen -q -t rsa -N "" -f ~/.ssh/id_rsa
11
- - cp $HOME/.ssh/id_rsa.pub $HOME/.ssh/authorized_keys
13
+ - cp $HOME/.ssh/id_rsa.pub $HOME/.ssh/authorized_keys
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ Rake::TestTask.new(:spec) do |t|
5
5
  t.libs << 'spec'
6
6
  t.pattern = 'spec/**/*_spec.rb'
7
7
  t.verbose = false
8
+ t.warning = false
8
9
  end
9
10
 
10
11
  desc 'Console'
@@ -15,4 +16,4 @@ task :console do
15
16
  Pry.start
16
17
  end
17
18
 
18
- task default: :spec
19
+ task default: :spec
data/lib/datacenter.rb CHANGED
@@ -2,6 +2,7 @@ require 'net/ssh'
2
2
  require 'open3'
3
3
  require 'class_config'
4
4
  require 'logger'
5
+ require 'delegate'
5
6
 
6
7
  module Datacenter
7
8
  extend ClassConfig
@@ -9,4 +10,4 @@ module Datacenter
9
10
  attr_config :process_cache_expiration, 2
10
11
  end
11
12
 
12
- Dir.glob(File.expand_path('datacenter/*.rb', File.dirname(__FILE__))).sort.each { |f| require f }
13
+ Dir.glob(File.expand_path('datacenter/**/*.rb', File.dirname(__FILE__))).sort.each { |f| require f }
@@ -0,0 +1,18 @@
1
+ module Datacenter
2
+ module Shell
3
+ class CommandError < StandardError
4
+
5
+ attr_reader :command, :error
6
+
7
+ def initialize(command, error)
8
+ @command = command
9
+ @error = error
10
+ end
11
+
12
+ def message
13
+ "#{command}\n#{error}"
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,101 @@
1
+ module Datacenter
2
+ module Shell
3
+ class Local
4
+
5
+ class SafeIO < SimpleDelegator
6
+ def initialize(io)
7
+ @io = io
8
+ super StringIO.new
9
+ end
10
+
11
+ def write(message)
12
+ super message
13
+ @io.write message
14
+ end
15
+ end
16
+
17
+
18
+ def initialize
19
+ @mutex = Mutex.new
20
+ end
21
+
22
+ def run(command, options={})
23
+ Datacenter.logger.debug(self.class) { command }
24
+
25
+ opts = {
26
+ chdir: options[:chdir] || Dir.pwd,
27
+ out: options[:out] || StringIO.new,
28
+ err: options[:err] || StringIO.new
29
+ }
30
+
31
+ if RUBY_ENGINE == 'jruby'
32
+ run_system command, opts
33
+ else
34
+ run_open3 command, opts
35
+ end
36
+ end
37
+
38
+ def self.open(*args)
39
+ shell = new *args
40
+ yield shell
41
+ end
42
+
43
+ private
44
+
45
+ def run_open3(command, options)
46
+ status = nil
47
+ result = nil
48
+ error = nil
49
+
50
+ begin
51
+ Open3.popen3("#{command}", chdir: options[:chdir]) do |stdin, stdout, stderr, wait_thr|
52
+ status = wait_thr.value
53
+ result = stdout.read
54
+ error = stderr.read
55
+
56
+ options[:out] << result
57
+ options[:err] << error
58
+ end
59
+ rescue => ex
60
+ raise CommandError.new(command, ex.message)
61
+ end
62
+
63
+ raise CommandError.new(command, error) unless status.success?
64
+
65
+ result
66
+ end
67
+
68
+ def run_system(command, options)
69
+ @mutex.synchronize do
70
+ begin
71
+ stdout = $stdout
72
+ stderr = $stderr
73
+
74
+ $stdout = SafeIO.new options[:out]
75
+ $stderr = SafeIO.new options[:err]
76
+
77
+ Dir.chdir(options[:chdir]) { system "#{command}" }
78
+
79
+ status = $?
80
+
81
+ $stdout.rewind
82
+ $stderr.rewind
83
+
84
+ result = $stdout.read.force_encoding('UTF-8')
85
+ error = $stderr.read.force_encoding('UTF-8')
86
+
87
+ raise CommandError.new(command, error) unless status.success?
88
+
89
+ result
90
+
91
+ ensure
92
+ $stdout = stdout
93
+ $stderr = stderr
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,80 @@
1
+ module Datacenter
2
+ module Shell
3
+ class Remote
4
+
5
+ def initialize(*args)
6
+ @args = args
7
+ end
8
+
9
+ def open
10
+ @session ||= Net::SSH.start *args
11
+ end
12
+
13
+ def close
14
+ if session && !session.closed?
15
+ session.close
16
+ @session = nil
17
+ end
18
+ end
19
+
20
+ def run(command, options={})
21
+ if session
22
+ run! command, options
23
+ else
24
+ self.class.open(*args) { |shell| shell.run command, options }
25
+ end
26
+ end
27
+
28
+ def self.open(*args)
29
+ shell = new *args
30
+ shell.open
31
+ yield shell
32
+ ensure
33
+ shell.close
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :args, :session
39
+
40
+ def run!(command, options={})
41
+ Datacenter.logger.debug(self.class) { command }
42
+
43
+ result = ''
44
+ error = ''
45
+
46
+ out = options[:out] || StringIO.new
47
+ err = options[:err] || StringIO.new
48
+
49
+ exit_code = nil
50
+
51
+ session.open_channel do |channel|
52
+ channel.exec(command) do |ch, success|
53
+ abort "FAILED: couldn't execute command (ssh.channel.exec)" unless success
54
+
55
+ channel.on_data do |ch, data|
56
+ out << data
57
+ result << data
58
+ end
59
+
60
+ channel.on_extended_data do |ch, type, data|
61
+ err << data
62
+ error << data
63
+ end
64
+
65
+ channel.on_request('exit-status') do |ch, data|
66
+ exit_code = data.read_long
67
+ end
68
+ end
69
+ end
70
+
71
+ session.loop
72
+
73
+ raise CommandError.new(command, error) unless exit_code == 0
74
+
75
+ result
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  module Datacenter
2
- VERSION = '0.3.1'
2
+ VERSION = '0.4.0'
3
3
  end
data/spec/shell_spec.rb CHANGED
@@ -3,21 +3,48 @@ require 'minitest_helper'
3
3
  describe Datacenter::Shell do
4
4
 
5
5
  module SharedExpamples
6
+
7
+ let(:shell) { shell_class.new *shell_args }
8
+
6
9
  it 'Success' do
7
10
  filename = File.join '/tmp', Time.now.to_i.to_s
8
11
  shell.run "echo \"test file\" > #{filename}"
9
- shell.run("cat #{filename}").must_equal 'test file'
12
+ shell.run("cat #{filename}").must_equal "test file\n"
10
13
  end
11
14
 
12
15
  it 'Error' do
13
16
  filename = '/invalid_dir/invalid_file'
14
- shell.run("cat #{filename}").must_equal "cat: #{filename}: No such file or directory"
17
+ error = Proc.new { shell.run "cat #{filename}" }.must_raise Datacenter::Shell::CommandError
18
+ error.message.must_include "cat: #{filename}: No such file or directory"
19
+ end
20
+
21
+ it 'Block' do
22
+ shell_class.open(*shell_args) do |shell|
23
+ shell.run('ls /').must_equal `ls /`
24
+ end
25
+ end
26
+
27
+ it 'Redirect stdout' do
28
+ out = StringIO.new
29
+ shell.run 'ls /', out: out
30
+ out.rewind
31
+ out.read.must_equal `ls /`
15
32
  end
33
+
34
+ it 'Redirect stderr' do
35
+ err = StringIO.new
36
+ filename = '/invalid_dir/invalid_file'
37
+ Proc.new { shell.run "cat #{filename}", err: err }.must_raise Datacenter::Shell::CommandError
38
+ err.rewind
39
+ err.read.must_include "cat: #{filename}: No such file or directory"
40
+ end
41
+
16
42
  end
17
43
 
18
44
  describe 'Local' do
19
45
 
20
- let(:shell) { Datacenter::Shell::Local.new }
46
+ let(:shell_args) { [] }
47
+ let(:shell_class) { Datacenter::Shell::Local }
21
48
 
22
49
  include SharedExpamples
23
50
 
@@ -25,17 +52,11 @@ describe Datacenter::Shell do
25
52
 
26
53
  describe 'Remote' do
27
54
 
28
- let(:connection_args) { ['localhost', `whoami`.strip] }
29
- let(:shell) { Datacenter::Shell::Remote.new *connection_args }
55
+ let(:shell_args) { ['localhost', `whoami`.strip] }
56
+ let(:shell_class) { Datacenter::Shell::Remote }
30
57
 
31
58
  include SharedExpamples
32
59
 
33
- it 'Block' do
34
- Datacenter::Shell::Remote.open(*connection_args) do |shell|
35
- shell.run('ls /').must_equal `ls /`.strip
36
- end
37
- end
38
-
39
60
  end
40
61
 
41
62
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datacenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-25 00:00:00.000000000 Z
11
+ date: 2016-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-ssh
@@ -144,7 +144,9 @@ files:
144
144
  - lib/datacenter/machine.rb
145
145
  - lib/datacenter/os.rb
146
146
  - lib/datacenter/process.rb
147
- - lib/datacenter/shell.rb
147
+ - lib/datacenter/shell/command_error.rb
148
+ - lib/datacenter/shell/local.rb
149
+ - lib/datacenter/shell/remote.rb
148
150
  - lib/datacenter/version.rb
149
151
  - spec/cache_spec.rb
150
152
  - spec/commands.yml
@@ -1,83 +0,0 @@
1
- module Datacenter
2
- module Shell
3
-
4
- class Local
5
-
6
- def initialize
7
- @mutex = Mutex.new
8
- end
9
-
10
- def run(command)
11
- Datacenter.logger.debug(self.class) { command }
12
- if RUBY_ENGINE == 'jruby'
13
- run_system command
14
- else
15
- run_open3 command
16
- end
17
- end
18
-
19
- private
20
-
21
- def run_open3(command)
22
- i,o,e,t = Open3.popen3 command
23
- (o.readlines.join + e.readlines.join).strip
24
- end
25
-
26
- def run_system(command)
27
- @mutex.synchronize do
28
- begin
29
- $stdout = StringIO.new
30
- $stderr = StringIO.new
31
-
32
- system command
33
-
34
- [$stdout, $stderr].map do |io|
35
- io.rewind
36
- io.readlines.join.force_encoding('UTF-8')
37
- end.join.strip
38
-
39
- ensure
40
- $stdout = STDOUT
41
- $stderr = STDERR
42
- end
43
- end
44
- end
45
- end
46
-
47
- class Remote
48
- attr_reader :options
49
-
50
- def initialize(*args)
51
- @options = args
52
- end
53
-
54
- def run(command)
55
- Datacenter.logger.debug(self.class) { command }
56
- if @session
57
- @session.exec!(command).strip
58
- else
59
- Net::SSH.start(*options) { |ssh| ssh.exec! command }.to_s.strip
60
- end
61
- end
62
-
63
- def open
64
- @session ||= Net::SSH.start *options
65
- end
66
-
67
- def close
68
- if @session
69
- @session.close
70
- @session = nil
71
- end
72
- end
73
-
74
- def self.open(*args, &block)
75
- shell = new *args
76
- shell.open
77
- block.call shell
78
- shell.close
79
- end
80
- end
81
-
82
- end
83
- end