Class: CC::Analyzer::Container
- Inherits:
-
Object
- Object
- CC::Analyzer::Container
- Defined in:
- lib/cc/analyzer/container.rb
Defined Under Namespace
Classes: ContainerData, Result
Constant Summary collapse
- ImageRequired =
Class.new(StandardError)
- DEFAULT_TIMEOUT =
15m
15 * 60
- DEFAULT_MAXIMUM_OUTPUT_BYTES =
500_000_000
Instance Method Summary collapse
-
#initialize(image:, name:, command: nil, listener: ContainerListener.new) ⇒ Container
constructor
A new instance of Container.
- #on_output(delimeter = "\n", &block) ⇒ Object
- #run(options = []) ⇒ Object
- #stop(message = nil) ⇒ Object
Constructor Details
#initialize(image:, name:, command: nil, listener: ContainerListener.new) ⇒ Container
Returns a new instance of Container.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/cc/analyzer/container.rb', line 27 def initialize(image:, name:, command: nil, listener: ContainerListener.new) raise ImageRequired if image.blank? @image = image @name = name @command = command @listener = listener @output_delimeter = "\n" @on_output = ->(*) {} @timed_out = false @maximum_output_exceeded = false @stderr_io = StringIO.new @output_byte_count = 0 @counter_mutex = Mutex.new end |
Instance Method Details
#on_output(delimeter = "\n", &block) ⇒ Object
42 43 44 45 |
# File 'lib/cc/analyzer/container.rb', line 42 def on_output(delimeter = "\n", &block) @output_delimeter = delimeter @on_output = block end |
#run(options = []) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/cc/analyzer/container.rb', line 47 def run( = []) started = Time.now @listener.started(container_data) command = docker_run_command() CLI.debug("docker run: #{command.inspect}") pid, _, out, err = POSIX::Spawn.popen4(*command) @t_out = read_stdout(out) @t_err = read_stderr(err) t_timeout = timeout_thread # blocks until the engine stops. this is put in a thread so that we can # explicitly abort it as part of #stop. otherwise a run-away container # could still block here forever if the docker-kill/wait is not # successful. there may still be stdout in flight if it was being # produced more quickly than consumed. @t_wait = Thread.new { _, @status = Process.waitpid2(pid) } @t_wait.join # blocks until all readers are done. they're still governed by the # timeout thread at this point. if we hit the timeout while processing # output, the threads will be Thread#killed as part of #stop and this # will unblock with the correct value in @timed_out [@t_out, @t_err].each(&:join) if @timed_out duration = timeout * 1000 @listener.timed_out(container_data(duration: duration)) else duration = ((Time.now - started) * 1000).round @listener.finished(container_data(duration: duration, status: @status)) end Result.new( @status && @status.exitstatus, @timed_out, duration, @maximum_output_exceeded, output_byte_count, @stderr_io.string, ) ensure kill_reader_threads t_timeout.kill if t_timeout end |
#stop(message = nil) ⇒ Object
94 95 96 97 98 |
# File 'lib/cc/analyzer/container.rb', line 94 def stop( = nil) reap_running_container() kill_reader_threads kill_wait_thread end |