foreman-tasks 0.8.6 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +35 -0
  3. data/.rubocop_todo.yml +138 -0
  4. data/app/controllers/foreman_tasks/api/recurring_logics_controller.rb +3 -4
  5. data/app/controllers/foreman_tasks/api/tasks_controller.rb +56 -72
  6. data/app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb +2 -4
  7. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +2 -5
  8. data/app/controllers/foreman_tasks/tasks_controller.rb +7 -8
  9. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +44 -46
  10. data/app/helpers/foreman_tasks/tasks_helper.rb +1 -1
  11. data/app/lib/actions/action_with_sub_plans.rb +6 -8
  12. data/app/lib/actions/base.rb +6 -7
  13. data/app/lib/actions/bulk_action.rb +13 -9
  14. data/app/lib/actions/entry_action.rb +1 -3
  15. data/app/lib/actions/foreman/host/import_facts.rb +2 -5
  16. data/app/lib/actions/foreman/puppetclass/import.rb +1 -1
  17. data/app/lib/actions/helpers/args_serialization.rb +0 -1
  18. data/app/lib/actions/helpers/humanizer.rb +16 -21
  19. data/app/lib/actions/helpers/with_continuous_output.rb +0 -1
  20. data/app/lib/actions/helpers/with_delegated_action.rb +2 -2
  21. data/app/lib/actions/middleware/inherit_task_groups.rb +3 -5
  22. data/app/lib/actions/middleware/keep_current_user.rb +0 -3
  23. data/app/lib/actions/middleware/recurring_logic.rb +0 -1
  24. data/app/lib/actions/proxy_action.rb +8 -8
  25. data/app/lib/actions/serializers/active_record_serializer.rb +0 -3
  26. data/app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb +3 -3
  27. data/app/models/foreman_tasks/concerns/action_subject.rb +4 -6
  28. data/app/models/foreman_tasks/concerns/action_triggering.rb +20 -33
  29. data/app/models/foreman_tasks/concerns/host_action_subject.rb +5 -5
  30. data/app/models/foreman_tasks/lock.rb +29 -37
  31. data/app/models/foreman_tasks/recurring_logic.rb +23 -24
  32. data/app/models/foreman_tasks/task.rb +65 -39
  33. data/app/models/foreman_tasks/task/dynflow_task.rb +23 -24
  34. data/app/models/foreman_tasks/task/status_explicator.rb +3 -3
  35. data/app/models/foreman_tasks/task/summarizer.rb +3 -3
  36. data/app/models/foreman_tasks/task_group.rb +0 -2
  37. data/app/models/foreman_tasks/task_group_member.rb +0 -2
  38. data/app/models/foreman_tasks/task_groups/recurring_logic_task_group.rb +1 -4
  39. data/app/models/foreman_tasks/triggering.rb +19 -19
  40. data/app/models/setting/foreman_tasks.rb +8 -11
  41. data/app/services/foreman_tasks/proxy_selector.rb +4 -5
  42. data/app/views/foreman_tasks/tasks/_details.html.erb +1 -1
  43. data/bin/dynflow-executor +1 -1
  44. data/bin/foreman-tasks +1 -1
  45. data/config/routes.rb +1 -1
  46. data/db/migrate/20150814204140_add_task_type_value_index.rb +1 -1
  47. data/db/migrate/20160924213030_change_tasks_widget_names.rb +8 -8
  48. data/db/seeds.d/61-foreman_tasks_bookmarks.rb +3 -3
  49. data/deploy/foreman-tasks.sysconfig +6 -0
  50. data/extra/dynflow-debug.sh +12 -0
  51. data/foreman-tasks.gemspec +1 -1
  52. data/lib/foreman_tasks.rb +3 -3
  53. data/lib/foreman_tasks/authorizer_ext.rb +1 -1
  54. data/lib/foreman_tasks/cleaner.rb +14 -16
  55. data/lib/foreman_tasks/dynflow.rb +11 -9
  56. data/lib/foreman_tasks/dynflow/configuration.rb +8 -10
  57. data/lib/foreman_tasks/dynflow/console_authorizer.rb +4 -5
  58. data/lib/foreman_tasks/dynflow/daemon.rb +17 -19
  59. data/lib/foreman_tasks/dynflow/persistence.rb +5 -8
  60. data/lib/foreman_tasks/engine.rb +30 -31
  61. data/lib/foreman_tasks/task_error.rb +1 -3
  62. data/lib/foreman_tasks/tasks/cleanup.rake +7 -19
  63. data/lib/foreman_tasks/tasks/dynflow.rake +1 -1
  64. data/lib/foreman_tasks/tasks/export_tasks.rake +51 -59
  65. data/lib/foreman_tasks/test_extensions.rb +1 -1
  66. data/lib/foreman_tasks/version.rb +1 -1
  67. data/lib/tasks/gettext.rake +10 -7
  68. data/locale/action_names.rb +3 -6
  69. data/locale/en/foreman_tasks.po +189 -177
  70. data/locale/foreman_tasks.pot +177 -137
  71. data/test/controllers/api/recurring_logics_controller_test.rb +3 -5
  72. data/test/controllers/api/tasks_controller_test.rb +5 -7
  73. data/test/factories/task_factory.rb +8 -8
  74. data/test/factories/triggering_factory.rb +2 -3
  75. data/test/helpers/foreman_tasks/tasks_helper_test.rb +11 -11
  76. data/test/support/dummy_proxy_action.rb +3 -4
  77. data/test/unit/actions/action_with_sub_plans_test.rb +5 -6
  78. data/test/unit/actions/proxy_action_test.rb +5 -8
  79. data/test/unit/cleaner_test.rb +11 -12
  80. data/test/unit/dynflow_console_authorizer_test.rb +4 -4
  81. data/test/unit/proxy_selector_test.rb +3 -3
  82. data/test/unit/recurring_logic_test.rb +19 -17
  83. data/test/unit/task_groups_test.rb +3 -4
  84. data/test/unit/task_test.rb +72 -5
  85. data/test/unit/triggering_test.rb +0 -1
  86. metadata +7 -6
  87. data/app/controllers/foreman_tasks/concerns/environments_extension.rb +0 -24
