foreman-tasks 8.0.2 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/lib/actions/check_long_running_tasks.rb +45 -0
- data/app/lib/actions/deliver_long_running_tasks_notification.rb +22 -0
- data/app/mailers/tasks_mailer.rb +12 -0
- data/app/models/foreman_tasks/tasks_mail_notification.rb +9 -0
- data/app/services/ui_notifications/tasks/tasks_running_long.rb +33 -0
- data/app/views/tasks_mailer/long_tasks.html.erb +29 -0
- data/app/views/tasks_mailer/long_tasks.text.erb +16 -0
- data/db/seeds.d/30-notification_blueprints.rb +7 -0
- data/db/seeds.d/95-mail_notifications.rb +24 -0
- data/lib/foreman_tasks/engine.rb +2 -1
- data/lib/foreman_tasks/tasks/reschedule_long_running_tasks_checker.rake +21 -0
- data/lib/foreman_tasks/version.rb +1 -1
- data/lib/foreman_tasks.rb +16 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cbc85cc5038629927d1204242995f7a8ffa0074caaa56fcc7886f6f2093dff1
|
4
|
+
data.tar.gz: 4f848db967c1791278c0fc9cebe3ddaa3a7fd3500208995ae84289496710db4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba8c8768bdaef20f5750b1052e9d43b525fee4260c81c0e61e0847cab958fc534129065d24f556920f2f5270fd8aad7192f808e60ee5fd693eedb54b8afdb77c
|
7
|
+
data.tar.gz: 0e8628e1db3a0a7fb800ae92fc722d7c7af1feaf9cebf659117f08686f0dae70f376ffe7236a7a99b2c6d1e20ed47e40194f52d37a3b5b0a653a23879460738e
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Actions
|
2
|
+
class CheckLongRunningTasks < ::Actions::EntryAction
|
3
|
+
include Actions::RecurringAction
|
4
|
+
|
5
|
+
INTERVAL = 2.days
|
6
|
+
STATES = ['running', 'paused'].freeze
|
7
|
+
|
8
|
+
def plan
|
9
|
+
time = Time.now.utc
|
10
|
+
cutoff = time - INTERVAL
|
11
|
+
notification = ::ForemanTasks::TasksMailNotification.find_by(name: "long_running_tasks")
|
12
|
+
org_admin_role = Role.find_by(name: 'Organization admin')
|
13
|
+
users = User.left_joins(:roles)
|
14
|
+
.where(id: UserMailNotification.where(mail_notification_id: notification.id).select(:host_id))
|
15
|
+
.or(User.where(admin: true))
|
16
|
+
.or(User.where(id: UserRole.where(id: [org_admin_role.id] + org_admin_role.cloned_role_ids).select(:owner_id)))
|
17
|
+
|
18
|
+
query = "state ^ (#{STATES.join(', ')}) AND state_updated_at <= \"#{cutoff}\""
|
19
|
+
users.each do |user|
|
20
|
+
User.as(user) do
|
21
|
+
tasks = ForemanTasks::Task.authorized
|
22
|
+
.search_for(query)
|
23
|
+
.select(:id)
|
24
|
+
.pluck(:id)
|
25
|
+
plan_action(DeliverLongRunningTasksNotification,
|
26
|
+
OpenStruct.new(
|
27
|
+
user_id: User.current.id,
|
28
|
+
time: time,
|
29
|
+
interval: INTERVAL,
|
30
|
+
states: STATES,
|
31
|
+
task_uuids: tasks,
|
32
|
+
query: query,
|
33
|
+
# Non serializable fields
|
34
|
+
user: nil,
|
35
|
+
tasks: nil
|
36
|
+
))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def humanized_name
|
42
|
+
_('Check for long running tasks')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Actions
|
2
|
+
class DeliverLongRunningTasksNotification < EntryAction
|
3
|
+
def plan(report)
|
4
|
+
return if report.task_uuids.empty?
|
5
|
+
|
6
|
+
plan_self report: report
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
report = OpenStruct.new(input[:report])
|
11
|
+
tasks = ForemanTasks::Task.where(id: report.task_uuids)
|
12
|
+
report.user = User.current
|
13
|
+
report.tasks = tasks
|
14
|
+
::UINotifications::Tasks::TasksRunningLong.new.deliver!
|
15
|
+
TasksMailer.long_tasks(report).deliver_now
|
16
|
+
end
|
17
|
+
|
18
|
+
def humanized_name
|
19
|
+
_('Deliver notifications about long running tasks')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class TasksMailer < ApplicationMailer
|
2
|
+
helper ApplicationHelper
|
3
|
+
|
4
|
+
def long_tasks(report, opts = {})
|
5
|
+
return if report.tasks.empty?
|
6
|
+
|
7
|
+
@report = report
|
8
|
+
@subject = opts[:subject]
|
9
|
+
@subject ||= _('Tasks pending since %s') % (@report.time - @report.interval)
|
10
|
+
mail(to: report.user.mail, subject: @subject)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class TasksRunningLong < Tasks::Base
|
4
|
+
include Rails.application.routes.url_helpers
|
5
|
+
|
6
|
+
def deliver!
|
7
|
+
notification = ::Notification.new(
|
8
|
+
:audience => Notification::AUDIENCE_GLOBAL,
|
9
|
+
:notification_blueprint => blueprint,
|
10
|
+
:initiator => initiator,
|
11
|
+
:message => message,
|
12
|
+
:subject => nil,
|
13
|
+
:notification_recipients => [NotificationRecipient.create(:user => User.current)]
|
14
|
+
)
|
15
|
+
notification.actions['links'] ||= []
|
16
|
+
notification.actions['links'] << {
|
17
|
+
href: foreman_tasks_tasks_path(search: subject.query),
|
18
|
+
title: N_('Long running tasks'),
|
19
|
+
}
|
20
|
+
notification.save!
|
21
|
+
notification
|
22
|
+
end
|
23
|
+
|
24
|
+
def blueprint
|
25
|
+
@blueprint ||= NotificationBlueprint.unscoped.find_by(:name => 'tasks_running_long')
|
26
|
+
end
|
27
|
+
|
28
|
+
def message
|
29
|
+
_("%{count} tasks are in running or paused state for more than a day") % { count: subject.task_uuids.count }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<p>
|
2
|
+
<%= _("Tasks lingering in states %{states} since %{time}") % {
|
3
|
+
time: @report.time - @report.interval,
|
4
|
+
states: @report.states.join(', ')
|
5
|
+
} %>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<div class="dashboard">
|
9
|
+
<table>
|
10
|
+
<tr>
|
11
|
+
<th>_("ID")</th>
|
12
|
+
<th>_("Action")</th>
|
13
|
+
<th>_("Label")</th>
|
14
|
+
<th>_("State")</th>
|
15
|
+
<th>_("State updated at")</th>
|
16
|
+
</tr>
|
17
|
+
<% @report.tasks.each do |task| %>
|
18
|
+
<tr>
|
19
|
+
<td><%= link_to task.id, foreman_tasks_task_url(task) %></td>
|
20
|
+
<td><%= task.action %></td>
|
21
|
+
<td><%= task.label %></td>
|
22
|
+
<td><%= task.state %></td>
|
23
|
+
<td><%= task.state_updated_at %></td>
|
24
|
+
</tr>
|
25
|
+
<% end %>
|
26
|
+
</table>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<%= link_to 'More details', foreman_tasks_tasks_url(search: @report.query) %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%= _("Tasks lingering in states %{states} since %{time}") % {
|
2
|
+
time: @report.time - @report.interval,
|
3
|
+
states: @report.states.join(', ')
|
4
|
+
} %>
|
5
|
+
|
6
|
+
More details: <%= foreman_tasks_tasks_url(search: @report.query) %>
|
7
|
+
|
8
|
+
<% @report.tasks.each do |task| %>
|
9
|
+
ID: <%= task.id %>
|
10
|
+
Action: <%= task.action %>
|
11
|
+
Label: <%= task.label %>
|
12
|
+
State: <%= task.state %>
|
13
|
+
State updated at: <%= task.state_updated_at %>
|
14
|
+
Details: <%= foreman_tasks_task_url(task) %>
|
15
|
+
|
16
|
+
<% end %>
|
@@ -49,6 +49,13 @@ blueprints = [
|
|
49
49
|
level: 'info',
|
50
50
|
message: "DYNAMIC",
|
51
51
|
},
|
52
|
+
|
53
|
+
{
|
54
|
+
group: N_('Tasks'),
|
55
|
+
name: 'tasks_running_long',
|
56
|
+
message: 'DYNAMIC',
|
57
|
+
level: 'warning',
|
58
|
+
},
|
52
59
|
]
|
53
60
|
|
54
61
|
blueprints.each { |blueprint| UINotifications::Seed.new(blueprint).configure }
|
@@ -0,0 +1,24 @@
|
|
1
|
+
N_('Long running tasks')
|
2
|
+
|
3
|
+
notifications = [
|
4
|
+
{
|
5
|
+
:name => 'long_running_tasks',
|
6
|
+
:description => N_('A notification when tasks run for suspiciously long time'),
|
7
|
+
:mailer => 'TasksMailer',
|
8
|
+
:method => 'long_tasks',
|
9
|
+
:subscription_type => 'alert',
|
10
|
+
},
|
11
|
+
]
|
12
|
+
|
13
|
+
notifications.each do |notification|
|
14
|
+
if (mail = ForemanTasks::TasksMailNotification.find_by(name: notification[:name]))
|
15
|
+
mail.attributes = notification
|
16
|
+
mail.save! if mail.changed?
|
17
|
+
else
|
18
|
+
created_notification = ForemanTasks::TasksMailNotification.create(notification)
|
19
|
+
if created_notification.nil? || created_notification.errors.any?
|
20
|
+
raise ::Foreman::Exception.new(N_("Unable to create mail notification: %s"),
|
21
|
+
SeedHelper.format_errors(created_notification))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/foreman_tasks/engine.rb
CHANGED
@@ -162,6 +162,7 @@ module ForemanTasks
|
|
162
162
|
world.middleware.use Actions::Middleware::KeepCurrentTimezone
|
163
163
|
world.middleware.use Actions::Middleware::KeepCurrentRequestID
|
164
164
|
world.middleware.use ::Actions::Middleware::LoadSettingValues
|
165
|
+
ForemanTasks.register_scheduled_task(Actions::CheckLongRunningTasks, ENV['FOREMAN_TASKS_CHECK_LONG_RUNNING_TASKS_CRONLINE'] || '0 0 * * *')
|
165
166
|
end
|
166
167
|
::ForemanTasks.dynflow.config.on_init(true) do
|
167
168
|
::ForemanTasks::Task::DynflowTask.consistency_check
|
@@ -186,7 +187,7 @@ module ForemanTasks
|
|
186
187
|
end
|
187
188
|
|
188
189
|
rake_tasks do
|
189
|
-
%w[dynflow.rake test.rake export_tasks.rake cleanup.rake generate_task_actions.rake].each do |rake_file|
|
190
|
+
%w[dynflow.rake test.rake export_tasks.rake cleanup.rake generate_task_actions.rake reschedule_long_running_tasks_checker.rake].each do |rake_file|
|
190
191
|
full_path = File.expand_path("../tasks/#{rake_file}", __FILE__)
|
191
192
|
load full_path if File.exist?(full_path)
|
192
193
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :foreman_tasks do
|
2
|
+
desc <<~DESC
|
3
|
+
Reschedules the long running task checker recurring logic to run at a different schedule. ENV variables:
|
4
|
+
|
5
|
+
* FOREMAN_TASKS_CHECK_LONG_RUNNING_TASKS_CRONLINE : A cron line describing the schedule, defaults to 0 0 * * *
|
6
|
+
DESC
|
7
|
+
task :reschedule_long_running_tasks_checker => ['environment', 'dynflow:client'] do
|
8
|
+
User.as_anonymous_admin do
|
9
|
+
task_class = Actions::CheckLongRunningTasks
|
10
|
+
cronline = ENV['FOREMAN_TASKS_CHECK_LONG_RUNNING_TASKS_CRONLINE'] || '0 0 * * *'
|
11
|
+
rl = ForemanTasks::RecurringLogic.joins(:tasks)
|
12
|
+
.where(state: 'active')
|
13
|
+
.merge(ForemanTasks::Task.where(label: task_class.name))
|
14
|
+
.first
|
15
|
+
if rl&.cron_line != cronline
|
16
|
+
rl.cancel
|
17
|
+
ForemanTasks.register_scheduled_task(task_class, cronline)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/foreman_tasks.rb
CHANGED
@@ -61,4 +61,20 @@ module ForemanTasks
|
|
61
61
|
result = dynflow.world.delay action, delay_options, *args
|
62
62
|
ForemanTasks::Task::DynflowTask.where(:external_id => result.id).first!
|
63
63
|
end
|
64
|
+
|
65
|
+
def self.register_scheduled_task(task_class, cronline)
|
66
|
+
ForemanTasks::RecurringLogic.transaction(isolation: :serializable) do
|
67
|
+
return if ForemanTasks::RecurringLogic.joins(:tasks)
|
68
|
+
.where(state: 'active')
|
69
|
+
.merge(ForemanTasks::Task.where(label: task_class.name))
|
70
|
+
.exists?
|
71
|
+
|
72
|
+
User.as_anonymous_admin do
|
73
|
+
recurring_logic = ForemanTasks::RecurringLogic.new_from_cronline(cronline)
|
74
|
+
recurring_logic.save!
|
75
|
+
recurring_logic.start(task_class)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
rescue ActiveRecord::TransactionIsolationError # rubocop:disable Lint/SuppressedException
|
79
|
+
end
|
64
80
|
end
|
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: 8.0
|
4
|
+
version: 8.1.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: 2023-
|
11
|
+
date: 2023-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -153,6 +153,8 @@ files:
|
|
153
153
|
- app/lib/actions/action_with_sub_plans.rb
|
154
154
|
- app/lib/actions/base.rb
|
155
155
|
- app/lib/actions/bulk_action.rb
|
156
|
+
- app/lib/actions/check_long_running_tasks.rb
|
157
|
+
- app/lib/actions/deliver_long_running_tasks_notification.rb
|
156
158
|
- app/lib/actions/entry_action.rb
|
157
159
|
- app/lib/actions/foreman/host/import_facts.rb
|
158
160
|
- app/lib/actions/foreman/puppetclass/import.rb
|
@@ -181,6 +183,7 @@ files:
|
|
181
183
|
- app/lib/actions/trigger_proxy_batch.rb
|
182
184
|
- app/lib/foreman_tasks/concerns/polling_action_extensions.rb
|
183
185
|
- app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb
|
186
|
+
- app/mailers/tasks_mailer.rb
|
184
187
|
- app/models/foreman_tasks/concerns/action_subject.rb
|
185
188
|
- app/models/foreman_tasks/concerns/action_triggering.rb
|
186
189
|
- app/models/foreman_tasks/concerns/host_action_subject.rb
|
@@ -199,6 +202,7 @@ files:
|
|
199
202
|
- app/models/foreman_tasks/task_group.rb
|
200
203
|
- app/models/foreman_tasks/task_group_member.rb
|
201
204
|
- app/models/foreman_tasks/task_groups/recurring_logic_task_group.rb
|
205
|
+
- app/models/foreman_tasks/tasks_mail_notification.rb
|
202
206
|
- app/models/foreman_tasks/triggering.rb
|
203
207
|
- app/services/foreman_tasks/proxy_selector.rb
|
204
208
|
- app/services/foreman_tasks/troubleshooting_help_generator.rb
|
@@ -208,6 +212,7 @@ files:
|
|
208
212
|
- app/services/ui_notifications/tasks/task_bulk_stop.rb
|
209
213
|
- app/services/ui_notifications/tasks/task_paused_admin.rb
|
210
214
|
- app/services/ui_notifications/tasks/task_paused_owner.rb
|
215
|
+
- app/services/ui_notifications/tasks/tasks_running_long.rb
|
211
216
|
- app/views/common/_trigger_form.html.erb
|
212
217
|
- app/views/foreman_tasks/api/locks/show.json.rabl
|
213
218
|
- app/views/foreman_tasks/api/recurring_logics/base.json.rabl
|
@@ -230,6 +235,8 @@ files:
|
|
230
235
|
- app/views/foreman_tasks/tasks/dashboard/_latest_tasks_in_error_warning.html.erb
|
231
236
|
- app/views/foreman_tasks/tasks/dashboard/_tasks_status.html.erb
|
232
237
|
- app/views/foreman_tasks/tasks/show.html.erb
|
238
|
+
- app/views/tasks_mailer/long_tasks.html.erb
|
239
|
+
- app/views/tasks_mailer/long_tasks.text.erb
|
233
240
|
- babel.config.js
|
234
241
|
- bin/dynflow-executor
|
235
242
|
- bin/foreman-tasks
|
@@ -268,6 +275,7 @@ files:
|
|
268
275
|
- db/seeds.d/30-notification_blueprints.rb
|
269
276
|
- db/seeds.d/60-dynflow_proxy_feature.rb
|
270
277
|
- db/seeds.d/61-foreman_tasks_bookmarks.rb
|
278
|
+
- db/seeds.d/95-mail_notifications.rb
|
271
279
|
- deploy/foreman-tasks.service
|
272
280
|
- deploy/foreman-tasks.sysconfig
|
273
281
|
- extra/dynflow-debug.sh
|
@@ -290,6 +298,7 @@ files:
|
|
290
298
|
- lib/foreman_tasks/tasks/dynflow.rake
|
291
299
|
- lib/foreman_tasks/tasks/export_tasks.rake
|
292
300
|
- lib/foreman_tasks/tasks/generate_task_actions.rake
|
301
|
+
- lib/foreman_tasks/tasks/reschedule_long_running_tasks_checker.rake
|
293
302
|
- lib/foreman_tasks/test_extensions.rb
|
294
303
|
- lib/foreman_tasks/test_helpers.rb
|
295
304
|
- lib/foreman_tasks/triggers.rb
|
@@ -633,7 +642,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
633
642
|
- !ruby/object:Gem::Version
|
634
643
|
version: '0'
|
635
644
|
requirements: []
|
636
|
-
rubygems_version: 3.4.
|
645
|
+
rubygems_version: 3.4.13
|
637
646
|
signing_key:
|
638
647
|
specification_version: 4
|
639
648
|
summary: Foreman plugin for showing tasks information for resources and users
|