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

Fixes #8409 - Pull docker image asynchronously #72

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/api/v2/containers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def show
param_group :container, :as => :create

def create
@container = Service::Containers.new.start_container!(set_wizard_state)
@container = ForemanDocker::Service::Containers.new.start_container!(set_wizard_state)
set_container_taxonomies
process_response @container.save
rescue ActiveModel::MassAssignmentSecurity::Error => e
Expand Down
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 @@ -52,7 +52,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 @@ -79,10 +79,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 @@ -27,22 +27,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(container_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(container_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 container_power_action(vm, authorizer = nil)
Expand Down Expand Up @@ -99,4 +105,20 @@ def processes(container)
def logs(container, opts = {})
ForemanDocker::Docker.get_container(container).logs(opts)
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
6 changes: 6 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 @@ -41,5 +42,10 @@ def in_fog

def self.humanize_class_name(_name = nil)
_("Docker/Container")
parametrize
end

def to_hash
parametrize
end
end
8 changes: 4 additions & 4 deletions app/models/foreman_docker/docker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def image(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 @@ -77,23 +77,23 @@ 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 }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was changed so that when no Cmd is specified, it uses the default. Otherwise a .merge will not replace a [] as it's not nil.

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 = {})
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, credentials, docker_connection)
end
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
50 changes: 50 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,50 @@
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
when StandardError
action_logger.error(event.message)
action_logger.debug(event.backtrace.join("\n "))
error!(event)
else
suspend do |suspended_action|
pull_docker_image(::Container.find(input[:container]), suspended_action)
end
end
end

def pull_docker_image(container, suspended_action)
Thread.new do
begin
container.compute_resource
.create_image(:fromImage => container.repository_pull_url)
suspended_action << :done
rescue => e
# encapsulate e as Foreman::Exception
suspended_action << e
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])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should start the container here

started = container.compute_resource.create_container(container.parametrize)
if started
container.update_attribute(:uuid, started.id)
started
else
[container.compute_resource.errors[:base]]
end
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
39 changes: 39 additions & 0 deletions app/models/foreman_docker/service/containers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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.

3 changes: 3 additions & 0 deletions app/views/api/v2/containers/create.json.rabl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object @container

extends "api/v2/containers/show"
Loading