From efe3a69748103ef5b74582397f25bd395c8478b0 Mon Sep 17 00:00:00 2001 From: Daniel Lobato Date: Thu, 22 Jan 2015 10:23:33 +0100 Subject: [PATCH] Fixes #8409 - Pull docker image asynchronously --- .../api/v2/containers_controller.rb | 2 +- .../containers/steps_controller.rb | 2 +- app/controllers/image_search_controller.rb | 9 +- app/helpers/containers_helper.rb | 48 +++++-- .../fog_extensions/fogdocker/server.rb | 2 +- app/models/container.rb | 6 + app/models/foreman_docker/docker.rb | 8 +- .../service/actions/container/provision.rb | 26 ++++ .../service/actions/container/pull.rb | 50 ++++++++ .../service/actions/container/start.rb | 34 +++++ .../foreman_docker/service/containers.rb | 39 ++++++ .../service/registry_api.rb | 0 app/models/service/containers.rb | 50 -------- app/views/api/v2/containers/create.json.rabl | 3 + app/views/containers/show.html.erb | 117 ++++++++++-------- foreman_docker.gemspec | 2 + lib/foreman_docker/engine.rb | 5 + test/actions/provision_test.rb | 58 +++++++++ .../api/v2/containers_controller_test.rb | 26 ++-- .../containers_steps_controller_test.rb | 4 +- .../image_search_controller_test.rb | 39 +++--- test/test_plugin_helper.rb | 6 + test/units/containers_service_test.rb | 12 +- 23 files changed, 375 insertions(+), 173 deletions(-) create mode 100644 app/models/foreman_docker/service/actions/container/provision.rb create mode 100644 app/models/foreman_docker/service/actions/container/pull.rb create mode 100644 app/models/foreman_docker/service/actions/container/start.rb create mode 100644 app/models/foreman_docker/service/containers.rb rename app/models/{ => foreman_docker}/service/registry_api.rb (100%) delete mode 100644 app/models/service/containers.rb create mode 100644 app/views/api/v2/containers/create.json.rabl create mode 100644 test/actions/provision_test.rb diff --git a/app/controllers/api/v2/containers_controller.rb b/app/controllers/api/v2/containers_controller.rb index 50c5a47..3262f41 100644 --- a/app/controllers/api/v2/containers_controller.rb +++ b/app/controllers/api/v2/containers_controller.rb @@ -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 diff --git a/app/controllers/containers/steps_controller.rb b/app/controllers/containers/steps_controller.rb index 00c62f9..8c4f8cd 100644 --- a/app/controllers/containers/steps_controller.rb +++ b/app/controllers/containers/steps_controller.rb @@ -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 diff --git a/app/controllers/image_search_controller.rb b/app/controllers/image_search_controller.rb index 57f2254..92d28ef 100644 --- a/app/controllers/image_search_controller.rb +++ b/app/controllers/image_search_controller.rb @@ -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) @@ -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 diff --git a/app/helpers/containers_helper.rb b/app/helpers/containers_helper.rb index c67b711..c02fc6d 100644 --- a/app/helpers/containers_helper.rb +++ b/app/helpers/containers_helper.rb @@ -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) @@ -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 = "" + attributes.each do |pair| + pair = pair.split("=") + table += "" + end + table += '
#{pair.first} #{pair.second}
' + table.html_safe + end end diff --git a/app/models/concerns/fog_extensions/fogdocker/server.rb b/app/models/concerns/fog_extensions/fogdocker/server.rb index 5ca3d4a..81331d8 100644 --- a/app/models/concerns/fog_extensions/fogdocker/server.rb +++ b/app/models/concerns/fog_extensions/fogdocker/server.rb @@ -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 diff --git a/app/models/container.rb b/app/models/container.rb index 3b31e5f..0c0d1f3 100644 --- a/app/models/container.rb +++ b/app/models/container.rb @@ -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 @@ -41,5 +42,10 @@ def in_fog def self.humanize_class_name(_name = nil) _("Docker/Container") + parametrize + end + + def to_hash + parametrize end end diff --git a/app/models/foreman_docker/docker.rb b/app/models/foreman_docker/docker.rb index 6fe5d80..5867e53 100644 --- a/app/models/foreman_docker/docker.rb +++ b/app/models/foreman_docker/docker.rb @@ -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 @@ -77,7 +77,7 @@ 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, docker_connection) @@ -85,6 +85,7 @@ def create_container(args = {}) 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) @@ -92,8 +93,7 @@ def create_image(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) diff --git a/app/models/foreman_docker/service/actions/container/provision.rb b/app/models/foreman_docker/service/actions/container/provision.rb new file mode 100644 index 0000000..4f4d198 --- /dev/null +++ b/app/models/foreman_docker/service/actions/container/provision.rb @@ -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 diff --git a/app/models/foreman_docker/service/actions/container/pull.rb b/app/models/foreman_docker/service/actions/container/pull.rb new file mode 100644 index 0000000..71973bb --- /dev/null +++ b/app/models/foreman_docker/service/actions/container/pull.rb @@ -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 diff --git a/app/models/foreman_docker/service/actions/container/start.rb b/app/models/foreman_docker/service/actions/container/start.rb new file mode 100644 index 0000000..68d56f1 --- /dev/null +++ b/app/models/foreman_docker/service/actions/container/start.rb @@ -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) + 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 diff --git a/app/models/foreman_docker/service/containers.rb b/app/models/foreman_docker/service/containers.rb new file mode 100644 index 0000000..ea26ca6 --- /dev/null +++ b/app/models/foreman_docker/service/containers.rb @@ -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 diff --git a/app/models/service/registry_api.rb b/app/models/foreman_docker/service/registry_api.rb similarity index 100% rename from app/models/service/registry_api.rb rename to app/models/foreman_docker/service/registry_api.rb diff --git a/app/models/service/containers.rb b/app/models/service/containers.rb deleted file mode 100644 index 0b336c9..0000000 --- a/app/models/service/containers.rb +++ /dev/null @@ -1,50 +0,0 @@ -module Service - class Containers - def errors - @errors ||= [] - end - - def start_container!(wizard_state) - 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 - - fail ActiveRecord::Rollback unless pull_image(container) && start_container(container) - - container.save! - destroy_wizard_state(wizard_state) - container - end - end - - def pull_image(container) - container.compute_resource.create_image(:fromImage => container.repository_pull_url) - end - - def start_container(container) - started = container.compute_resource.create_container(container.parametrize) - if started - container.uuid = started.id - else - errors << container.compute_resource.errors[:base] - end - started - end - - def destroy_wizard_state(wizard_state) - wizard_state.destroy - DockerContainerWizardState.destroy_all(["updated_at < ?", (Time.now - 24.hours)]) - end - end -end diff --git a/app/views/api/v2/containers/create.json.rabl b/app/views/api/v2/containers/create.json.rabl new file mode 100644 index 0000000..639f1b1 --- /dev/null +++ b/app/views/api/v2/containers/create.json.rabl @@ -0,0 +1,3 @@ +object @container + +extends "api/v2/containers/show" diff --git a/app/views/containers/show.html.erb b/app/views/containers/show.html.erb index 2200abf..31d7268 100644 --- a/app/views/containers/show.html.erb +++ b/app/views/containers/show.html.erb @@ -1,4 +1,3 @@ -<% title "#{@container.name.titleize} - #{@container.in_fog.name}" %> <%= stylesheet 'foreman_docker/terminal' %> <%= container_title_actions(@container) %>
@@ -6,10 +5,10 @@
- + - + @@ -21,40 +20,38 @@ - + - + - + - + - + - + <% Taxonomy.enabled_taxonomies.each do |taxonomy| %> @@ -74,50 +71,60 @@
- <% if @container.in_fog.ready? %> - -
-
-
- <% processes(@container).each do |process| %> -
-

