class EzPaaS::Helpers::ContainerManager

Attributes

connection[R]
slug_dir[R]

Public Class Methods

new() click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 18
def initialize
  ensure_paths
end

Public Instance Methods

create_slug(src_tar_stream, emitter = nil) click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 22
def create_slug(src_tar_stream, emitter = nil)

  temp_tar = Tempfile.new('ezpaas') # Temporary place to copy the slug tarball

  emitter.emit :message, '-----> Creating slug compilation container' if emitter
  container = Docker::Container.create({'Image' => 'deis/slugbuilder', 'OpenStdin' => true, 'StdinOnce' => true}, connection)

  begin
    # Start the container
    emitter.emit :message, '-----> Starting slug compilation container' if emitter
    container.start

    # Redirect container output to HTTP stream
    container.attach(stdin: src_tar_stream) do |_fd, chunk|
      emitter.emit :message, chunk if emitter
    end

    # Wait for container to finish compiling the slug
    container.wait

    # Kill the container
    emitter.emit :message, '-----> Stopping slug compilation container' if emitter
    begin
      container.stop
    end

    # Copy the tarred slug out of the container
    emitter.emit :message, "-----> Temporarily copying slug from container to #{temp_tar.path}" if emitter
    container.copy('/tmp/slug.tgz') { |chunk| temp_tar.write(chunk) }

    temp_tar.rewind # rewind the temp file for immediate reading

    # Decompress the tarred slug to our final destination
    slug_name = SecureRandom.uuid
    slug_destination = slug_path(slug_name)
    emitter.emit :message, "-----> Untarring slug to #{slug_destination}" if emitter
    tar_extract = Gem::Package::TarReader.new(temp_tar)
    slug_entry = tar_extract.find { |e| e.full_name == 'slug.tgz' }
    File.open(slug_destination, 'wb') do |file|
      File.ez_cp(slug_entry, file)
    end
    temp_tar.close
  rescue Exception => ex
    raise
  else
    slug_name
    ensure
      emitter.emit :message, "-----> Removing container" if emitter
      # Try to remove the container
      begin
        container.remove
      rescue
        raise
      end
      emitter.emit :message, "-----> Deleting temporary files" if emitter
      temp_tar.close
      temp_tar.unlink
    end

  end
deploy_app(name, slug, config, emitter = nil) click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 83
def deploy_app(name, slug, config, emitter = nil)

  emitter.emit :message, "-----> Creating temporary slug container to snapshot" if emitter

  # Load the slug into a temporary container to produce an image
  slug_labels = {
    'com.tendigi.appname' => name,
  }

  slug_file = File.open(slug_path(slug), 'rb')
  slug_container = Docker::Container.create({'Image' => 'deis/slugrunner', 'OpenStdin' => true, 'StdinOnce' => true, 'Labels' => slug_labels}, connection)
  slug_container.start
  slug_container.attach(stdin: slug_file) do |_fd, chunk|
    # puts chunk
  end

  slug_image_name = "ezpass/#{name}"

  emitter.emit :message, "-----> Imaging container #{slug_container.id}" if emitter
  slug_image = slug_container.commit(repo: slug_image_name, 'Labels' => slug_labels)
  emitter.emit :message, "-----> Created slug image #{slug_image.id}" if emitter

  slug_container.remove(force: true)
  emitter.emit :message, "-----> Removing temporary slug container #{slug_container.id}" if emitter

  emitter.emit :message, "-----> Starting deployment..." if emitter

  # Start up instances using that image
  config.each do |process, count|

    # iterate over the desired number of instances
    for i in 0 ... count
      container_name = "#{name}-#{process}-#{i}"
      labels = {
        'com.tendigi.appname' => name,
        'com.tendigi.instance' => container_name,
        'com.tendigi.slug' => slug,
        'com.tendigi.process' => process
      }
      container = slug_image.run("start #{process}", { name: container_name, 'Labels' => labels, 'PublishAllPorts' => true })
      emitter.emit :message, "-----> Deployed container #{i + 1} for process type `#{process}`: #{container.id}" if emitter
    end
  end

end
http_destinations(name) click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 151
def http_destinations(name)
  containers = Docker::Container.all(filters: { label: [ "com.tendigi.appname=#{name}", "com.tendigi.process=web"]  }.to_json)

  ports = {}

  for container in containers
    for port_info in (container.info['Ports'] || [])
      if port_info['PrivatePort'] == 5000
        ports[container.id] = port_info['PublicPort']
      end
    end
  end

  ports
end
pull_images() click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 179
def pull_images

  images = [
    'deis/slugbuilder',
    'deis/slugrunner'
  ]

  puts

  images.each do |name|

        pastel = Pastel.new
        puts 'Downloading latest image: ' + pastel.blue(name)

    Docker::Image.create({'fromImage' => name, 'tag' => 'latest'}, connection) do |chunk|
      fragments = chunk.split "\r\n"
      fragments.each do |fragment|
        data = JSON.parse(fragment)
        if id = data['id']
                # puts "#{id}: #{data['status']}" #off for now
        else
                puts pastel.green(data['status'].rstrip)
        end
        
      end
    end

    puts
  end

end
read_procfile(slug_name) click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 167
def read_procfile(slug_name)
  tar_extract = Gem::Package::TarReader.new(Zlib::GzipReader.open(slug_path(slug_name)))
  tar_extract.rewind # The extract has to be rewinded after every iteration
  tar_extract.each do |entry|
    if entry.full_name == './Procfile' && entry.file?
      return YAML.load(entry.read)
    end
  end
ensure
  tar_extract.close
end
undeploy_app(name, emitter = nil) click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 129
def undeploy_app(name, emitter = nil)

  emitter.emit :message, "-----> Un-deploying #{name}" if emitter

  containers = Docker::Container.all(all: true, filters: { label: [ "com.tendigi.appname=#{name}"  ]  }.to_json)

  containers.each do |c|
    emitter.emit :message, "-----> Removing container #{c.id}" if emitter
    c.remove(force: true)
  end

  emitter.emit :message, "-----> Deleting slug images for #{name}" if emitter

  images = Docker::Image.all(all: true, filters: { label: [ "com.tendigi.appname=#{name}"  ]  }.to_json)

  images.each do |i|
    emitter.emit :message, "-----> Removing image #{i.id}" if emitter
    i.remove
  end

end

Private Instance Methods

ensure_paths() click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 221
def ensure_paths
  @slug_dir ||= File.join(EzPaaS::Helpers::Config.data_dir, 'slugs')
  FileUtils.mkdir_p @slug_dir
end
slug_path(slug_name) click to toggle source
# File lib/ezpaas/helpers/container_manager.rb, line 226
def slug_path(slug_name)
  File.join(slug_dir, slug_name + '.tgz')
end