@@ -5,7 +5,7 @@ module ForemanTasks
5
5
  include ForemanTasks::Concerns::ActionSubject
6
6
 
7
7
  def action_input_key
8
- "host"
8
+ 'host'
9
9
  end
10
10
 
11
11
  def available_locks
@@ -16,15 +16,15 @@ module ForemanTasks
16
16
  # TODO: This should get into the Foreman core, extracting the
17
17
  # +importHostAndFacts+ method into two
18
18
  def import_host(hostname, certname, facts, proxy_id = nil)
19
- raise(::Foreman::Exception.new("Invalid Facts, must be a Hash")) unless facts.is_a?(Hash)
20
- raise(::Foreman::Exception.new("Invalid Hostname, must be a String")) unless hostname.is_a?(String)
19
+ raise Foreman::Exception, 'Invalid Facts, must be a Hash' unless facts.is_a?(Hash)
20
+ raise Foreman::Exception, 'Invalid Hostname, must be a String' unless hostname.is_a?(String)
21
21
 
22
22
  # downcase everything
23
23
  hostname.try(:downcase!)
24
24
  certname.try(:downcase!)
25
25
 
26
- host = certname.present? ? Host.find_by_certname(certname) : nil
27
- host ||= Host.find_by_name hostname
26
+ host = certname.present? ? Host.find_by(certname: certname) : nil
27
+ host ||= Host.find_by name: hostname
28
28
  host ||= Host.new(:name => hostname, :certname => certname) if Setting[:create_new_host_when_facts_are_uploaded]
29
29
 
30
30
  return Host.new if host.nil?
@@ -1,32 +1,31 @@
1
1
  module ForemanTasks
2
2
  class Lock < ActiveRecord::Base
3
-
4
3
  LINK_LOCK_NAME = :link_resource
5
4
  OWNER_LOCK_NAME = :task_owner
6
5
 
7
- # not really intedet to be created in database, but it's used for
6
+ # not really intended to be created in database, but it's used for
8
7
  # explicitly stating that the all the locks for resource should be used
9
8
  ALL_LOCK_NAME = :all
10
9
 
11
- RESERVED_LOCK_NAMES = [LINK_LOCK_NAME, OWNER_LOCK_NAME, ALL_LOCK_NAME]
10
+ RESERVED_LOCK_NAMES = [LINK_LOCK_NAME, OWNER_LOCK_NAME, ALL_LOCK_NAME].freeze
12
11
 
13
12
  class LockConflict < StandardError
14
13
  attr_reader :required_lock, :conflicting_locks
