foreman-tasks 8.0.2 → 8.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|