class Baha::Builder

Constants

LOG

Attributes

config[R]

Public Class Methods

new(config) click to toggle source
# File lib/baha/builder.rb, line 24
def initialize(config)
  @config = case config
  when Baha::Config
    config
  else
    Baha::Config.load(config.to_s)
  end
end

Public Instance Methods

build!() click to toggle source
# File lib/baha/builder.rb, line 33
def build!
  LOG.info("Building Images")
  LOG.debug { "Config: #{@config.inspect}" }
  LOG.debug { "Initializing Docker" }
  @config.init_docker!

  @config.each_image do |image|
    build_log = Baha::Log.for_name("Builder [#{image.name}]")
    unless image.needs_update?
      build_log.info { "Skipped image #{image.name} - No update needed" }
      next
    end

    ## Prepare Workspace
    workspace = Pathname.new(@config.workspace) + image.name
    unless workspace.exist?
      build_log.debug { "Creating Workspace: #{workspace}" }
      FileUtils.mkdir_p workspace.to_s
    end

    run = false
    ## Image Run Config
    if image.run
      build_log.debug { "Image has RUN commands"}
      run = '.init.sh'
      File.open(workspace + run,'w') do |f|
        f.write("#!/bin/sh\n")
        f.write("set -xe\n")
        image.run.each do |cmd|
          build_log.debug { "Writing command: #{cmd}"}
          case cmd
          when String
            f.write("#{cmd}\n")
          when Array
            safe = Shellwords.shelljoin(cmd)
            f.write("#{safe}\n")
          end
        end
      end
    end

    ## Pre-Build tasks
    build_log.info { "Building #{image.name}" }
    if image.pre_build
      build_log.debug { "Preparing workspace for #{image.name}" }
      image.pre_build.each do |task|
        build_log.debug { "execute task: #{task.inspect}" }
        Baha::PreBuild::Module.execute(task.merge({ :config => @config, :image => image }))
      end
    end

    ## Build Image
    command = image.command
    if run
      command = ["/bin/sh", "#{image.bind}/#{run}"]
    end
    container_config = {
      'Image'       => image.parent_id,
      'Cmd'         => command,
      'Workingdir'  => image.bind
    }
    build_log.debug { "Creating container for #{image.name} => #{container_config.inspect}" }
    container = Docker::Container.create(container_config)
    build_log.debug { "Created container #{container.id} "}

    build_log.debug { "Running container for #{image.name}: #{command}" }
    container.start({
      'Binds' => "#{image.host_mount.expand_path}:#{image.bind}"
    })

    begin
      ## Stream logs
      container.streaming_logs({'stdout' => true, 'stderr' => true, 'follow' => true, 'timestamps' => false }) do |out,msg|
        case out
        when :stdout
          build_log.info { "++ #{msg.chomp}" }
        when :stderr
          build_log.warn { "++ #{msg.chomp}" }
        end
      end
      ## Wait for finish
      build_log.debug { "Waiting #{image.timeout} seconds for container #{container.id} to finish building" }
      status = container.wait(image.timeout)
    rescue Exception => e
      build_log.error { "Error building image #{image.name}" }
      build_log.error { e }
      build_log.info { "Removing container #{container.id}" }
      container.stop
      container.remove
      raise BuildError.new("Interrupted",image)
    end

    if status['StatusCode'] != 0
      build_log.error { "Error building image #{image.name}" }
      build_log.info { "Removing container #{container.id}" }
      container.remove
      raise BuildError.new(status,image)
    end

    ## Commit Image
    build_log.debug { "Committing Container #{container.id}" }
    build_log.debug { "Run Config: #{image.commit_config}" }
    build_image = container.commit({'run'=>image.commit_config})

    build_log.info { "New Image created: #{build_image.id}"}
    build_image = Docker::Image.get(build_image.id)

    image.tags.each do |tag|
      build_log.debug { "Tagging as #{tag}"}
      t = tag.split(/:/)
      build_image.tag(:repo => t[0], :tag => t[1])
    end

    ## Cleanup container
    container.remove
  end
end
inspect() click to toggle source
# File lib/baha/builder.rb, line 151
  def inspect
    <<-eos.gsub(/\n?\s{2,}/,'')
    #{self.class.name}<
      @config=#{@config.inspect}
    >
    eos
  end