15
14
  def initialize(required_lock, conflicting_locks)
16
- header = _("Required lock is already taken by other running tasks.")
15
+ header = _('Required lock is already taken by other running tasks.')
17
16
  header << "\n"
18
- header << _("Please inspect their state, fix their errors and resume them.")
17
+ header << _('Please inspect their state, fix their errors and resume them.')
19
18
  header << "\n\n"
20
- header << _("Required lock: %s") % required_lock.name
19
+ header << _('Required lock: %s') % required_lock.name
21
20
  header << "\n"
22
- header << _("Conflicts with tasks:")
21
+ header << _('Conflicts with tasks:')
23
22
  header << "\n"
24
23
  url_helpers = Rails.application.routes.url_helpers
25
- conflicting_tasks = conflicting_locks.
26
- map(&:task).
27
- uniq.
28
- map { |task| "- #{Setting['foreman_url'] + url_helpers.foreman_tasks_task_path(task)}" }.
29
- join("\n")
24
+ conflicting_tasks = conflicting_locks
25
+ .map(&:task)
26
+ .uniq
27
+ .map { |task| "- #{Setting['foreman_url'] + url_helpers.foreman_tasks_task_path(task)}" }
28
+ .join("\n")
30
29
 
31
30
  super header + conflicting_tasks
32
31
  @required_lock = required_lock
@@ -38,21 +37,17 @@ module ForemanTasks
38
37
 
39
38
  belongs_to :resource, polymorphic: true
40
39
 
41
- scope :active, -> do
42
- joins(:task).where('foreman_tasks_tasks.state != ?', :stopped)
43
- end
40
+ scope :active, -> { joins(:task).where('foreman_tasks_tasks.state != ?', :stopped) }
44
41
 
45
42
  validates :task_id, :name, :resource_id, :resource_type, presence: true
46
43
 
47
44
  validate do
48
- unless available?
49
- raise LockConflict.new(self, colliding_locks)
50
- end
45
+ raise LockConflict.new(self, colliding_locks) unless available?
51
46
  end
52
47
 
53
48
  # returns true if it's possible to aquire this kind of lock
54
49
  def available?
55
- not colliding_locks.exists?
50
+ !colliding_locks.exists?
56
51
  end
57
52
 
58
53
  # returns a scope of the locks colliding with this one
@@ -62,14 +57,13 @@ module ForemanTasks
62
57
  colliding_locks_scope = colliding_locks_scope.where(name: name,
63
58
  resource_id: resource_id,
64
59
  resource_type: resource_type)
65
- unless self.exclusive?
60
+ unless exclusive?
66
61
  colliding_locks_scope = colliding_locks_scope.where(:exclusive => true)
67
62
  end
68
- return colliding_locks_scope
63
+ colliding_locks_scope
69
64
  end
70
65
 
71
66
  class << self
72
-
73
67
  # Locks the resource so that no other task can lock it while running.
74
68
  # No other task related to the resource is not allowed (even not-locking ones)
75
69
  # A typical usecase is resource deletion, where it's good idea to make sure
@@ -82,7 +76,6 @@ module ForemanTasks
82
76
  build_exclusive_locks(resource).all?(&:available?)
83
77
  end
84
78
 
85
-
86
79
  # Locks the resource so that no other task can lock it while running.
87
80
  # Other not-locking tasks are tolerated.
88
81
  #
@@ -103,12 +96,12 @@ module ForemanTasks
103
96
  end
104
97
 
105
98
  def locked?(resource, uuid, *lock_names)
106
- not lockable?(resource, uuid, *lock_names)
99
+ !lockable?(resource, uuid, *lock_names)
107
100
  end
108
101
 
109
102
  def colliding_locks(resource, uuid, *lock_names)
110
- build_locks(resource, lock_names, uuid).
111
- inject([]) { |collisions, lock| collisions.concat lock.colliding_locks.to_a }
103
+ build_locks(resource, lock_names, uuid)
104
+ .inject([]) { |collisions, lock| collisions.concat lock.colliding_locks.to_a }
112
105
  end
113
106
 
114
107
  # Assigns the resource to the task to easily track the task in context of
@@ -136,7 +129,7 @@ module ForemanTasks
136
129
  def all_lock_names(resource, include_links = false)
137
130
  lock_names = []
138
131
  if resource.class.respond_to?(:available_locks) &&
