app/models/foreman_docker/docker.rb
require 'uri'
module ForemanDocker
class Docker < ::ComputeResource
validates :url, :format => { :with => URI.regexp }, :presence => true
validates :email, :format => { :with => /.+@.+\..+/i }, :allow_blank => true
def self.model_name
ComputeResource.model_name
end
def self.get_container(container)
conn = container.compute_resource.docker_connection
::Docker::Container.get(container.uuid, {}, conn)
end
def capabilities
[]
end
def supports_update?
false
end
def provided_attributes
super.merge(:mac => :mac)
end
def max_memory
16 * 1024 * 1024 * 1024
end
def max_cpu_count
::Docker.info['NCPU'] || 1
end
def available_images
::Docker::Image.all({}, docker_connection)
end
def local_images(filter = '')
::Docker::Image.all({ 'filter' => filter }, docker_connection)
end
def tags_for_local_image(image, tag = nil)
result = image.info['RepoTags'].map do |image_tag|
_, tag = image_tag.split(':')
tag
end
result = filter_tags(result, tag) if tag
result
end
def exist?(name)
::Docker::Image.exist?(name, {}, docker_connection)
end
def image(id)
::Docker::Image.get(id, {}, docker_connection)
end
def tags(image_name)
if exist?(image_name)
tags_for_local_image(image(image_name))
else
Service::RegistryApi.docker_hub.tags(image_name).map { |tag| tag['name'] }
end
end
def search(term = '')
client.images.image_search(:term => term)
end
def provider_friendly_name
'Docker'
end
def create_container(args = {})
options = vm_instance_defaults.merge(args)
logger.debug("Creating container with the following options: #{options.inspect}")
docker_command do
::Docker::Container.create(options, docker_connection)
end
end
def create_image(args = {})
logger.debug("Creating docker image with the following options: #{args.inspect}")
docker_command do
::Docker::Image.create(args, credentials, docker_connection)
end
end
def vm_instance_defaults
ActiveSupport::HashWithIndifferentAccess.new('name' => "foreman_#{Time.now.to_i}",
'Cmd' => ['/bin/bash'])
end
def console(uuid)
test_connection
container = ::Docker::Container.get(uuid, {}, docker_connection)
{
:name => container.info['Name'],
'timestamp' => Time.now.utc,
'output' => container.logs(:stdout => true, :tail => 100)
}
end
def api_version
::Docker.version(docker_connection)
end
def authenticate!
::Docker.authenticate!(credentials, docker_connection)
end
def test_connection(options = {})
super
api_version
credentials.empty? ? true : authenticate!
# This should only rescue Fog::Errors, but Fog returns all kinds of errors...
rescue => e
errors[:base] << e.message
false
end
def docker_connection
@docker_connection ||= ::Docker::Connection.new(url, credentials)
end
protected
def filter_tags(result, query)
result.select do |tag_name|
tag_name['name'] =~ /^#{query}/
end
end
def docker_command
yield
rescue Excon::Errors::Error, ::Docker::Error::DockerError => e
logger.debug "Fog error: #{e.message}\n " + e.backtrace.join("\n ")
errors.add(:base,
_("Error creating communicating with Docker. Check the Foreman logs: %s") %
e.message.to_s)
false
end
def bootstrap(args)
client.servers.bootstrap vm_instance_defaults.merge(args.to_hash)
rescue Fog::Errors::Error => e
errors.add(:base, e.to_s)
false
end
def client
opts = {
:provider => 'fogdocker',
:docker_url => url
}
opts[:docker_username] = user if user.present?
opts[:docker_password] = password if password.present?
opts[:docker_email] = email if email.present?
@client ||= ::Fog::Compute.new(opts)
end
def credentials
@credentials ||= {}.tap do |options|
options[:username] = user if user.present?
options[:password] = password if password.present?
options[:email] = email if email.present?
end
end
end
end