datacenter 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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