139
- resource.class.available_locks.any?
132
+ resource.class.available_locks.any?
140
133
  lock_names.concat(resource.class.available_locks)
141
134
  else
142
135
  raise "The resource #{resource.class.name} doesn't define any available lock"
@@ -145,7 +138,7 @@ module ForemanTasks
145
138
  raise "Lock name #{lock_name} is reserved"
146
139
  end
147
140
  lock_names.concat([LINK_LOCK_NAME, OWNER_LOCK_NAME]) if include_links
148
- return lock_names
141
+ lock_names
149
142
  end
150
143
 
151
144
  def build_exclusive_locks(resource, uuid = nil)
@@ -161,7 +154,7 @@ module ForemanTasks
161
154
  locks << build(uuid, resource, lock_name, true)
162
155
  end
163
156
  locks.concat(build_links(resource, uuid))
164
- return locks
157
+ locks
165
158
  end
166
159
 
167
160
  def build_links(resource, uuid = nil)
@@ -179,23 +172,22 @@ module ForemanTasks
179
172
  end
180
173
 
181
174
  def build(uuid, resource, lock_name, exclusive)
182
- self.new(task_id: uuid,
183
- name: lock_name,
184
- resource_type: resource.class.name,
185
- resource_id: resource.id,
186
- exclusive: !!exclusive)
175
+ new(task_id: uuid,
176
+ name: lock_name,
177
+ resource_type: resource.class.name,
178
+ resource_id: resource.id,
179
+ exclusive: !!exclusive)
187
180
  end
188
181
 
189
182
  # recursively search for related resources of the resource (using
190
183
  # the +related_resources+ method, avoiding the cycles
191
184
  def related_resources(resource)
192
185
  if resource.respond_to?(:all_related_resources)
193
- return resource.all_related_resources
186
+ resource.all_related_resources
194
187
  else
195
- return []
188
+ []
196
189
  end
197
190
  end
198
191
  end
199
-
200
192
  end
201
193
  end
@@ -1,5 +1,4 @@
1
1
  module ForemanTasks
2
-
3
2
  require 'parse-cron'
4
3
 
5
4
  class RecurringLogic < ActiveRecord::Base
@@ -15,13 +14,13 @@ module ForemanTasks
15
14
  has_many :task_groups, -> { uniq }, :through => :tasks
16
15
  end
17
16
 
18
- scoped_search :on => :id, :complete_value => false
17
+ scoped_search :on => :id, :complete_value => false, :validator => ScopedSearch::Validators::INTEGER
19
18
  scoped_search :on => :max_iteration, :complete_value => false, :rename => :iteration_limit
20
19
  scoped_search :on => :iteration, :complete_value => false
21
20
  scoped_search :on => :cron_line, :complete_value => true
22
21
 
23
22
  before_create do
24
- self.task_group.save
23
+ task_group.save
25
24
  end
26
25
 
27
26
  def self.allowed_states
@@ -35,16 +34,16 @@ module ForemanTasks
35
34
  end
36
35
 
37
36
  def trigger_repeat(action_class, *args)
38
- unless can_continue?
39
- self.state = 'finished'
40
- save!
41
- return
42
- else
37
+ if can_continue?
43
38
  self.iteration += 1
44
39
  save!
45
40
  ::ForemanTasks.delay action_class,
46
41
  generate_delay_options,
47
42
  *args
43
+ else
44
+ self.state = 'finished'
45
+ save!
46
+ nil
48
47
  end
49
48
  end
50
49
 
@@ -54,21 +53,21 @@ module ForemanTasks
54
53
  tasks.active.each(&:cancel)
55
54
  end
56
55
 
57
- def next_occurrence_time(time = Time.now)
58
- @parser ||= CronParser.new(cron_line)
56
+ def next_occurrence_time(time = Time.zone.now)
57
+ @parser ||= CronParser.new(cron_line, Time.zone)
59
58
  @parser.next(time)
60
59
  end
61
60
 
62
- def generate_delay_options(time = Time.now, options = {})
61
+ def generate_delay_options(time = Time.zone.now, options = {})
63
62
  {
64
63
  :start_at => next_occurrence_time(time),
65
64
  :start_before => options['start_before'],
66
- :recurring_logic_id => self.id
65
+ :recurring_logic_id => id
67
66
  }
68
67
  end
69
68
 
70
69
  def valid?(*_)
71
- cron_line.present? && valid_cronline? && !self.state.nil? || can_start?
70
+ cron_line.present? && valid_cronline? && !state.nil? || can_start?
72
71
  end