- -index' - class='accordion-toggle' - data-toggle='collapse' - data-parent='#accordion'> - <%= process['CMD'] %> -
- <%= process['UID'] %> -

+ <% if @container.uuid.present? %> + <% if @container.in_fog.ready? %> + +
+
+ <% processes = Docker::Container.get(@container.uuid).top %> +
+ <% processes(@container).each do |process| %> + +
-index' class='collapse accordion-body'> +
<%= JSON.pretty_generate(process) %>
+
+ <% end %> +
-
-index' class='collapse accordion-body'> -
<%= JSON.pretty_generate(process) %>
+
+

+              <%= logs(@container, :stdout => true, :tail => 100) %>
+            
- <% end %>
-
-
-

-          <%= logs(@container, :stdout => true, :tail => 100) %>
-        
-
-
+ <% else %> +
+

<%= _("Notice") %> +


+ <%= _("Your container is stopped.") %>

+

<%= _("Please turn on your container to see processes running, logs, and more.") %>

+
+ <% end %> <% else %>

<%= _("Notice") %>


- <%= _("Your container is stopped.") %>

-

<%= _("Please turn on your container to see processes running, logs, and more.") %>

+ <%= _("Your container is being provisioned.") %>

+

<%= _("Please wait until your image is pulled to the Docker host. You can track progress at Monitor > Tasks.") %>

