Skip to content
This repository has been archived by the owner on Mar 16, 2021. It is now read-only.

Commit

Permalink
Fixes #8409 - Pull docker image asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
dLobatog committed Jan 28, 2015
1 parent e054355 commit 7989dee
Show file tree
Hide file tree
Showing 20 changed files with 269 additions and 147 deletions.
2 changes: 1 addition & 1 deletion app/controllers/containers/steps_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def set_form

def create_container
@state.send(:"create_#{step}", params[:"docker_container_wizard_states_#{step}"])
container = (service = Service::Containers.new).start_container!(@state)
container = (service = ForemanDocker::Service::Containers.new).start_container!(@state)
if container.present?
process_success(:object => container, :success_redirect => container_path(container))
else
Expand Down
9 changes: 4 additions & 5 deletions app/controllers/image_search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def use_hub?
end

def hub_image_exists?(terms)
@compute_resource.exist?(terms)
::Docker::Image.exist?(terms)
end

def hub_auto_complete_image_tags(terms)
Expand All @@ -61,10 +61,9 @@ def registry_auto_complete_image_tags(terms)
end

def registry_search_image(terms)
r = ::Service::RegistryApi.new(:url => @registry.url,
:user => @registry.username,
:password => @registry.password).search(terms)
r['results']
::Service::RegistryApi.new(:url => @registry.url,
:user => @registry.username,
:password => @registry.password).search(terms)['results']
end

def action_permission
Expand Down
48 changes: 35 additions & 13 deletions app/helpers/containers_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,28 @@ def container_link_hash(container, resource)
end
end

def container_title(container)
title = container.name.titleize
title += if container.uuid.present?
"- #{container.in_fog.name}"
else
_(" - provisioning ") + image_tag('spinner.gif')
end
title(container.name.titleize, title.html_safe)
end

def container_title_actions(container)
@compute_resource = container.compute_resource
container_title(container)
title_actions(
button_group(
link_to(_('Commit'), '#commit-modal', :'data-toggle' => 'modal')
),
button_group(vm_power_action(container.in_fog)),
button_group(
display_delete_if_authorized(
hash_for_container_path(:id => container.id)
.merge(:auth_object => container,
:auth_action => 'destroy',
:authorizer => authorizer),
:confirm => _("Delete %s?") % container.name)
)
)
button_group(link_to(_('Commit'), '#commit-modal', :'data-toggle' => 'modal')),
button_group(vm_power_action(container.in_fog)),
button_group(display_delete_if_authorized(
hash_for_container_path(:id => container.id).merge(:auth_object => container,
:auth_action => 'destroy',
:authorizer => authorizer),
:confirm => _("Delete %s?") % container.name))
) if container.uuid.present?
end

def auto_complete_docker_search(name, val, options = {})
Expand All @@ -63,4 +69,20 @@ def hub_url(image)
"https://registry.hub.docker.com/u/#{image['name']}"
end
end

def fog_property(container)
return 'Not available' unless container.uuid.present?
yield
end

def pair_attributes_table(attributes)
table = "<table id='environment_variables' class='table table-bordered'
style='table-layout:fixed; word-wrap: break-word'>"
attributes.each do |pair|
pair = pair.split("=")
table += "<tr><td><b> #{pair.first} </b></td><td><i> #{pair.second} </i></td></tr>"
end
table += '</table>'
table.html_safe
end
end
2 changes: 1 addition & 1 deletion app/models/concerns/fog_extensions/fogdocker/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def command
end

def poweroff
service.vm_action(:id => id, :action => :kill)
service.container_action(:id => id, :action => :kill)
end

def reset
Expand Down
5 changes: 5 additions & 0 deletions app/models/container.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Container < ActiveRecord::Base
include Authorizable
include Taxonomix
include ForemanTasks::Concerns::ActionSubject

belongs_to :compute_resource
belongs_to :registry, :class_name => "DockerRegistry", :foreign_key => :registry_id
Expand Down Expand Up @@ -35,4 +36,8 @@ def parametrize
def in_fog
@fog_container ||= compute_resource.vms.get(uuid)
end

def to_hash
parametrize
end
end
20 changes: 6 additions & 14 deletions app/models/foreman_docker/docker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,12 @@ def tags_for_local_image(image)
end
end

def exist?(name)
::Docker::Image.exist?(name)
end

def image(id)
client.image_get(id)
end

def tags(image_name)
if exist?(image_name)
if ::Docker::Image.exist?(image_name)
tags_for_local_image(local_images(image_name).first)
else
# If image is not found in the compute resource, get the tags from the Hub
Expand All @@ -73,23 +69,19 @@ def provider_friendly_name
end

def create_container(args = {})
options = vm_instance_defaults.merge(args)
options = vm_instance_defaults.merge(args) { |_, default, new| new.empty? ? default : new }
logger.debug("Creating container with the following options: #{options.inspect}")
docker_command do
::Docker::Container.create(options)
end
docker_command { ::Docker::Container.create(options) }
end