73
72
 
74
73
  def valid_cronline?
@@ -77,21 +76,21 @@ module ForemanTasks
77
76
  false
78
77
  end
79
78
 
80
- def can_start?(time = Time.now)
79
+ def can_start?(time = Time.zone.now)
81
80
  (end_time.nil? || next_occurrence_time(time) < end_time) &&
82
81
  (max_iteration.nil? || iteration < max_iteration)
83
82
  end
84
83
 
85
- def can_continue?(time = Time.now)
86
- self.state == 'active' && can_start?(time)
84
+ def can_continue?(time = Time.zone.now)
85
+ state == 'active' && can_start?(time)
87
86
  end
88
87
 
89
88
  def finished?
90
- self.state == 'finished'
89
+ state == 'finished'
91
90
  end
92
91
 
93
92
  def humanized_state
94
- case self.state
93
+ case state
95
94
  when 'active'
96
95
  N_('Active')
97
96
  when 'cancelled'
@@ -104,13 +103,13 @@ module ForemanTasks
104
103
  end
105
104
 
106
105
  def self.assemble_cronline(hash)
107
- hash.values_at(*[:minutes, :hours, :days, :months, :days_of_week])
108
- .map { |value| (value.nil? || value.blank?) ? '*' : value }
106
+ hash.values_at(:minutes, :hours, :days, :months, :days_of_week)
107
+ .map { |value| value.nil? || value.blank? ? '*' : value }
109
108
  .join(' ')
110
109
  end
111
110
 
112
111
  def self.new_from_cronline(cronline)
113
- self.new.tap do |logic|
112
+ new.tap do |logic|
114
113
  logic.cron_line = cronline
115
114
  logic.task_group = ::ForemanTasks::TaskGroups::RecurringLogicTaskGroup.new
116
115
  end
@@ -120,7 +119,7 @@ module ForemanTasks
120
119
  cronline = if triggering.input_type == :cronline
121
120
  triggering.cronline
122
121
  else
123
- ::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash triggering.input_type, triggering.time, triggering.days_of_week)
122
+ ::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash(triggering.input_type, triggering.time, triggering.days_of_week))
124
123
  end
125
124
  ::ForemanTasks::RecurringLogic.new_from_cronline(cronline).tap do |manager|
126
125
  manager.end_time = triggering.end_time unless triggering.end_time_limited.blank?
@@ -132,8 +131,8 @@ module ForemanTasks
132
131
  def self.cronline_hash(recurring_type, time_hash, days_of_week_hash)
133
132
  hash = Hash[[:years, :months, :days, :hours, :minutes].zip(time_hash.values)]
134
133
  hash.update :days_of_week => days_of_week_hash
135
- .select { |key, value| value == "1" }
136
- .keys.join(',')
134
+ .select { |_key, value| value == '1' }
135
+ .keys.join(',')
137
136
  allowed_keys = case recurring_type
138
137
  when :monthly
139
138
  [:minutes, :hours, :days]
@@ -4,7 +4,7 @@ module ForemanTasks
4
4
  class Task < ActiveRecord::Base
5
5
  include Authorizable
6
6
 
7
- # TODO missing validation of states
7
+ # TODO: missing validation of states
8
8
 
9
9
  self.primary_key = :id
10
10
  before_create :generate_id
@@ -18,17 +18,16 @@ module ForemanTasks
18
18
  if Rails::VERSION::MAJOR < 4
19
19
  has_many :recurring_logic_task_groups, :through => :task_group_members, :conditions => { :type => 'ForemanTasks::TaskGroups::RecurringLogicTaskGroup' }, :source => :task_group
20
20
  has_many :owners, :through => :locks, :source => :resource, :source_type => 'User',
21
- :conditions => ["foreman_tasks_locks.name = ?", Lock::OWNER_LOCK_NAME]
21
+ :conditions => ['foreman_tasks_locks.name = ?', Lock::OWNER_LOCK_NAME]
22
22
  else
23
23
  has_many :recurring_logic_task_groups, -> { where :type => 'ForemanTasks::TaskGroups::RecurringLogicTaskGroup' },
24
24
  :through => :task_group_members, :source => :task_group
25
25
  # in fact, the task has only one owner but Rails don't let you to
26
26
  # specify has_one relation though has_many relation
