docker_toolkit 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -1
  3. data/Gemfile.lock +1 -1
  4. data/bin/terminator.rb +56 -0
  5. data/docker/Dockerfile +4 -1
  6. data/docker_toolkit.gemspec +1 -0
  7. data/lib/docker_toolkit/childprocess/abstract_io.rb +38 -0
  8. data/lib/docker_toolkit/childprocess/abstract_process.rb +194 -0
  9. data/lib/docker_toolkit/childprocess/errors.rb +28 -0
  10. data/lib/docker_toolkit/childprocess/jruby/io.rb +17 -0
  11. data/lib/docker_toolkit/childprocess/jruby/process.rb +161 -0
  12. data/lib/docker_toolkit/childprocess/jruby/pump.rb +55 -0
  13. data/lib/docker_toolkit/childprocess/jruby.rb +58 -0
  14. data/lib/docker_toolkit/childprocess/tools/generator.rb +148 -0
  15. data/lib/docker_toolkit/childprocess/unix/fork_exec_process.rb +72 -0
  16. data/lib/docker_toolkit/childprocess/unix/io.rb +22 -0
  17. data/lib/docker_toolkit/childprocess/unix/lib.rb +188 -0
  18. data/lib/docker_toolkit/childprocess/unix/platform/i386-linux.rb +14 -0
  19. data/lib/docker_toolkit/childprocess/unix/platform/i386-solaris.rb +13 -0
  20. data/lib/docker_toolkit/childprocess/unix/platform/x86_64-linux.rb +14 -0
  21. data/lib/docker_toolkit/childprocess/unix/platform/x86_64-macosx.rb +13 -0
  22. data/lib/docker_toolkit/childprocess/unix/posix_spawn_process.rb +135 -0
  23. data/lib/docker_toolkit/childprocess/unix/process.rb +91 -0
  24. data/lib/docker_toolkit/childprocess/unix.rb +11 -0
  25. data/lib/docker_toolkit/childprocess/version.rb +5 -0
  26. data/lib/docker_toolkit/childprocess/windows/handle.rb +93 -0
  27. data/lib/docker_toolkit/childprocess/windows/io.rb +25 -0
  28. data/lib/docker_toolkit/childprocess/windows/lib.rb +418 -0
  29. data/lib/docker_toolkit/childprocess/windows/process.rb +132 -0
  30. data/lib/docker_toolkit/childprocess/windows/process_builder.rb +177 -0
  31. data/lib/docker_toolkit/childprocess/windows/structs.rb +151 -0
  32. data/lib/docker_toolkit/childprocess/windows.rb +35 -0
  33. data/lib/docker_toolkit/childprocess.rb +208 -0
  34. data/lib/docker_toolkit/version.rb +1 -1
  35. data/lib/docker_toolkit/watcher.rb +188 -0
  36. data/lib/docker_toolkit.rb +5 -0
  37. metadata +33 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9065c8bb330bb661236077890a09b9e29231a7962ac51c907a5ad734bd952d5
4
- data.tar.gz: 290f4cb58b9dbea44f6e409f624911ca9f0c661468fa937484ad151d788f82ef
3
+ metadata.gz: 37e19e4995dbe0cc868b51fdae6fc18b69d26e12c85a68b8364113e19b7efdf8
4
+ data.tar.gz: 243fb2286022970786e1cdde0bffafacf35f6d5b9dd33fb9c1f1ea1b433e5626
5
5
  SHA512:
6
- metadata.gz: abb75dc06309b0b09ea590e0e4e1bf444d9c546695ab68706cb84694355ea655ce4405243d1eaf11617123243dd64406a26c3ae02a3a8419fef073bc2ac80717
7
- data.tar.gz: 5ae23825dbd86459d5a2e117e46ff8e15bec266077be420ce69dd5efde75d4b0ab65e92fa91fbe9e9d4e71519bc59dc5fca0fa5117b8bc8f1280b4c11a80c420
6
+ metadata.gz: 0553be938e83e0d9359181234499cf1cb10cf0fe0152eab1d29c8bd33f805810da1a8eb67bc0dd0e302cacd73a1eaa02f023c82827b66cc92efc5f7e21a91d20
7
+ data.tar.gz: 38a0e77028d94411d4da7ceccf40a34f8b2fa87f4147842e95cbc0340b211733af572e8e817d8f4ec281557d83f80db5cf53917fd9a2b9837744916bfe61a628
data/.travis.yml CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  language: ruby
2
3
  rvm:
3
4
  - 2.0
@@ -8,8 +9,16 @@ services:
8
9
 
9
10
  stage: test
10
11
 
