foreman-tasks 0.15.1 → 0.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.babelrc +9 -1
- data/.eslintrc +6 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +6 -0
- data/.storybook/webpack.config.js +51 -54
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +0 -2
- data/app/controllers/foreman_tasks/tasks_controller.rb +6 -1
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +8 -0
- data/app/lib/actions/base.rb +7 -0
- data/app/lib/actions/helpers/lifecycle_logging.rb +21 -0
- data/app/lib/actions/proxy_action.rb +4 -2
- data/app/models/foreman_tasks/task.rb +23 -0
- data/app/models/foreman_tasks/task/summarizer.rb +96 -6
- data/app/models/foreman_tasks/triggering.rb +2 -2
- data/app/models/setting/foreman_tasks.rb +8 -1
- data/app/services/foreman_tasks/dashboard_table_filter.rb +47 -0
- data/app/services/foreman_tasks/troubleshooting_help_generator.rb +92 -0
- data/app/services/ui_notifications/tasks.rb +20 -0
- data/app/services/ui_notifications/tasks/task_paused_admin.rb +43 -0
- data/app/services/ui_notifications/tasks/task_paused_owner.rb +30 -0
- data/app/views/foreman_tasks/tasks/_details.html.erb +5 -3
- data/app/views/foreman_tasks/tasks/index.html.erb +13 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20190318153925_add_task_state_updated_at.foreman_tasks.rb +5 -0
- data/db/migrate/20190404132157_add_implicit_varchar_uuid_cast.rb +25 -0
- data/db/seeds.d/30-notification_blueprints.rb +33 -0
- data/foreman-tasks.gemspec +1 -1
- data/lib/foreman_tasks/cleaner.rb +5 -4
- data/lib/foreman_tasks/engine.rb +1 -1
- data/lib/foreman_tasks/test_helpers.rb +10 -0
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +14 -11
- data/test/controllers/tasks_controller_test.rb +10 -0
- data/test/foreman_tasks_test_helper.rb +4 -0
- data/test/support/dummy_dynflow_action.rb +29 -0
- data/test/support/history_tasks_builder.rb +42 -0
- data/test/unit/actions/action_with_sub_plans_test.rb +4 -1
- data/test/unit/actions/bulk_action_test.rb +2 -0
- data/test/unit/cleaner_test.rb +15 -0
- data/test/unit/dashboard_table_filter_test.rb +65 -0
- data/test/unit/summarizer_test.rb +39 -0
- data/test/unit/task_test.rb +14 -0
- data/test/unit/troubleshooting_help_generator_test.rb +71 -0
- data/test/unit/ui_notifications_test.rb +86 -0
- data/webpack/ForemanTasks/Components/Chart/Chart.js +128 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.js +20 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.stories.js +51 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js +11 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +36 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.js +20 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.stories.js +51 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js +11 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +36 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +64 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +25 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.stories.js +28 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js +18 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +94 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +89 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +46 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.stories.js +72 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +48 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardHelper.js +63 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +973 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +96 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +17 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.stories.js +46 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js +43 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/__snapshots__/TasksDonutCard.test.js.snap +183 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.js +166 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.scss +24 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.stories.js +25 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js +40 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartConstants.js +13 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.js +94 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.test.js +152 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChart.test.js.snap +302 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChartHelper.test.js.snap +21 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.fixtures.js +25 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.js +72 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.stories.js +52 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js +21 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +223 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.js +57 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss +26 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.stories.js +22 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.test.js +57 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/__snapshots__/TasksLabelsRow.test.js.snap +47 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.js +51 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.stories.js +23 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js +19 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/__snapshots__/TimeDropDown.test.js.snap +85 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.js +33 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.scss +11 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.stories.js +22 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.test.js +15 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/__snapshots__/TasksTimeRow.test.js.snap +41 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.js +77 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.scss +6 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +62 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +94 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +78 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardPropTypes.js +13 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardReducer.js +50 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardSelectors.js +44 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboard.test.js +13 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardActions.test.js +37 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardHelper.test.js +36 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardReducer.test.js +58 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test..js +59 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboard.test.js.snap +51 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardActions.test.js.snap +61 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardReducer.test.js.snap +280 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/index.js +25 -0
- data/webpack/ForemanTasks/ForemanTasksReducers.js +10 -0
- data/webpack/ForemanTasks/ForemanTasksSelectors.js +1 -0
- data/webpack/__mocks__/foremanReact/API.js +7 -0
- data/webpack/__mocks__/foremanReact/common/I18n.js +5 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +3 -0
- data/webpack/index.js +13 -1
- data/webpack/stories/decorators/index.js +1 -0
- data/webpack/stories/decorators/withCardsDecorator.js +14 -0
- data/webpack/stories/index.js +1 -3
- data/webpack/stories/index.scss +6 -0
- metadata +101 -8
- data/webpack/ForemanTasks/components/Hello/Hello.stories.js +0 -5
- data/webpack/ForemanTasks/components/Hello/__tests__/Hello.test.js +0 -11
- data/webpack/ForemanTasks/components/Hello/__tests__/__snapshots__/Hello.test.js.snap +0 -7
- data/webpack/ForemanTasks/components/Hello/index.js +0 -5
@@ -18,8 +18,8 @@ module ForemanTasks
|
|
18
18
|
ALLOWED_INPUT_TYPES = [:cronline, :monthly, :weekly, :daily, :hourly].freeze
|
19
19
|
|
20
20
|
TIME_FORMAT = '%Y-%m-%d %H:%M'.freeze
|
21
|
-
TIME_REGEXP = /\A\d{4}-\d{2}-\d{2} \d{2}:\d{2}\Z
|
22
|
-
DAYS_REGEXP = /\A(\s*\d{1,2}\s*)(,\s*\d{1,2}\s*)*\Z
|
21
|
+
TIME_REGEXP = /\A\d{4}-\d{2}-\d{2} \d{2}:\d{2}\Z/.freeze
|
22
|
+
DAYS_REGEXP = /\A(\s*\d{1,2}\s*)(,\s*\d{1,2}\s*)*\Z/.freeze
|
23
23
|
|
24
24
|
has_one :recurring_logic, :foreign_key => :triggering_id, :dependent => :nullify
|
25
25
|
|
@@ -3,6 +3,8 @@ class Setting::ForemanTasks < Setting
|
|
3
3
|
# Check the table exists
|
4
4
|
return unless super
|
5
5
|
|
6
|
+
Setting::BLANK_ATTRS.push('foreman_tasks_troubleshooting_url')
|
7
|
+
|
6
8
|
transaction do
|
7
9
|
[
|
8
10
|
set('foreman_tasks_sync_task_timeout', N_('Number of seconds to wait for synchronous task to finish.'), 120),
|
@@ -12,7 +14,12 @@ class Setting::ForemanTasks < Setting
|
|
12
14
|
set('foreman_tasks_proxy_action_retry_count', N_('Number of attempts to start a task on the smart proxy before failing'), 4),
|
13
15
|
set('foreman_tasks_proxy_action_retry_interval', N_('Time in seconds between retries'), 15),
|
14
16
|
set('foreman_tasks_proxy_batch_trigger', N_('Allow triggering tasks on the smart proxy in batches'), true),
|
15
|
-
set('foreman_tasks_proxy_batch_size', N_('Number of tasks which should be sent to the smart proxy in one request, if foreman_tasks_proxy_batch_trigger is enabled'),
|
17
|
+
set('foreman_tasks_proxy_batch_size', N_('Number of tasks which should be sent to the smart proxy in one request, if foreman_tasks_proxy_batch_trigger is enabled'), 100),
|
18
|
+
set('foreman_tasks_troubleshooting_url',
|
19
|
+
N_('Url pointing to the task troubleshooting documentation. '\
|
20
|
+
'It should contain %{label} placeholder, that will be replaced with normalized task label '\
|
21
|
+
'(restricted to only alphanumeric characters)). %{version} placeholder is also available.'),
|
22
|
+
nil)
|
16
23
|
].each { |s| create! s.update(:category => 'Setting::ForemanTasks') }
|
17
24
|
end
|
18
25
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
# narrows the scope for the tasks table based on params coming from tasks dashboard
|
3
|
+
#
|
4
|
+
# Supported filters:
|
5
|
+
#
|
6
|
+
# * :result
|
7
|
+
# * :state
|
8
|
+
# * :time_horizon - expected format of Hxy, where the xy is the time horizon in hours we're interested in
|
9
|
+
# :time_mode can be set to 'recent' to filter the recent tasks, or 'older' (default) to filter earlier ones
|
10
|
+
class DashboardTableFilter
|
11
|
+
def initialize(scope, params)
|
12
|
+
@scope = scope
|
13
|
+
@params = params
|
14
|
+
end
|
15
|
+
|
16
|
+
def scope
|
17
|
+
@new_scope = @scope
|
18
|
+
scope_by(:result)
|
19
|
+
scope_by(:state)
|
20
|
+
scope_by_time
|
21
|
+
@new_scope
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def scope_by(field)
|
27
|
+
@new_scope = @new_scope.where(field => @params[field]) if @params[field].present?
|
28
|
+
end
|
29
|
+
|
30
|
+
def scope_by_time
|
31
|
+
return if @params[:time_horizon].blank?
|
32
|
+
hours = @params[:time_horizon][/\AH(\d{1,2})$/i, 1]
|
33
|
+
unless hours
|
34
|
+
raise Foreman::Exception, 'Unexpected format of time: should be in form of "H24"'
|
35
|
+
end
|
36
|
+
timestamp = Time.now.utc - hours.to_i.hours
|
37
|
+
case @params[:time_mode]
|
38
|
+
when 'recent'
|
39
|
+
operator = '>'
|
40
|
+
else
|
41
|
+
operator = '<'
|
42
|
+
search_suffix = 'OR state_updated_at IS NULL'
|
43
|
+
end
|
44
|
+
@new_scope = @new_scope.where("state_updated_at #{operator} ? #{search_suffix}", timestamp)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
class TroubleshootingHelpGenerator
|
3
|
+
class Link
|
4
|
+
attr_accessor :name, :title, :description, :href
|
5
|
+
|
6
|
+
def initialize(name:, title:, description:, href:)
|
7
|
+
@name = name
|
8
|
+
@title = title
|
9
|
+
@description = description
|
10
|
+
@href = href
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h(capitalize_title: false)
|
14
|
+
title = capitalize_title ? self.title.titlecase : self.title
|
15
|
+
{ name: name, title: title, description: description, href: href, external: true }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Info
|
20
|
+
attr_reader :links, :description_lines
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@description_lines = []
|
24
|
+
@links = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_line(line)
|
28
|
+
@description_lines << line
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_link(link)
|
32
|
+
@links << link
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(action)
|
37
|
+
@action = action
|
38
|
+
@custom_info = action.troubleshooting_info if action.respond_to?(:troubleshooting_info)
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_html
|
42
|
+
# rubocop:disable Rails/OutputSafety
|
43
|
+
(description + link_descriptions_html).join('<br/>').html_safe
|
44
|
+
# rubocop:enable Rails/OutputSafety
|
45
|
+
end
|
46
|
+
|
47
|
+
def link_descriptions_html
|
48
|
+
links.map do |link|
|
49
|
+
link.description % { link: %(<a href="%{href}">%{title}</a>) % link.to_h }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def description
|
54
|
+
ret = generic_info.description_lines
|
55
|
+
ret += @custom_info.description_lines if @custom_info
|
56
|
+
ret
|
57
|
+
end
|
58
|
+
|
59
|
+
def links
|
60
|
+
links = generic_info.links
|
61
|
+
links += @custom_info.links if @custom_info
|
62
|
+
links
|
63
|
+
end
|
64
|
+
|
65
|
+
def generic_info
|
66
|
+
@generic_info ||= Info.new.tap do |i|
|
67
|
+
i.add_line _('A paused task represents a process that has not finished properly. '\
|
68
|
+
'Any task in paused state can lead to potential inconsistency '\
|
69
|
+
'and needs to be resolved.')
|
70
|
+
i.add_line _("The recommended approach is to investigate the error messages below and in 'errors' tab, "\
|
71
|
+
'address the primary cause of the issue and resume the task.')
|
72
|
+
if (link = troubleshooting_link)
|
73
|
+
i.add_link(link)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def troubleshooting_link(generic_only: false)
|
79
|
+
url_template = Setting[:foreman_tasks_troubleshooting_url]
|
80
|
+
return if url_template.blank?
|
81
|
+
url = url_template % { label: generic_only ? '' : link_anchor, version: SETTINGS[:version].short }
|
82
|
+
Link.new(name: :troubleshooting,
|
83
|
+
title: _('troubleshooting documentation'),
|
84
|
+
description: _('See %{link} for more details on how to resolve the issue'),
|
85
|
+
href: url)
|
86
|
+
end
|
87
|
+
|
88
|
+
def link_anchor
|
89
|
+
@action.label.to_s
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class Base < ::UINotifications::Base
|
4
|
+
def initialize(task)
|
5
|
+
@subject = @task = task
|
6
|
+
end
|
7
|
+
|
8
|
+
def initiator
|
9
|
+
User.anonymous_admin
|
10
|
+
end
|
11
|
+
|
12
|
+
def troubleshooting_help_generator
|
13
|
+
return @troubleshooting_help_generator if defined? @troubleshooting_help_generator
|
14
|
+
@troubleshooting_help_generator = if @task.main_action
|
15
|
+
ForemanTasks::TroubleshootingHelpGenerator.new(@task.main_action)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class TaskPausedAdmin < Tasks::Base
|
4
|
+
def deliver!
|
5
|
+
# delete previous notifications about paused tasks first
|
6
|
+
Notification.where(notification_blueprint_id: blueprint.id).each(&:destroy)
|
7
|
+
notification = ::Notification.new(
|
8
|
+
:audience => Notification::AUDIENCE_ADMIN,
|
9
|
+
:notification_blueprint => blueprint,
|
10
|
+
:initiator => initiator,
|
11
|
+
:subject => subject,
|
12
|
+
:message => message
|
13
|
+
)
|
14
|
+
|
15
|
+
notification.send(:set_custom_attributes) # to add links from blueprint
|
16
|
+
notification.actions['links'] ||= []
|
17
|
+
if troubleshooting_help_generator
|
18
|
+
troubleshooting_link = troubleshooting_help_generator.troubleshooting_link(generic_only: true)
|
19
|
+
notification.actions['links'] << troubleshooting_link.to_h(capitalize_title: true) if troubleshooting_link
|
20
|
+
end
|
21
|
+
notification.save!
|
22
|
+
notification
|
23
|
+
end
|
24
|
+
|
25
|
+
def initiator
|
26
|
+
User.anonymous_admin
|
27
|
+
end
|
28
|
+
|
29
|
+
def blueprint
|
30
|
+
@blueprint ||= NotificationBlueprint.unscoped.find_by(:name => 'tasks_paused_admin')
|
31
|
+
end
|
32
|
+
|
33
|
+
def message
|
34
|
+
return @message if @message
|
35
|
+
|
36
|
+
tasks_count = ForemanTasks::Task.where(state: 'paused').count
|
37
|
+
@message = n_('There is %{count} paused task in the system that need attention',
|
38
|
+
'There are %{count} paused tasks in the system that need attention',
|
39
|
+
tasks_count) % { count: tasks_count }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class TaskPausedOwner < Tasks::Base
|
4
|
+
def deliver!
|
5
|
+
notification = ::Notification.new(
|
6
|
+
:audience => Notification::AUDIENCE_USER,
|
7
|
+
:notification_blueprint => blueprint,
|
8
|
+
:initiator => initiator,
|
9
|
+
:message => message,
|
10
|
+
:subject => subject
|
11
|
+
)
|
12
|
+
notification.send(:set_custom_attributes) # to add links from blueprint
|
13
|
+
notification.actions['links'] ||= []
|
14
|
+
if troubleshooting_help_generator
|
15
|
+
notification.actions['links'].concat(troubleshooting_help_generator.links.map { |l| l.to_h(capitalize_title: true) })
|
16
|
+
end
|
17
|
+
notification.save!
|
18
|
+
notification
|
19
|
+
end
|
20
|
+
|
21
|
+
def blueprint
|
22
|
+
@blueprint ||= NotificationBlueprint.unscoped.find_by(:name => 'tasks_paused_owner')
|
23
|
+
end
|
24
|
+
|
25
|
+
def message
|
26
|
+
StringParser.new(blueprint.message, subject: subject.action).to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -174,6 +174,8 @@
|
|
174
174
|
</div>
|
175
175
|
</div>
|
176
176
|
|
177
|
+
<%= troubleshooting_info %>
|
178
|
+
|
177
179
|
<% unless @task.humanized[:output].blank? %>
|
178
180
|
<div>
|
179
181
|
<span class="param-name list-group-item-heading"><%= _("Output") %>:</span>
|
@@ -184,10 +186,10 @@
|
|
184
186
|
<% end %>
|
185
187
|
|
186
188
|
<% unless @task.humanized[:errors].blank? %>
|
187
|
-
<
|
188
|
-
<span class="param-name"><%= _("Errors") %>:</span>
|
189
|
+
<p>
|
190
|
+
<span class="param-name"><b><%= _("Errors") %>:</b></span>
|
189
191
|
<span class="param-value">
|
190
192
|
<pre><%=Array(@task.humanized[:errors]).join("\n") %></pre>
|
191
193
|
</span>
|
192
|
-
</
|
194
|
+
</p>
|
193
195
|
<% end %>
|
@@ -1,3 +1,16 @@
|
|
1
|
+
<% content_for(:javascripts) do %>
|
2
|
+
<%= webpacked_plugins_js_for :'foreman-tasks' %>
|
3
|
+
<% end %>
|
4
|
+
<% content_for(:stylesheets) do %>
|
5
|
+
<%= webpacked_plugins_css_for :'foreman-tasks' %>
|
6
|
+
<% end %>
|
7
|
+
<% content_for(:before_search_bar) do %>
|
8
|
+
<div id="tasks-dashboard"></div>
|
9
|
+
<%= mount_react_component('TasksDashboard', '#tasks-dashboard', {
|
10
|
+
yo: 'ya'
|
11
|
+
}.to_json) %>
|
12
|
+
<% end %>
|
13
|
+
|
1
14
|
<% title _("Tasks") %>
|
2
15
|
<% title_actions csv_link, help_button %>
|
3
16
|
<% stylesheet 'foreman_tasks/tasks' %>
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
class AddImplicitVarcharUuidCast < ActiveRecord::Migration[5.2]
|
2
|
+
def up
|
3
|
+
if on_postgresql?
|
4
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
5
|
+
CREATE CAST (varchar AS uuid)
|
6
|
+
WITH INOUT
|
7
|
+
AS IMPLICIT
|
8
|
+
SQL
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def down
|
13
|
+
if on_postgresql?
|
14
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
15
|
+
DROP CAST (varchar AS uuid)
|
16
|
+
SQL
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def on_postgresql?
|
23
|
+
ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
blueprints = [
|
2
|
+
{
|
3
|
+
group: N_('Tasks'),
|
4
|
+
name: 'tasks_paused_admin',
|
5
|
+
message: "DYNAMIC",
|
6
|
+
level: 'warning',
|
7
|
+
actions:
|
8
|
+
{
|
9
|
+
links:
|
10
|
+
[
|
11
|
+
href: "/foreman_tasks/tasks?search=#{CGI.escape('state=paused')}",
|
12
|
+
title: N_('List of tasks')
|
13
|
+
]
|
14
|
+
}
|
15
|
+
},
|
16
|
+
|
17
|
+
{
|
18
|
+
group: N_('Tasks'),
|
19
|
+
name: 'tasks_paused_owner',
|
20
|
+
message: "The task '%{subject}' got paused",
|
21
|
+
level: 'warning',
|
22
|
+
actions:
|
23
|
+
{
|
24
|
+
links:
|
25
|
+
[
|
26
|
+
path_method: :foreman_tasks_task_path,
|
27
|
+
title: N_('Task Details')
|
28
|
+
]
|
29
|
+
}
|
30
|
+
}
|
31
|
+
]
|
32
|
+
|
33
|
+
blueprints.each { |blueprint| UINotifications::Seed.new(blueprint).configure }
|
data/foreman-tasks.gemspec
CHANGED
@@ -29,7 +29,7 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
|
|
29
29
|
s.extra_rdoc_files = Dir['README*', 'LICENSE']
|
30
30
|
|
31
31
|
s.add_dependency "foreman-tasks-core"
|
32
|
-
s.add_dependency "dynflow", '>= 1.2.
|
32
|
+
s.add_dependency "dynflow", '>= 1.2.3'
|
33
33
|
s.add_dependency "sinatra" # for Dynflow web console
|
34
34
|
s.add_dependency "parse-cron", '~> 0.1.4'
|
35
35
|
s.add_dependency "get_process_mem" # for memory polling
|
@@ -193,15 +193,16 @@ module ForemanTasks
|
|
193
193
|
|
194
194
|
def orphaned_dynflow_tasks
|
195
195
|
db = ForemanTasks.dynflow.world.persistence.adapter.db
|
196
|
-
|
197
|
-
|
196
|
+
db.fetch("select dynflow_execution_plans.uuid from dynflow_execution_plans left join "\
|
197
|
+
"foreman_tasks_tasks on (dynflow_execution_plans.uuid = foreman_tasks_tasks.external_id) "\
|
198
|
+
"where foreman_tasks_tasks.id IS NULL")
|
198
199
|
end
|
199
200
|
|
200
201
|
def prepare_filter
|
201
202
|
filter_parts = [filter]
|
202
203
|
filter_parts << %(started_at < "#{after.ago.to_s(:db)}") if after > 0
|
203
|
-
filter_parts <<
|
204
|
-
filter_parts.select(&:present?).join(' AND ')
|
204
|
+
filter_parts << "state ^ (#{states.join(',')})" if states.any?
|
205
|
+
filter_parts.select(&:present?).map { |segment| "(#{segment})" }.join(' AND ')
|
205
206
|
end
|
206
207
|
|
207
208
|
def start_tracking_progress(name, total = tasks.size)
|
data/lib/foreman_tasks/engine.rb
CHANGED
@@ -56,7 +56,7 @@ module ForemanTasks
|
|
56
56
|
:last => true
|
57
57
|
|
58
58
|
security_block :foreman_tasks do |_map|
|
59
|
-
permission :view_foreman_tasks, { :'foreman_tasks/tasks' => [:auto_complete_search, :sub_tasks, :index, :show],
|
59
|
+
permission :view_foreman_tasks, { :'foreman_tasks/tasks' => [:auto_complete_search, :sub_tasks, :index, :summary, :show],
|
60
60
|
:'foreman_tasks/react' => [:index],
|
61
61
|
:'foreman_tasks/api/tasks' => [:bulk_search, :show, :index, :summary] }, :resource_type => ForemanTasks::Task.name
|
62
62
|
permission :edit_foreman_tasks, { :'foreman_tasks/tasks' => [:resume, :unlock, :force_unlock, :cancel_step, :cancel, :abort],
|
@@ -1,9 +1,19 @@
|
|
1
1
|
require 'dynflow/testing'
|
2
2
|
module ForemanTasks
|
3
3
|
module TestHelpers
|
4
|
+
def self.use_in_memory_sqlite!
|
5
|
+
raise 'the in thread world have already been initialized' if @test_in_thread_world
|
6
|
+
@use_in_memory_sqlite = true
|
7
|
+
end
|
8
|
+
|
4
9
|
def self.test_in_thread_world
|
5
10
|
return @test_in_thread_world if @test_in_thread_world
|
6
11
|
world_config = ForemanTasks.dynflow.config.world_config
|
12
|
+
if @use_in_memory_sqlite
|
13
|
+
world_config.persistence_adapter = lambda do |*_args|
|
14
|
+
::ForemanTasks::Dynflow::Persistence.new('adapter' => 'sqlite', 'database' => ':memory:')
|
15
|
+
end
|
16
|
+
end
|
7
17
|
@test_in_thread_world = ::Dynflow::Testing::InThreadWorld.new(world_config)
|
8
18
|
end
|
9
19
|
|