27
- has_many :owners, lambda {where(["foreman_tasks_locks.name = ?", Lock::OWNER_LOCK_NAME])},
27
+ has_many :owners, -> { where(['foreman_tasks_locks.name = ?', Lock::OWNER_LOCK_NAME]) },
28
28
  :through => :locks, :source => :resource, :source_type => 'User'
29
29
  end
30
30
 
31
-
32
31
  scoped_search :on => :id, :complete_value => false
33
32
  scoped_search :on => :label, :complete_value => true
34
33
  scoped_search :on => :state, :complete_value => true
@@ -37,21 +36,26 @@ module ForemanTasks
37
36
  scoped_search :on => :start_at, :complete_value => false
38
37
  scoped_search :on => :ended_at, :complete_value => false
39
38
  scoped_search :on => :parent_task_id, :complete_value => true
40
- scoped_search :in => :locks, :on => :resource_type, :complete_value => true, :rename => "resource_type", :ext_method => :search_by_generic_resource
41
- scoped_search :in => :locks, :on => :resource_id, :complete_value => false, :rename => "resource_id", :ext_method => :search_by_generic_resource
42
- scoped_search :in => :owners, :on => :id, :complete_value => true, :rename => "owner.id", :ext_method => :search_by_owner
43
- scoped_search :in => :owners, :on => :login, :complete_value => true, :rename => "owner.login", :ext_method => :search_by_owner
44
- scoped_search :in => :owners, :on => :firstname, :complete_value => true, :rename => "owner.firstname", :ext_method => :search_by_owner
45
- scoped_search :in => :task_groups, :on => :id, :complete_value => true, :rename => "task_group.id"
39
+ scoped_search :relation => :locks, :on => :resource_type, :complete_value => true, :rename => 'resource_type', :ext_method => :search_by_generic_resource
40
+ scoped_search :relation => :locks, :on => :resource_id, :complete_value => false, :rename => 'resource_id', :ext_method => :search_by_generic_resource
41
+ scoped_search :relation => :owners,
42
+ :on => :id,
43
+ :complete_value => true,
44
+ :rename => 'owner.id',
45
+ :ext_method => :search_by_owner,
46
+ :validator => ->(value) { ScopedSearch::Validators::INTEGER.call(value) || value == 'current_user' }
47
+ scoped_search :relation => :owners, :on => :login, :complete_value => true, :rename => 'owner.login', :ext_method => :search_by_owner
48
+ scoped_search :relation => :owners, :on => :firstname, :complete_value => true, :rename => 'owner.firstname', :ext_method => :search_by_owner
49
+ scoped_search :relation => :task_groups, :on => :id, :complete_value => true, :rename => 'task_group.id', :validator => ScopedSearch::Validators::INTEGER
46
50
 
47
51
  scope :active, -> { where('foreman_tasks_tasks.state != ?', :stopped) }
48
- scope :running, -> { where("foreman_tasks_tasks.state NOT IN ('stopped', 'paused')") }
52
+ scope :running, -> { where("foreman_tasks_tasks.state NOT IN ('stopped', 'paused')") }
49
53
  scope :for_resource,
50
- (lambda do |resource|
51
- joins(:locks).where(:"foreman_tasks_locks.resource_id" => resource.id,
52
- :"foreman_tasks_locks.resource_type" => resource.class.name)
53
- end)
54
- scope :for_action_types, (lambda { |action_types| where('foreman_tasks_tasks.label IN (?)', Array(action_types)) })
54
+ (lambda do |resource|
55
+ joins(:locks).where(:"foreman_tasks_locks.resource_id" => resource.id,
56
+ :"foreman_tasks_locks.resource_type" => resource.class.name)
57
+ end)
58
+ scope :for_action_types, (->(action_types) { where('foreman_tasks_tasks.label IN (?)', Array(action_types)) })
55
59
 
56
60
  def input
57
61
  {}
@@ -62,61 +66,67 @@ module ForemanTasks
62
66
  end
63
67
 
64
68
  def owner
65
- self.owners.first
69
+ owners.first
66
70
  end
67
71
 
68
72
  def username
69
- self.owner.try(:login)
73
+ owner.try(:login)
70
74
  end
71
75
 
72
76
  def execution_type
73
- self.start_at.to_i == self.started_at.to_i ? N_('Immediate') : N_('Delayed')
77
+ delayed? ? N_('Delayed') : N_('Immediate')
74
78
  end
75
79
 