12
+ before_install:
13
+ - sudo apt-get install -y libxml2-dev unzip curl
14
+
11
15
  script:
12
- - cd docker && ./run_tests.sh
16
+ - gem build `ls | grep gemspec`
17
+ - gem install `ls | grep -e '.gem$'`
18
+ - curl -sSLo /tmp/consul.zip https://releases.hashicorp.com/consul/1.2.1/consul_1.2.1_linux_amd64.zip
19
+ - sudo unzip -d /bin /tmp/consul.zip
20
+ - bundle exec rspec
21
+
13
22
 
14
23
  jobs:
15
24
  include:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- docker_toolkit (0.1.2)
4
+ docker_toolkit (0.1.3)
5
5
  diplomat
6
6
  json
7
7
 
data/bin/terminator.rb ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'English'
4
+
5
+ STDOUT.sync = true
6
+ STDERR.sync = true
7
+
8
+ @opts = {
9
+ code: 0,
10
+ sleep: 1,
11
+ term_code: 0
12
+ }
13
+
14
+ parser = OptionParser.new do |o|
15
+ o.banner = 'Usage: term.rb [options]'
16
+
17
+ o.on("--exit code=#{@opts[:code]}", 'set exit code') do |code|
18
+ @opts[:code] = code.to_i
19
+ end
20
+
21
+ o.on("--sleep sec=#{@opts[:sleep]}", 'Sleep before exit') do |sec|
22
+ @opts[:sleep] = sec.to_i
23
+ end
24
+
25
+ o.on('--term', 'SIGTERM self') do
26
+ @opts[:term] = true
27
+ end
28
+
29
+ o.on("--term-code=#{@opts[:term_code]}", 'exit code when SIGTERM catched') do |code|
30
+ @opts[:term_code] = code.to_i
31
+ end
32
+
33
+ o.on('--kill', 'SIGKILL self') do
34
+ @opts[:kill] = true
35
+ end
36
+
37
+ end
38
+ parser.parse!
39
+
40
+ def log msg
41
+ puts "[terminator]: #{msg}"
42
+ end
43
+
44
+
45
+ %w[INT TERM].each do |sig|
46
+ trap(sig) do
47
+ exit(@opts[:term_code])
48
+ end
49
+ end
50
+
51
+ sleep @opts[:sleep]
52
+
53
+ ::Process.kill('KILL', $$) if @opts[:kill]
54
+ ::Process.kill('TERM', $$) if @opts[:term]
55
+
56
+ exit @opts[:code]
data/docker/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.5.0-alpine
1
+ FROM mayok/alpine-ruby
2
2
  MAINTAINER Firmhouse "kinnalru@gmail.com"
3
3
 
4
4
  WORKDIR /home/app
@@ -46,6 +46,9 @@ RUN set -ex \
46
46
 
47
47
  ADD . /home/app
48
48
 
49
+ RUN set -ex \
50
+ && gem build `ls | grep gemspec` \
51
+ && gem install `ls | grep -e '.gem$'`
49
52
 
50
53
 
51
54
  SHELL ["/bin/sh", "-c", "-l"]
@@ -5,6 +5,7 @@ require 'docker_toolkit/version'
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'docker_toolkit'
7
7
  spec.version = DockerToolkit::VERSION
8
+ spec.license = 'MIT'
8
9
  spec.authors = ['Godko Ivan', 'Samoilenko Yuri']
9
10
  spec.email = ['igodko@rnds.pro', 'kinnalru@gmail.com']
10
11
  spec.homepage = 'https://github.com/RnD-Soft/docker_toolkit'
