foreman-tasks 0.11.3 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5215b1de3a75cefb5abd6ee4cddab099336f5982
4
- data.tar.gz: d4a4c997bc7a1527fb022d2e058f8e0b6c47379d
3
+ metadata.gz: c7c6574c1c5525bc889cdc026a5604229f0807b9
4
+ data.tar.gz: 4c79cb7a232ea3115f09c06e619667b7a203d821
5
5
  SHA512:
6
- metadata.gz: d4a03380fa48d6f4c61f0b3b87ab9ef0b81e7938ee1090a50e205ec9e2a60b4e11a1a18ccd3bbb7c5d69880b8bf76e913a403233f5df7df9b4839f6cc5310396
7
- data.tar.gz: dfd5566f78c22ab02632dc33edca0a9a9e9ef25a00e297399d09440be29c2d79fd3bb87371766fef052e5ae8aefac914dc7407b8093071a21d9218eef8588a34
6
+ metadata.gz: 0a4b956c2dd74d1cd3c20499636bcaf794accdd6442a21565bc2912c8c112827f5c1fdc709334393631e4e1d1d8460e090c6a9ea9a6904c072657a1743d21de0
7
+ data.tar.gz: 1b31d911db9af5260d56754779c068f53d66a9936e90a73b2b5889cdd2321d6aefdde41bfc6a3e68152d908312e2101c7e1fe971fd4851969bb4d51b11e05e08
data/.rubocop.yml CHANGED
@@ -98,3 +98,6 @@ Rails/InverseOf:
98
98
 
99
99
  Style/FormatStringToken:
100
100
  Enabled: false
101
+
102
+ Style/RegexpLiteral:
103
+ Enabled: false
@@ -1,7 +1,13 @@
1
1
  module ForemanTasks
2
2
  module Concerns
3
3
  module HostsControllerExtension