76
80
  def humanized
77
81
  { action: label,
78
- input: "",
79
- output: "" }
82
+ input: '',
83
+ output: '' }
80
84
  end
81
85
 
82
86
  def cli_example
83
- ""
87
+ ''
84
88
  end
85
89
 
86
90
  # returns true if the task is running or waiting to be run
87
91
  def pending?
88
- self.state != 'stopped'
92
+ state != 'stopped'
89
93
  end
90
- alias_method :pending, :pending?
94
+ alias pending pending?
91
95
 
92
96
  def resumable?
93
97
  false
94
98
  end
95
99
 
96
100
  def paused?
97
- self.state == 'paused'
101
+ state == 'paused'
102
+ end
103
+
104
+ def recurring?
105
+ !recurring_logic_task_group_ids.empty?
106
+ end
107
+
108
+ def delayed?
109
+ start_at.to_i != started_at.to_i
98
110
  end
99
111
 
100
112
  def self_and_parents
101
113
  [self].tap do |ret|
102
- if parent_task
103
- ret.concat(parent_task.self_and_parents)
104
- end
114
+ ret.concat(parent_task.self_and_parents) if parent_task
105
115
  end
106
116
  end
107
117
 
108
118
  def self.search_by_generic_resource(key, operator, value)
109
- key = "resource_type" if key.blank?
110
- key_name = self.connection.quote_column_name(key.sub(/^.*\./,''))
119
+ key = 'resource_type' if key.blank?
120
+ key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
111
121
  condition = sanitize_sql_for_conditions(["foreman_tasks_locks.#{key_name} #{operator} ?", value])
112
122
 
113
- return {:conditions => condition, :joins => :locks }
123
+ { :conditions => condition, :joins => :locks }
114
124
  end
115
125
 
116
126
  def self.search_by_owner(key, operator, value)
117
127
  return { :conditions => '0 = 1' } if value == 'current_user' && User.current.nil?
118
128
 
119
- key_name = self.connection.quote_column_name(key.sub(/^.*\./,''))
129
+ key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
120
130
  joins = <<-SQL
121
131
  INNER JOIN foreman_tasks_locks AS foreman_tasks_locks_owner
122
132
  ON (foreman_tasks_locks_owner.task_id = foreman_tasks_tasks.id AND
@@ -132,21 +142,19 @@ module ForemanTasks
132
142
  condition = if key.blank?
133
143
  sanitize_sql_for_conditions(["users.login #{operator} ? or users.firstname #{operator} ? ", value, value])
134
144
  elsif key =~ /\.id\Z/
135
- if value == 'current_user'
136
- value = User.current.id
137
- end
145
+ value = User.current.id if value == 'current_user'
138
146
  sanitize_sql_for_conditions(["foreman_tasks_locks_owner.resource_id #{operator} ?", value])
139
147
  else
140
148
  sanitize_sql_for_conditions(["users.#{key_name} #{operator} ?", value])
141
149
  end
142
- return {:conditions => condition, :joins => joins }
150
+ { :conditions => condition, :joins => joins }
143
151
  end
144
152
 
145
153
  def progress
146
- case self.state.to_s
147
- when "running", "paused"
154
+ case state.to_s
155
+ when 'running', 'paused'
148
156
  0.5
149
- when "stopped"
157
+ when 'stopped'
150
158
  1
151
159
  else
152
160
  0
@@ -163,6 +171,24 @@ module ForemanTasks
163
171
  (groups - task_groups).each { |group| task_groups << group }
164
172
  end
165
173
 
174
+ def sub_tasks_counts
175
+ result = %w(cancelled error pending success warning).zip([0].cycle).to_h
176
+ result.update sub_tasks.group(:result).count
177
+ sum = result.values.reduce(:+)
178
+ if respond_to?(:main_action) && main_action.respond_to?(:total_count)
179
+ result[:total] = main_action.total_count
180
+ # In case of batch planning there might be some plans still unplanned (not present in database).
181
+ # To get correct counts we need to add them to either:
182
+ # cancelled when the parent is stopped
183
+ # pending when the parent is still running.
184
+ key = state == 'stopped' ? 'cancelled' : 'pending'
185
+ result[key] += result[:total] - sum
186
+ else
187
+ result[:total] = sum
188
+ end
189
+ result.symbolize_keys
190
+ end
191
+
166
192
  protected
167
193
 
168
194
  def generate_id