@@ -0,0 +1,38 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ class AbstractIO
4
+ attr_reader :stderr, :stdout, :stdin
5
+
6
+ def inherit!
7
+ @stdout = STDOUT
8
+ @stderr = STDERR
9
+ end
10
+
11
+ def stderr=(io)
12
+ check_type io
13
+ @stderr = io
14
+ end
15
+
16
+ def stdout=(io)
17
+ check_type io
18
+ @stdout = io
19
+ end
20
+
21
+ #
22
+ # @api private
23
+ #
24
+
25
+ def _stdin=(io)
26
+ check_type io
27
+ @stdin = io
28
+ end
29
+
30
+ private
31
+
32
+ def check_type(io)
33
+ raise SubclassResponsibility, "check_type"
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,194 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ class AbstractProcess
4
+ POLL_INTERVAL = 0.1
5
+
6
+ attr_reader :exit_code
7
+
8
+ #
9
+ # Set this to true if you do not care about when or if the process quits.
10
+ #
11
+ attr_accessor :detach
12
+
13
+ #
14
+ # Set this to true if you want to write to the process' stdin (process.io.stdin)
15
+ #
16
+ attr_accessor :duplex
17
+
18
+ #
19
+ # Modify the child's environment variables
20
+ #
21
+ attr_reader :environment
22
+
23
+ #
24
+ # Set the child's current working directory.
25
+ #
26
+ attr_accessor :cwd
27
+
28
+ #
29
+ # Set this to true to make the child process the leader of a new process group
30
+ #
31
+ # This can be used to make sure that all grandchildren are killed
32
+ # when the child process dies.
33
+ #
34
+ attr_accessor :leader
35
+
36
+ #
37
+ # Create a new process with the given args.
38
+ #
39
+ # @api private
40
+ # @see ChildProcess.build
41
+ #
42
+
43
+ def initialize(args)
44
+ unless args.all? { |e| e.kind_of?(String) }
45
+ raise ArgumentError, "all arguments must be String: #{args.inspect}"
46
+ end
47
+
48
+ @args = args
49
+ @started = false
50
+ @exit_code = nil
51
+ @io = nil
52
+ @cwd = nil
53
+ @detach = false
54
+ @duplex = false
55
+ @leader = false
56
+ @environment = {}
57
+ end
58
+
59
+ #
60
+ # Returns a ChildProcess::AbstractIO subclass to configure the child's IO streams.
61
+ #
62
+
63
+ def io
64
+ raise SubclassResponsibility, "io"
65
+ end
66
+
67
+ #
68
+ # @return [Integer] the pid of the process after it has started
69
+ #
70
+
71
+ def pid
72
+ raise SubclassResponsibility, "pid"
73
+ end
74
+
75
+ #
76
+ # Launch the child process
77
+ #
78
+ # @return [AbstractProcess] self
79
+ #
80
+
81
+ def start
82
+ launch_process
83
+ @started = true
84
+
85
+ self
86
+ end
87
+
88
+ #
89
+ # Forcibly terminate the process, using increasingly harsher methods if possible.
90
+ #
91
+ # @param [Integer] timeout (3) Seconds to wait before trying the next method.
92
+ #
93
+
94
+ def stop(timeout = 3)
95
+ raise SubclassResponsibility, "stop"
96
+ end
97
+
98
+ #
99
+ # Block until the process has been terminated.
100
+ #
101
+ # @return [Integer] The exit status of the process
102
+ #
103
+
104
+ def wait
105
+ raise SubclassResponsibility, "wait"
106
+ end
107
+
108
+ #
109
+ # Did the process exit?
110
+ #
111
+ # @return [Boolean]
112
+ #
113
+
114
+ def exited?
115
+ raise SubclassResponsibility, "exited?"
116
+ end
117
+
118
+ #
119
+ # Has the process started?
120
+ #
121
+ # @return [Boolean]
122
+ #
123
+
124
+ def started?
125
+ @started
126
+ end
127
+
128
+ #
129
+ # Is this process running?
130
+ #
131
+ # @return [Boolean]
132
+ #
133
+
134
+ def alive?
135
+ started? && !exited?
136
+ end
137
+
138
+ #
139
+ # Returns true if the process has exited and the exit code was not 0.
140
+ #
141
+ # @return [Boolean]
142
+ #
143
+
144
+ def crashed?
145
+ exited? && @exit_code != 0
146
+ end
147
+
148
+ #
149
+ # Wait for the process to exit, raising a ChildProcess::TimeoutError if
150
+ # the timeout expires.
151
+ #
152
+
153
+ def poll_for_exit(timeout)
154
+ log "polling #{timeout} seconds for exit"
155
+
156
+ end_time = Time.now + timeout
157
+ until (ok = exited?) || Time.now > end_time
158
+ sleep POLL_INTERVAL
159
+ end
160
+
161
+ unless ok
162
+ raise TimeoutError, "process still alive after #{timeout} seconds"
163
+ end
164
+ end
165
+
166
+ private
167
+
168
+ def launch_process
169
+ raise SubclassResponsibility, "launch_process"
170
+ end
171
+
172
+ def detach?
173
+ @detach
174
+ end
175
+
176
+ def duplex?
177
+ @duplex
178
+ end
179
+
180
+ def leader?
181
+ @leader
182
+ end
183
+
184
+ def log(*args)
185
+ ChildProcess.logger.debug "#{self.inspect} : #{args.inspect}"
186
+ end
187
+
188
+ def assert_started
189
+ raise Error, "process not started" unless started?
190
+ end
191
+
192
+ end # AbstractProcess
193
+ end # ChildProcess
194
+ end
@@ -0,0 +1,28 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ class Error < StandardError
4
+ end
5
+
6
+ class TimeoutError < Error
7
+ end
8
+
9
+ class SubclassResponsibility < Error
10
+ end
11
+
12
+ class InvalidEnvironmentVariable < Error
13
+ end
14
+
15
+ class LaunchError < Error
16
+ end
17
+
18
+ class MissingPlatformError < Error
19
+ def initialize
20
+ message = "posix_spawn is not yet supported on #{ChildProcess.platform_name} (#{RUBY_PLATFORM}), falling back to default implementation. " +
21
+ "If you believe this is an error, please file a bug at http://github.com/enkessler/childprocess/issues"
22
+
23
+ super(message)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ module JRuby
4
+ class IO < AbstractIO
5
+ private
6
+
7
+ def check_type(output)
8
+ unless output.respond_to?(:to_outputstream) && output.respond_to?(:write)
9
+ raise ArgumentError, "expected #{output.inspect} to respond to :to_outputstream"
10
+ end
11
+ end
12
+
13
+ end # IO
14
+ end # Unix
15
+ end # ChildProcess
16
+ end
17
+
@@ -0,0 +1,161 @@
1
+ require "java"
2
+
3
+ module DockerToolkit
4
+ module ChildProcess
5
+ module JRuby
6
+ class Process < AbstractProcess
7
+ def initialize(args)
8
+ super(args)
9
+
10
+ @pumps = []
11
+ end
12
+
13
+ def io
14
+ @io ||= JRuby::IO.new
15
+ end
16
+
17
+ def exited?
18
+ return true if @exit_code
19
+
20
+ assert_started
21
+ @exit_code = @process.exitValue
22
+ stop_pumps
23
+
24
+ true
25
+ rescue java.lang.IllegalThreadStateException => ex
26
+ log(ex.class => ex.message)
27
+ false
28
+ ensure
29
+ log(:exit_code => @exit_code)
30
+ end
31
+
32
+ def stop(timeout = nil)
33
+ assert_started
34
+
35
+ @process.destroy
36
+ wait # no way to actually use the timeout here..
37
+ end
38
+
39
+ def wait
40
+ if exited?
41
+ exit_code
42
+ else
43
+ @process.waitFor
44
+
45
+ stop_pumps
46
+ @exit_code = @process.exitValue
47
+ end
48
+ end
49
+
50
+ #
51
+ # Only supported in JRuby on a Unix operating system, thanks to limitations
52
+ # in Java's classes
53
+ #
54
+ # @return [Integer] the pid of the process after it has started
55
+ # @raise [NotImplementedError] when trying to access pid on non-Unix platform
56
+ #
57
+ def pid
58
+ if @process.getClass.getName != "java.lang.UNIXProcess"
59
+ raise NotImplementedError, "pid is only supported by JRuby child processes on Unix"
60
+ end
61
+
62
+ # About the best way we can do this is with a nasty reflection-based impl
63
+ # Thanks to Martijn Courteaux
64
+ # http://stackoverflow.com/questions/2950338/how-can-i-kill-a-linux-process-in-java-with-sigkill-process-destroy-does-sigter/2951193#2951193
65
+ field = @process.getClass.getDeclaredField("pid")
66
+ field.accessible = true
67
+ field.get(@process)
68
+ end
69
+
70
+ private
71
+
72
+ def launch_process(&blk)
73
+ pb = java.lang.ProcessBuilder.new(@args)
74
+
75
+ pb.directory java.io.File.new(@cwd || Dir.pwd)
76
+ set_env pb.environment
77
+
78
+ begin
79
+ @process = pb.start
80
+ rescue java.io.IOException => ex
81
+ raise LaunchError, ex.message
82
+ end
83
+
84
+ setup_io
85
+ end
86
+
87
+ def setup_io
88
+ if @io
89
+ redirect(@process.getErrorStream, @io.stderr)
90
+ redirect(@process.getInputStream, @io.stdout)
91
+ else
92
+ @process.getErrorStream.close
93
+ @process.getInputStream.close
94
+ end
95
+
96
+ if duplex?
97
+ io._stdin = create_stdin
98
+ else
99
+ @process.getOutputStream.close
100
+ end
101
+ end
102
+
103
+ def redirect(input, output)
104
+ if output.nil?
105
+ input.close
106
+ return
107
+ end
108
+
109
+ @pumps << Pump.new(input, output.to_outputstream).run
110
+ end
111
+
112
+ def stop_pumps
113
+ @pumps.each { |pump| pump.stop }
114
+ end
115
+
116
+ def set_env(env)
117
+ merged = ENV.to_hash
118
+
119
+ @environment.each { |k, v| merged[k.to_s] = v }
120
+
121
+ merged.each do |k, v|
122
+ if v
123
+ env.put(k, v.to_s)
124
+ elsif env.has_key? k
125
+ env.remove(k)
126
+ end
127
+ end
128
+
129
+ removed_keys = env.key_set.to_a - merged.keys
130
+ removed_keys.each { |k| env.remove(k) }
131
+ end
132
+
133
+ def create_stdin
134
+ output_stream = @process.getOutputStream
135
+
136
+ stdin = output_stream.to_io
137
+ stdin.sync = true
138
+ stdin.instance_variable_set(:@childprocess_java_stream, output_stream)
139
+
140
+ class << stdin
141
+ # The stream provided is a BufferedeOutputStream, so we
142
+ # have to flush it to make the bytes flow to the process
143
+ def __childprocess_flush__
144
+ @childprocess_java_stream.flush
145
+ end
146
+
147
+ [:flush, :print, :printf, :putc, :puts, :write, :write_nonblock].each do |m|
148
+ define_method(m) do |*args|
149
+ super(*args)
150
+ self.__childprocess_flush__
151
+ end
152
+ end
153
+ end
154
+
155
+ stdin
156
+ end
157
+
158
+ end # Process
159
+ end # JRuby
160
+ end # ChildProcess
161
+ end
@@ -0,0 +1,55 @@
1
+ module DockerToolkit
2
+ module ChildProcess
3
+ module JRuby
4
+ class Pump
5
+ BUFFER_SIZE = 2048
6
+
7
+ def initialize(input, output)
8
+ @input = input
9
+ @output = output
10
+ @stop = false
11
+ end
12
+
13
+ def stop
14
+ @stop = true
15
+ @thread && @thread.join
16
+ end
17
+
18
+ def run
19
+ @thread = Thread.new { pump }
20
+
21
+ self
22
+ end
23
+
24
+ private
25
+
26
+ def pump
27
+ buffer = Java.byte[BUFFER_SIZE].new
28
+
29
+ until @stop && (@input.available == 0)
30
+ read, avail = 0, 0
31
+
32
+ while read != -1
33
+ avail = [@input.available, 1].max
34
+ avail = BUFFER_SIZE if avail > BUFFER_SIZE
35
+ read = @input.read(buffer, 0, avail)
36
+
37
+ if read > 0
38
+ @output.write(buffer, 0, read)
39
+ @output.flush
40
+ end
41
+ end
42
+
43
+ sleep 0.1
44
+ end
45
+
46
+ @output.flush
47
+ rescue java.io.IOException => ex
48
+ ChildProcess.logger.debug ex.message
49
+ ChildProcess.logger.debug ex.backtrace
50
+ end
51
+
52
+ end # Pump
53
+ end # JRuby
54
+ end # ChildProcess
55
+ end
@@ -0,0 +1,58 @@
1
+ require 'java'
2
+ require 'jruby'
3
+
4
+ class Java::SunNioCh::FileChannelImpl
5
+ field_reader :fd
6
+ end
7
+
8
+ class Java::JavaIo::FileDescriptor
9
+ if ChildProcess.os == :windows
10
+ field_reader :handle
11
+ end
12
+
13
+ field_reader :fd
14
+ end
15
+
16
+ module DockerToolkit
17
+ module ChildProcess
18
+ module JRuby
19
+ def self.posix_fileno_for(obj)
20
+ channel = ::JRuby.reference(obj).channel
21
+ begin
22
+ channel.getFDVal
23
+ rescue NoMethodError
24
+ fileno = channel.fd
25
+ if fileno.kind_of?(Java::JavaIo::FileDescriptor)
26
+ fileno = fileno.fd
27
+ end
28
+
29
+ fileno == -1 ? obj.fileno : fileno
30
+ end
31
+ rescue
32
+ # fall back
33
+ obj.fileno
34
+ end
35
+
36
+ def self.windows_handle_for(obj)
37
+ channel = ::JRuby.reference(obj).channel
38
+ fileno = obj.fileno
39
+
40
+ begin
41
+ fileno = channel.getFDVal
42
+ rescue NoMethodError
43
+ fileno = channel.fd if channel.respond_to?(:fd)
44
+ end
45
+
46
+ if fileno.kind_of? Java::JavaIo::FileDescriptor
47
+ fileno.handle
48
+ else
49
+ Windows::Lib.handle_for fileno
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ require "docker_toolkit/childprocess/jruby/pump"
57
+ require "docker_toolkit/childprocess/jruby/io"
58
+ require "docker_toolkit/childprocess/jruby/process"