4
- def facts
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method_chain :facts, :dynflow
8
+ end
9
+
10
+ def facts_with_dynflow
5
11
  task = ForemanTasks.async_task(::Actions::Foreman::Host::ImportFacts,
6
12
  detect_host_type,
7
13
  params[:name],
@@ -17,7 +17,7 @@ module ForemanTasks
17
17
  render :index
18
18
  end
19
19
  format.csv do
20
- csv_response(@tasks, [:to_label, :state, :result, 'started_at.in_time_zone', 'ended_at.in_time_zone', :username], ['Action', 'State', 'Result', 'Started At', 'Ended At', 'User'])
20
+ csv_response(@tasks, [:action_label, :state, :result, 'started_at.in_time_zone', 'ended_at.in_time_zone', :username], ['Action', 'State', 'Result', 'Started At', 'Ended At', 'User'])
21
21
  end
22
22
  end
23
23
  end
@@ -1,7 +1,8 @@
1
1
  module ForemanTasks
2
2
  module TasksHelper
3
3
  def format_task_input(task)
4
- task ? task.to_label : '-'
4
+ return '-' unless task
5
+ task.action
5
6
  end
6
7
 
7
8
  def format_recurring_logic_limit(thing)
@@ -36,6 +36,7 @@ module ForemanTasks
36
36
  end
37
37
 
38
38
  scoped_search :on => :id, :complete_value => false
39
+ scoped_search :on => :action, :complete_value => false
39
40
  scoped_search :on => :label, :complete_value => true
40
41
  scoped_search :on => :state, :complete_value => true
41
42
  scoped_search :on => :result, :complete_value => true
@@ -202,6 +203,10 @@ module ForemanTasks
202
203
  result.symbolize_keys
203
204
  end
204
205
 
206
+ def action
207
+ super || to_label
208
+ end
209
+
205
210
  def to_label
206
211
  parts = []
207
212
  parts << get_humanized(:name)
@@ -3,6 +3,7 @@ module ForemanTasks
3
3
  include Algebrick::TypeCheck
4
4
 
5
5
  scope :for_action, ->(action_class) { where(label: action_class.name) }
6
+ after_validation :set_action_field
6
7
 
7
8
  def update_from_dynflow(data)
8
9
  utc_zone = ActiveSupport::TimeZone.new('UTC')
@@ -152,6 +153,10 @@ module ForemanTasks
152
153
 
153
154
  private
154
155
 
156
+ def set_action_field
157
+ self.action = to_label
158
+ end
159
+
155
160
  def map_result(data)
156
161
  if state_result_transitioned?(%w[planned pending], %w[stopped error], data) ||
157
162
  (data[:result] == :error && cancelled?)
@@ -1,7 +1,7 @@
1
1
  <% title _("Recurring logics") %>
2
2
  <% title_actions SETTINGS[:version].short <= '1.13' ? help_path : help_button %>
3
3
 
4
- <table class="table table-fixed table-bordered table-striped table-condensed">
4
+ <table class="<%= table_css_classes('table-condensed table-fixed') %>">
5
5
  <thead>
6
6
  <th><%= N_("Cron line") %></th>
7
7
  <th><%= N_("Task count") %></th>
@@ -1,5 +1,5 @@
1
1
  <div>
2
- <table class='table table-condensed'>
2
+ <table class='<%= table_css_classes('table-condensed') %>'>
3
3
  <tr>
4
4
  <th><%= N_('ID') %></th>
5
5
  <td><%= link_to(task_group.id, foreman_tasks_task_group_url(task_group)) %></td>
@@ -1,5 +1,5 @@
1
1
  <% recurring_logic = task_group.recurring_logic -%>
2
- <table class='table table-condensed'>
2
+ <table class='<%= table_css_classes('table-condensed') %>'>
3
3
  <tr>
4
4
  <th>ID</th>
5
5
  <td><%= link_to(recurring_logic.id, recurring_logic) %></td>
@@ -89,7 +89,8 @@
89
89
  <div class="col-md-6">
90
90
  <div>
91
91
  <span class="param-name list-group-item-heading"><%= _("Name") %>:</span>
92
- <span class="param-value" data-original-title="<%= @task.to_label %>" rel="twipsy"> <%= truncate(@task.to_label, :length => 50) %></span>
92
+ <% task_label = format_task_input(@task) %>
93
+ <span class="param-value" data-original-title="<%= task_label %>" rel="twipsy"> <%= truncate(task_label, :length => 50) %></span>
93
94
  </div>
94
95
  <div>
95
96
  <span class="param-name list-group-item-heading"><%= _("Result") %>:</span>
@@ -1,5 +1,5 @@
1
1
  <h4><%= link_to _("Latest Warning/Error Tasks"), foreman_tasks_tasks_path(:order=>'started_at DESC') %></h4>
2
- <table class="table table-striped table-fixed">
2
+ <table class="<%= table_css_classes('table-fixed') %>">
3
3
  <tr>
4
4
  <th class="col-md-5"><%= _("Name") %></th>
5
5
  <th class="col-md-2"><%= _("State") %></th>
@@ -1,5 +1,5 @@
1
1
  <h4 class="header"><%=_("Task Status")%></h4>
2
- <table class="table table-striped">
2
+ <table class="<%= table_css_classes('table-condensed') %>">
3
3
  <tr>
4
4
  <th><%= _("State") %></th>
5
5
  <th><%= _("Result") %></th>
@@ -27,8 +27,8 @@ $(document).on('click', ".table-two-pane td.two-pane-link", function(e) {
27
27
  <% for task in @tasks %>
28
28
  <tr>
29
29
  <td class="task-id two-pane-link ellipsis">
30
- <%= link_to_if_authorized(task.to_label,
31
- hash_for_foreman_tasks_task_path(:id => task)) %>
30
+ <%= link_to_if_authorized(format_task_input(task),
31
+ hash_for_foreman_tasks_task_path(:id => task)) %>
32
32
  </td>
33
33
  <td class="ellipsis"><%= task.state %></td>
34
34
  <td class="ellipsis"><%= task.result %></td>
@@ -0,0 +1,9 @@
1
+ class AddTaskAction < ActiveRecord::Migration[4.2]
2
+ def up
3
+ add_column :foreman_tasks_tasks, :action, :string
4
+ end
5
+
6
+ def down
7
+ remove_column :foreman_tasks_tasks, :action
8
+ end
9
+ end
@@ -0,0 +1,44 @@
1
+ class UseUuid < ActiveRecord::Migration[5.0]
2
+ # PostgreSQL has a special column type for storing UUIDs.
3
+ # Using this type instead of generic string should lead to having
4
+ # smaller DB and possibly better overall performance.
5
+ def up
6
+ if on_postgresql?
7
+ change_table :foreman_tasks_tasks do |t|
8
+ t.change :id, :uuid, :using => 'id::uuid'
9
+ t.change :parent_task_id, :uuid, :using => 'parent_task_id::uuid'
10
+ end
11
+
12
+ change_table :foreman_tasks_task_group_members do |t|
13
+ t.change :task_id, :uuid, :using => 'task_id::uuid'
14
+ end
15
+
16
+ change_table :foreman_tasks_locks do |t|
17
+ t.change :task_id, :uuid, :using => 'task_id::uuid'
18
+ end
19
+ end
20
+ end
21
+
22
+ def down
23
+ if on_postgresql?
24
+ change_table :foreman_tasks_tasks do |t|
25
+ t.change :id, :string
26
+ t.change :parent_task_id, :string
27
+ end
28
+
29
+ change_table :foreman_tasks_task_group_members do |t|
30
+ t.change :task_id, :string
31
+ end
32
+
33
+ change_table :foreman_tasks_locks do |t|
34
+ t.change :task_id, :string
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def on_postgresql?
42
+ ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
43
+ end
44
+ end
@@ -133,7 +133,7 @@ module ForemanTasks
133
133
  # to enable async Foreman operations using Dynflow
134
134
  if ENV['FOREMAN_TASKS_MONKEYS'] == 'true'
135
135
  config.to_prepare do
136
- ::Api::V2::HostsController.send :prepend, ForemanTasks::Concerns::HostsControllerExtension
136
+ ::Api::V2::HostsController.send :include, ForemanTasks::Concerns::HostsControllerExtension
137
137
  ::Host::Base.send :include, ForemanTasks::Concerns::HostActionSubject
138
138
  end
139
139
  end
@@ -144,8 +144,23 @@ module ForemanTasks
144
144
  Authorizer.send(:prepend, AuthorizerExt)
145
145
  end
146
146
 
147
+ config.after_initialize do
148
+ ForemanTasks.dynflow.eager_load_actions!
149
+ ForemanTasks.dynflow.config.increase_db_pool_size
150
+
151
+ unless ForemanTasks.dynflow.config.lazy_initialization
152
+ if defined?(PhusionPassenger)
153
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
154
+ ForemanTasks.dynflow.initialize! if forked
155
+ end
156
+ else
157
+ ForemanTasks.dynflow.initialize!
158
+ end
159
+ end
160
+ end
161
+
147
162
  rake_tasks do
148
- %w[dynflow.rake test.rake export_tasks.rake cleanup.rake].each do |rake_file|
163
+ %w[dynflow.rake test.rake export_tasks.rake cleanup.rake generate_task_actions.rake].each do |rake_file|
149
164
  full_path = File.expand_path("../tasks/#{rake_file}", __FILE__)
150
165
  load full_path if File.exist?(full_path)
151
166
  end
@@ -0,0 +1,41 @@
1
+ #
2
+ # generate_task_actions.rake is a data migration task to properly fill the missing
3
+ # values into the foreman_tasks_tasks table.
4
+ #
5
+ # Run "foreman-rake foreman_tasks:generate_task_actions" to generate missing values.
6
+
7
+ namespace :foreman_tasks do
8
+ desc 'Generate missing values for action column in foreman_tasks_tasks table.'
9
+
10
+ BATCH_SIZE = 100
11
+
12
+ task :generate_task_actions => :environment do
13
+ class ProgressReporter
14
+ def initialize(count, message = nil)
15
+ @count = count
16
+ @processed = 0
17
+ puts message % { :count => count } unless message.nil?
18
+ end
19
+
20
+ def progress(count)
21
+ @processed += count
22
+ end
23
+
24
+ def report
25
+ puts _('Processed %{processed}/%{count} tasks') % { :processed => @processed, :count => @count }
26
+ end
27
+ end
28
+
29
+ scope = ::ForemanTasks::Task.where(:action => nil).order(:started_at => :desc)
30
+ count = scope.count
31
+ reporter = ProgressReporter.new count, _('Generating action for %{count} tasks.')
32
+ scope.find_in_batches(:batch_size => BATCH_SIZE) do |group|
33
+ group.each do |task|
34
+ task.action = task.to_label
35
+ task.save!
36
+ end
37
+ reporter.progress group.size
38
+ reporter.report
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '0.11.3'.freeze
2
+ VERSION = '0.12.0'.freeze
3
3
  end
@@ -41,7 +41,7 @@ module ForemanTasks
41
41
  task.reload
42
42
  task.state.must_equal 'stopped'
43
43
  task.result.must_equal 'success'
44
- task.main_action.output['proxy_task_id'].must_equal '123'
44
+ task.main_action.output['proxy_task_id'].must_equal Support::DummyProxyAction.proxy.uuid
45
45
  task.main_action.output['proxy_output'].must_equal('result' => 'success')
46
46
  end
47
47
  end
@@ -8,6 +8,7 @@ module ForemanTasks
8
8
  humanized = { :humanized_name => 'Create', :humanized_input => [[:user, { :text => "user 'Anonymous Admin'", :link => nil }]] }
9
9
  @task.instance_variable_set('@humanized_cache', humanized)
10
10
  @task.stubs(:input).returns('user' => { 'id' => 1, 'name' => 'Anonymous Admin' }, 'locale' => 'en')
11
+ @task.stubs(:action).returns(@task.to_label)
11
12
  end
12
13
 
13
14
  it 'formats the task input properly' do
@@ -31,6 +32,7 @@ module ForemanTasks
31
32
  'cp_id' => '1412251033866',
32
33
  'locale' => 'en' }
33
34
  @task.stubs(:input).returns(input)
35
+ @task.stubs(:action).returns(@task.to_label)
34
36
  end
35
37
 
36
38
  it 'formats the task input properly' do
@@ -1,17 +1,20 @@
1
+ require 'securerandom'
2
+
1
3
  module Support
2
4
  class DummyProxyAction < Actions::ProxyAction
3
5
  class DummyProxy
4
- attr_reader :log, :task_triggered
6
+ attr_reader :log, :task_triggered, :uuid
5
7
 
6
8
  def initialize
7
9
  @log = Hash.new { |h, k| h[k] = [] }
8
10
  @task_triggered = Concurrent.future
11
+ @uuid = SecureRandom.uuid
9
12
  end
10
13
 
11
14
  def trigger_task(*args)
12
15
  @log[:trigger_task] << args
13
16
  @task_triggered.success(true)
14
- { 'task_id' => '123' }
17
+ { 'task_id' => @uuid }
15
18
  end
16
19
 
17
20
  def cancel_task(*args)
@@ -36,7 +39,7 @@ module Support
36
39
  def task
37
40
  super
38
41
  rescue ActiveRecord::RecordNotFound
39
- ForemanTasks::Task::DynflowTask.new.tap { |task| task.id = '123' }
42
+ ForemanTasks::Task::DynflowTask.new.tap { |task| task.id = proxy.uuid }
40
43
  end
41
44
 
42
45
  class << self
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ require 'foreman_tasks_test_helper'
3
+
4
+ class GenerateTaskActionsTest < ActiveSupport::TestCase
5
+ TASK_NAME = 'foreman_tasks:generate_task_actions'.freeze
6
+
7
+ setup do
8
+ Rake.application.rake_require 'foreman_tasks/tasks/generate_task_actions'
9
+
10
+ Rake::Task.define_task(:environment)
11
+ Rake::Task[TASK_NAME].reenable
12
+ end
13
+
14
+ let(:tasks) do
15
+ (1..5).map { FactoryBot.build(:dynflow_task) }
16
+ end
17
+
18
+ it 'fixes the tasks' do
19
+ label = 'a label'
20
+ tasks
21
+ ForemanTasks::Task.update_all(:action => nil)
22
+ ForemanTasks::Task.any_instance.stubs(:to_label).returns(label)
23
+
24
+ stdout, _stderr = capture_io do
25
+ Rake.application.invoke_task TASK_NAME
26
+ end
27
+
28
+ assert_match(%r{Generating action for #{tasks.count} tasks}, stdout)
29
+ ForemanTasks::Task.where(:action => label).count.must_equal tasks.count
30
+ assert_match(%r{Processed #{tasks.count}/#{tasks.count} tasks}, stdout)
31
+ end
32
+
33
+ it 'fixes only tasks with missing action' do
34
+ tasks
35
+ ForemanTasks::Task.any_instance.expects(:save!).never
36
+
37
+ stdout, _stderr = capture_io do
38
+ Rake.application.invoke_task TASK_NAME
39
+ end
40
+
41
+ assert_match(%r{Generating action for 0 tasks}, stdout)
42
+ end
43
+ end
@@ -29,7 +29,7 @@ module ForemanTasks
29
29
  { 'retry_interval' => 15, 'retry_count' => 4, 'timeout' => 60 },
30
30
  'proxy_url' => 'proxy.example.com',
31
31
  'proxy_action_name' => 'Proxy::DummyAction',
32
- 'callback' => { 'task_id' => '123', 'step_id' => @action.run_step_id } }]
32
+ 'callback' => { 'task_id' => Support::DummyProxyAction.proxy.uuid, 'step_id' => @action.run_step_id } }]
33
33
  proxy_call.must_equal(expected_call)
34
34
  end
35
35
  end
@@ -52,7 +52,7 @@ module ForemanTasks
52
52
  describe 'cancel' do
53
53
  it 'sends the cancel event to the proxy when the cancel event is sent for the first time' do
54
54
  action = run_action(@action, ::Dynflow::Action::Cancellable::Cancel)
55
- Support::DummyProxyAction.proxy.log[:cancel_task].first.must_equal ['123']
55
+ Support::DummyProxyAction.proxy.log[:cancel_task].first.must_equal [Support::DummyProxyAction.proxy.uuid]
56
56
  action.state.must_equal :suspended
57
57
  end
58
58
 
@@ -58,9 +58,11 @@ class TasksTest < ActiveSupport::TestCase
58
58
 
59
59
  describe 'task without valid execution plan' do
60
60
  let(:task) do
61
- FactoryBot.create(:dynflow_task).tap do |task|
61
+ task = FactoryBot.create(:dynflow_task).tap do |task|
62
62
  task.external_id = 'missing-task'
63
+ task.save
63
64
  end
65
+ ForemanTasks::Task.find(task.id)
64
66
  end
65
67
 
66
68
  it 'handles the error while loading the task and does not propagate errors unless necessary' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.3
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-13 00:00:00.000000000 Z
11
+ date: 2018-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: foreman-tasks-core
@@ -200,6 +200,8 @@ files:
200
200
  - db/migrate/20160920151810_add_more_lock_indexes.rb
201
201
  - db/migrate/20160924213030_change_tasks_widget_names.rb
202
202
  - db/migrate/20161003091412_add_missing_indexes.rb
203
+ - db/migrate/20171026082635_add_task_action.foreman_tasks.rb
204
+ - db/migrate/20180216092715_use_uuid.rb
203
205
  - db/seeds.d/20-foreman_tasks_permissions.rb
204
206
  - db/seeds.d/60-dynflow_proxy_feature.rb
205
207
  - db/seeds.d/61-foreman_tasks_bookmarks.rb
@@ -220,6 +222,7 @@ files:
220
222
  - lib/foreman_tasks/task_error.rb
221
223
  - lib/foreman_tasks/tasks/cleanup.rake
222
224
  - lib/foreman_tasks/tasks/export_tasks.rake
225
+ - lib/foreman_tasks/tasks/generate_task_actions.rake
223
226
  - lib/foreman_tasks/test_extensions.rb
224
227
  - lib/foreman_tasks/test_helpers.rb
225
228
  - lib/foreman_tasks/triggers.rb
@@ -243,6 +246,7 @@ files:
243
246
  - test/support/dummy_dynflow_action.rb
244
247
  - test/support/dummy_proxy_action.rb
245
248
  - test/support/dummy_task_group.rb
249
+ - test/tasks/generate_task_actions_test.rb
246
250
  - test/unit/actions/action_with_sub_plans_test.rb
247
251
  - test/unit/actions/proxy_action_test.rb
248
252
  - test/unit/cleaner_test.rb
@@ -291,6 +295,7 @@ test_files:
291
295
  - test/support/dummy_dynflow_action.rb
292
296
  - test/support/dummy_proxy_action.rb
293
297
  - test/support/dummy_task_group.rb
298
+ - test/tasks/generate_task_actions_test.rb
294
299
  - test/unit/actions/action_with_sub_plans_test.rb
295
300
  - test/unit/actions/proxy_action_test.rb
296
301
  - test/unit/cleaner_test.rb