def create_image(args = {})
return true if ::Docker::Image.exist?(args[:fromImage])
logger.debug("Creating docker image with the following options: #{args.inspect}")
docker_command do
::Docker::Image.create(args)
end
docker_command { ::Docker::Image.create(args) }
end

def vm_instance_defaults
ActiveSupport::HashWithIndifferentAccess.new('name' => "foreman_#{Time.now.to_i}",
'Cmd' => ['/bin/bash'])
{ 'name' => "foreman_#{Time.now.to_i}", 'Cmd' => ['/bin/bash'] }
end

def console(uuid)
Expand Down
26 changes: 26 additions & 0 deletions app/models/foreman_docker/service/actions/container/provision.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module ForemanDocker
module Service
module Actions
module Container
class Provision < ::Actions::EntryAction
def plan(container)
action_subject(container)

sequence do
plan_action(Container::Pull, container)
plan_action(Container::Start, container)
end
end

def humanized_name
_('Provision container')
end

def finalize
action_logger.info('Finished provisioning of Docker container')
end
end
end
end
end
end
44 changes: 44 additions & 0 deletions app/models/foreman_docker/service/actions/container/pull.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module ForemanDocker
module Service
module Actions
module Container
class Pull < ::Actions::EntryAction
def plan(container)
action_subject(container)
plan_self(:container => container.id)
end

def run(event = nil)
case event
when :done # do nothing and move to next step
else
suspend do |suspended_action|
Thread.new do
begin
container = ::Container.find(input[:container])
container.compute_resource
.create_image(:fromImage => container.repository_pull_url)
suspended_action << :done
rescue => e
action_logger.error(e.message)
action_logger.debug(e.backtrace.join("\n "))
error!(e)
end
end
end
end
end

def humanized_name
_('Pull')
end

def finalize
container = ::Container.find(input[:container])
action_logger.info("[Docker] Finished pulling image #{container.repository_pull_url}")
end
end
end
end
end
end
34 changes: 34 additions & 0 deletions app/models/foreman_docker/service/actions/container/start.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module ForemanDocker
module Service
module Actions
module Container
class Start < ::Actions::EntryAction
def plan(container)
action_subject(container)
plan_self(:container => container.id)
end

def run
container = ::Container.find(input[:container])
started = container.compute_resource.create_container(container.parametrize)
if started
container.update_attribute(:uuid, started.id)
else
errors << container.compute_resource.errors[:base]
end
started
end

def humanized_name
_('Start')
end

def finalize
container = ::Container.find(input[:container])
action_logger.info("[Docker] container #{container.name} successfully started")
end
end
end
end
end
end
38 changes: 38 additions & 0 deletions app/models/foreman_docker/service/containers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module ForemanDocker
module Service
class Containers
def errors
@errors ||= []
end

def start_container!(wizard_state)
container = ActiveRecord::Base.transaction do
container = Container.new(wizard_state.container_attributes) do |r|
# eagerly load environment variables
state = DockerContainerWizardState.includes(:environment => [:environment_variables])
.find(wizard_state.id)
state.environment_variables.each do |environment_variable|
r.environment_variables.build :name => environment_variable.name,
:value => environment_variable.value,
:priority => environment_variable.priority
end
end
Taxonomy.enabled_taxonomies.each do |taxonomy|
container.send(:"#{taxonomy}=", wizard_state.preliminary.send(:"#{taxonomy}"))
end
container.save!
container
end

destroy_wizard_state(wizard_state)
ForemanTasks.async_task(Service::Actions::Container::Provision, container)
container
end

def destroy_wizard_state(wizard_state)
wizard_state.destroy
DockerContainerWizardState.destroy_all(["updated_at < ?", (Time.now - 24.hours)])
end
end
end
end
50 changes: 0 additions & 50 deletions app/models/service/containers.rb

This file was deleted.

4 changes: 2 additions & 2 deletions app/views/containers/_list.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
<td class="ellipsis text-center"><%= link_to_container(container, resource) %></td>
<td class="hidden-tablet hidden-xs text-center">
<span <%= vm_power_class(container.ready?) %>><%= vm_state(container) %></span></td>
<td class="hidden-tablet hidden-xs text-center"><%= trunc(container.image_friendly_name) %></td>
<td class="hidden-tablet hidden-xs text-center"><%= trunc(container.command) %></td>
<td class="hidden-tablet hidden-xs text-center"><%= trunc_with_tooltip(container.image_friendly_name) %></td>
<td class="hidden-tablet hidden-xs text-center"><%= trunc_with_tooltip(container.command) %></td>
<td class="hidden-tablet hidden-xs text-center">
<span class="glyphicon glyphicon-time"></span> <%= container.ready? ? time_ago_in_words(container.started_at) : "N/A" %>
</td>
Expand Down
Loading

0 comments on commit 7989dee

Please sign in to comment.