<% end %>
diff --git a/foreman_docker.gemspec b/foreman_docker.gemspec index cfebdd2..7d7cbdf 100644 --- a/foreman_docker.gemspec +++ b/foreman_docker.gemspec @@ -20,4 +20,6 @@ Gem::Specification.new do |s| s.add_dependency 'docker-api', '1.17' s.add_dependency 'wicked', '~> 1.1' + s.add_dependency 'foreman-tasks', '~> 0.6.0' + s.add_dependency 'minitest-reporters' end diff --git a/lib/foreman_docker/engine.rb b/lib/foreman_docker/engine.rb index 58fbf83..547eacc 100644 --- a/lib/foreman_docker/engine.rb +++ b/lib/foreman_docker/engine.rb @@ -4,6 +4,7 @@ require 'fog/fogdocker' require 'wicked' require 'docker' +require 'foreman-tasks' module ForemanDocker # Inherit from the Rails module of the parent app (Foreman), not the plugin. @@ -14,6 +15,10 @@ class Engine < ::Rails::Engine config.autoload_paths += Dir["#{config.root}/app/controllers/concerns"] config.autoload_paths += Dir["#{config.root}/app/models/concerns"] + initializer "foreman_docker.require_dynflow", :before => "foreman_tasks.initialize_dynflow" do + ::ForemanTasks.dynflow.require! + end + initializer 'foreman_docker.load_app_instance_data' do |app| app.config.paths['db/migrate'] += ForemanDocker::Engine.paths['db/migrate'].existent end diff --git a/test/actions/provision_test.rb b/test/actions/provision_test.rb new file mode 100644 index 0000000..bb2329c --- /dev/null +++ b/test/actions/provision_test.rb @@ -0,0 +1,58 @@ +require 'test_plugin_helper' + +module ForemanDocker + module Service + module Actions + module Container + class TestBase < ActiveSupport::TestCase + include Dynflow::Testing + include FactoryGirl::Syntax::Methods + + let(:container) { FactoryGirl.create(:container) } + end + + class ProvisionTest < TestBase + let(:action_class) { ForemanDocker::Service::Actions::Container::Provision } + + it 'plans pull and start' do + action = create_action(action_class) + action.stubs(:action_subject).with(container) + plan_action(action, container) + %w(Pull Start).each do |container_action| + container_action = "ForemanDocker::Service::Actions::Container::#{container_action}" + assert_action_planed_with(action, container_action.constantize, container) + end + end + end + + class PullTest < TestBase + let(:action_class) { ForemanDocker::Service::Actions::Container::Pull } + + it 'pulls the container image' do + ::Container.expects(:find).returns(container) + container.compute_resource.expects(:create_image).returns(true) + action = create_action(action_class) + action.stubs(:action_subject).with(container) + plan_action(action, container) + run_action(action) { |dynflow_action| dynflow_action.expects(:pull_docker_image) } + action.pull_docker_image(container, []).join + end + end + + class StartTest < TestBase + let(:action_class) { ForemanDocker::Service::Actions::Container::Start } + + it 'starts the container' do + ::Container.expects(:find).returns(container) + container.compute_resource.expects(:create_container).returns(container) + action = create_action(action_class) + action.stubs(:action_subject).with(container) + plan_action(action, container) + assert_run_phase(action) + run_action(action) + end + end + end + end + end +end diff --git a/test/functionals/api/v2/containers_controller_test.rb b/test/functionals/api/v2/containers_controller_test.rb index a505f66..d91e75b 100644 --- a/test/functionals/api/v2/containers_controller_test.rb +++ b/test/functionals/api/v2/containers_controller_test.rb @@ -74,23 +74,23 @@ class ContainersControllerTest < ActionController::TestCase tag = "7" name = "foo" registry_uri = URI.parse(@registry.url) - Service::Containers.any_instance.expects(:pull_image).returns(true) - Service::Containers.any_instance - .expects(:start_container).returns(true).with do |container| - container.must_be_kind_of(Container) - container.repository_name.must_equal(repository_name) - container.tag.must_equal(tag) - container.compute_resource_id.must_equal(@compute_resource.id) - container.name.must_equal(name) - container.repository_pull_url.must_include(registry_uri.host) - container.repository_pull_url.must_include("#{repository_name}:#{tag}") + container_mock = mock('container') + container_mock.expects(:save).returns(true) + ForemanDocker::Service::Containers.any_instance + .expects(:start_container!).returns(container_mock).with do |wizard_state| + wizard_state.must_be_kind_of(DockerContainerWizardState) + container_attributes = wizard_state.container_attributes + container_attributes[:repository_name].must_equal(repository_name) + container_attributes[:tag].must_equal(tag) + container_attributes[:compute_resource_id].must_equal(@compute_resource.id) + container_attributes[:name].must_equal(name) end post :create, :container => { :compute_resource_id => @compute_resource.id, :name => name, :registry_id => @registry.id, :repository_name => repository_name, :tag => tag } - assert_response :created + assert_response :success end test 'creates a katello container with correct params' do @@ -102,7 +102,7 @@ class ContainersControllerTest < ActionController::TestCase tag = "7" name = "foo" capsule_id = "10000" - Service::Containers.any_instance.expects(:start_container!) + ForemanDocker::Service::Containers.any_instance.expects(:start_container!) .returns(@container).with do |wizard_state| wizard_state.must_be_kind_of(DockerContainerWizardState) container_attributes = wizard_state.container_attributes @@ -117,7 +117,7 @@ class ContainersControllerTest < ActionController::TestCase :capsule_id => capsule_id, :repository_name => repository_name, :tag => tag } - assert_response :created + assert_response :success end end end diff --git a/test/functionals/containers_steps_controller_test.rb b/test/functionals/containers_steps_controller_test.rb index ef9ce2b..c8ae231 100644 --- a/test/functionals/containers_steps_controller_test.rb +++ b/test/functionals/containers_steps_controller_test.rb @@ -8,8 +8,8 @@ class StepsControllerTest < ActionController::TestCase test 'wizard finishes with a redirect to the managed container' do state = DockerContainerWizardState.create! - Service::Containers.any_instance.expects(:start_container!).with(equals(state)) - .returns(@container) + ForemanDocker::Service::Containers.any_instance.expects(:start_container!) + .with(equals(state)).returns(@container) put :update, { :wizard_state_id => state.id, :id => :environment, :docker_container_wizard_states_environment => { :tty => false } }, diff --git a/test/functionals/image_search_controller_test.rb b/test/functionals/image_search_controller_test.rb index c062ed9..873748a 100644 --- a/test/functionals/image_search_controller_test.rb +++ b/test/functionals/image_search_controller_test.rb @@ -5,29 +5,28 @@ class ImageSearchControllerTest < ActionController::TestCase @container = FactoryGirl.create(:docker_cr) end - [Docker::Error::DockerError, Excon::Errors::Error, Errno::ECONNREFUSED].each do |error| - test 'auto_complete_repository_name catches exceptions on network errors' do - ForemanDocker::Docker.any_instance.expects(:exist?).raises(error) - get :auto_complete_repository_name, { :search => "test", :id => @container.id }, - set_session_user - assert_response_is_expected - end + context 'network errors' do + [Docker::Error::DockerError, Excon::Errors::Error, Errno::ECONNREFUSED].each do |error| + test 'auto_complete_repository_name catches exceptions on network errors' do + ::Docker::Image.expects(:exist?).raises(error) + get :auto_complete_repository_name, { :search => "test", :id => @container.id }, + set_session_user + end - test 'auto_complete_image_tag catch exceptions on network errors' do - ForemanDocker::Docker.any_instance.expects(:tags).raises(error) - get :auto_complete_image_tag, { :search => "test", :id => @container.id }, set_session_user - assert_response_is_expected - end + test 'auto_complete_image_tag catch exceptions on network errors' do + ForemanDocker::Docker.any_instance.expects(:tags).raises(error) + get :auto_complete_image_tag, { :search => "test", :id => @container.id }, set_session_user + end - test 'search_repository catch exceptions on network errors' do - ForemanDocker::Docker.any_instance.expects(:search).raises(error) - get :search_repository, { :search => "test", :id => @container.id }, set_session_user - assert_response_is_expected + test 'search_repository catch exceptions on network errors' do + ForemanDocker::Docker.any_instance.expects(:search).raises(error) + get :search_repository, { :search => "test", :id => @container.id }, set_session_user + end end - end - def assert_response_is_expected - assert_response :error - assert response.body.include?('An error occured during repository search:') + teardown do + assert_response :error + assert response.body.include?('An error occured during repository search:') + end end end diff --git a/test/test_plugin_helper.rb b/test/test_plugin_helper.rb index 84a9b0e..6888ba6 100644 --- a/test/test_plugin_helper.rb +++ b/test/test_plugin_helper.rb @@ -1,5 +1,7 @@ # This calls the main test_helper in Foreman-core require 'test_helper' +require "minitest/reporters" +Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(:slow_count => 5)] def assert_row_button(index_path, link_text, button_text, dropdown = false) visit index_path @@ -9,6 +11,10 @@ def assert_row_button(index_path, link_text, button_text, dropdown = false) end end +require 'dynflow/testing' +Mocha::Mock.send :include, Dynflow::Testing::Mimic +Dynflow::Testing.logger_adapter.level = 1 + # Add plugin to FactoryGirl's paths FactoryGirl.definition_file_paths << File.join(File.dirname(__FILE__), 'factories') FactoryGirl.reload diff --git a/test/units/containers_service_test.rb b/test/units/containers_service_test.rb index 39a416e..6170a87 100644 --- a/test/units/containers_service_test.rb +++ b/test/units/containers_service_test.rb @@ -12,14 +12,10 @@ class ContainersServiceTest < ActiveSupport::TestCase end end - test 'removes current state after successful container creation' do - ret = OpenStruct.new(:id => 1) - ForemanDocker::Docker.any_instance.expects(:create_image).returns(ret).with do |subject| - subject.must_equal(:fromImage => "test:test") - end - ForemanDocker::Docker.any_instance.expects(:create_container) - .returns(OpenStruct.new(:uuid => 1)) - Service::Containers.new.start_container!(@state) + test 'removes current state after container creation task is scheduled' do + ForemanTasks.expects(:async_task).returns(true) + assert_equal DockerContainerWizardState.where(:id => @state.id).count, 1 + ForemanDocker::Service::Containers.new.start_container!(@state) assert_equal DockerContainerWizardState.where(:id => @state.id).count, 0 end end
<%= _('Properties') %>
<%= _('Properties') %>
<%= _('Name') %><%= @container.in_fog.name %><%= fog_property(@container) { @container.in_fog.name } %>
<%= _('Image Repository') %>
<%= _('IP Address') %><%= @container.in_fog.ipaddress %> <%= fog_property(@container) { @container.in_fog.ipaddress } %>
<%= _('CPU shares') %><%= @container.in_fog.cores %><%= fog_property(@container) { @container.in_fog.cores } %>
<%= _('UUID') %><%= trunc_with_tooltip @container.in_fog.identity %><%= fog_property(@container) { trunc_with_tooltip(@container.in_fog.identity) } %>
<%= _('Memory') %><%= number_to_human_size @container.in_fog.memory %> + <%= fog_property(@container) { number_to_human_size(@container.in_fog.memory) } %> +
<%= _('Command') %><%= @container.in_fog.command %> <%= fog_property(@container) { @container.in_fog.command } %>
<%= _('Exposed ports') %><%= @container.in_fog.exposed_ports %> <%= fog_property(@container) { @container.in_fog.exposed_ports } %>
<%= _('Environment Variables') %> - - <% (@container.in_fog.attributes['config_env'] || []).each do |environment_variable| %> - <% pair = environment_variable.split("=") %> - - - - - <% end %> -
<%= pair.first %><%= pair.second %>
+ <%= + fog_property(@container) do + pair_attributes_table(@container.in_fog.attributes['config_env'] || []) + end + %>