inspec/test/docker_run.rb
2015-09-23 01:51:51 +02:00

119 lines
2.8 KiB
Ruby

# encoding: utf-8
require 'docker'
require 'yaml'
require 'concurrent'
class DockerRunner
def initialize(conf_path = nil)
@conf_path = conf_path ||
ENV['config'] ||
File.join(File.dirname(__FILE__), 'test.yaml')
unless File.file?(@conf_path)
fail "Can't find configuration in #{@conf_path}"
end
@conf = YAML.load_file(@conf_path)
if @conf.nil? or @conf.empty?
fail "Can't read coniguration in #{@conf_path}"
end
if @conf['images'].nil?
fail "You must configure test images in your #{@conf_path}"
end
@images = docker_images_by_tag
@image_pull = Concurrent::Promise.execute { true }
end
def run_all(&block)
fail 'You must provide a block for run_all' unless block_given?
promises = @conf['images'].map do |id|
run_on_target(id, &block)
end
# wait for all tests to be finished
sleep(0.1) until promises.all?(&:fulfilled?)
# return resulting values
promises.map(&:value)
end
def run_on_target(name, &block)
pr = Concurrent::Promise.new {
begin
container = start_container(name)
res = block.call(name, container)
# special rescue block to handle not implemented error
rescue NotImplementedError => err
raise err.message
end
# always stop the container
stop_container(container)
res
}.execute
# failure handling
pr.rescue do |err|
msg = "\033[31;1m#{err.message}\033[0m"
puts msg
msg + "\n" + err.backtrace.join("\n")
end
end
def start_container(name, version = nil)
unless name.include?(':')
version ||= 'latest'
name = "#{name}:#{version}"
end
image = @images[name]
if image.nil?
puts "\033[35;1m--> pull docker images #{name} "\
"(this may take a while)\033[0m"
pull = @image_pull.then do
puts "... start pull image #{name}"
Docker::Image.create('fromImage' => name)
end
cur = pull.rescue { nil }
@image_pull = cur
sleep(0.1) until cur.fulfilled?
image = cur.value
unless image.nil?
puts "\033[35;1m--> pull docker images finished for #{name}\033[0m"
end
end
fail "Can't find nor pull docker image #{name}" if image.nil?
puts "--> start docker #{name}"
container = Docker::Container.create(
'Cmd' => %w{sleep 3600},
'Image' => image.id,
'OpenStdin' => true,
)
container.start
container
end
def stop_container(container)
puts "--> killrm docker #{container.id}"
container.kill
container.delete(force: true)
end
private
# get all docker image tags
def docker_images_by_tag
images = {}
Docker::Image.all.map do |img|
Array(img.info['RepoTags']).each do |tag|
images[tag] = img
end
end
images
end
end