rocketjob_mission_control 3.1.0 → 3.2.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.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -1
  3. data/app/controllers/rocket_job_mission_control/active_workers_controller.rb +1 -0
  4. data/app/controllers/rocket_job_mission_control/application_controller.rb +15 -2
  5. data/app/controllers/rocket_job_mission_control/dirmon_entries_controller.rb +19 -2
  6. data/app/controllers/rocket_job_mission_control/jobs_controller.rb +45 -17
  7. data/app/controllers/rocket_job_mission_control/servers_controller.rb +18 -2
  8. data/app/datatables/rocket_job_mission_control/abstract_datatable.rb +0 -1
  9. data/app/datatables/rocket_job_mission_control/jobs_datatable.rb +8 -6
  10. data/app/datatables/rocket_job_mission_control/servers_datatable.rb +20 -8
  11. data/app/models/rocket_job_mission_control/access_policy.rb +50 -0
  12. data/app/models/rocket_job_mission_control/authorization.rb +22 -0
  13. data/app/views/rocket_job_mission_control/dirmon_entries/_sidebar.html.erb +5 -2
  14. data/app/views/rocket_job_mission_control/dirmon_entries/show.html.erb +8 -2
  15. data/app/views/rocket_job_mission_control/jobs/show.html.erb +9 -5
  16. data/app/views/rocket_job_mission_control/servers/index.html.erb +10 -8
  17. data/lib/rocket_job_mission_control/engine.rb +9 -0
  18. data/lib/rocket_job_mission_control/version.rb +1 -1
  19. data/test/controllers/rocket_job_mission_control/dirmon_entries_controller_test.rb +78 -1
  20. data/test/controllers/rocket_job_mission_control/jobs_controller_test.rb +52 -1
  21. data/test/controllers/rocket_job_mission_control/servers_controller_test.rb +58 -1
  22. data/test/test_helper.rb +12 -10
  23. data/vendor/assets/stylesheets/{fontawesome-all.min.css → fontawesome-all.min.css.erb} +1 -1
  24. metadata +20 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c601ebf6d78762b41133227dedad5cf2279137fcfbd3dbbfbf68c551309101a
4
- data.tar.gz: d9631a241d9d50aaa95dc701406549133f25657368aa40b002955e63037350d8
3
+ metadata.gz: 04c47815b195983663c44887317137d965b99c5a9e30d40f3b8969585dc7465a
4
+ data.tar.gz: 789ee3b6b5d9e006f8fa20d310fed0c30ed23dc89353a507cb7a544cfdaf46e8
5
5
  SHA512:
6
- metadata.gz: 1e5aeb332d6983bb3290ceb0566a1edf07565423665a52e1db8cfd2b28445052bab50c4ac0a48d9dc0bc20acf19425179f96771f69b619b75b994be379d8cf95
7
- data.tar.gz: d7d7ee95bd05c7a5901ead43d8bfb10018750ed85b8fcc6bc72a66aef81dfa79a165975a88d6cad237b467f8a806f5f04f568fe8890678b284add102e5c62358
6
+ metadata.gz: 39413801aeb5be085f2f6ef7f7b9e44641efa786322126f34b9d05e5299ea149e92f5d6ef2d988521717d035d1a76bb300c5479ebf59a58441bb67212efd2621
7
+ data.tar.gz: 3f9e7b8308596809f4eeb73ed67da1f2fc0e65d879d7199f6f9d506acc2e33bfd7277a24cff3fb9b3a0706c940cfa7a0222acf4a22ecc13f8690c5ea3dea3672
data/Rakefile CHANGED
@@ -2,7 +2,9 @@
2
2
  require 'rubygems'
3
3
  require 'bundler/setup'
4
4
 
5
- APP_RAKEFILE = File.expand_path('../rjmc/Rakefile', __FILE__)
5
+ require 'rails/version'
6
+ rakefile = Rails.version.to_f >= 5.2 ? '../rjmc/Rakefile' : '../rjmc4/Rakefile'
7
+ APP_RAKEFILE = File.expand_path(rakefile, __FILE__)
6
8
  load 'rails/tasks/engine.rake'
7
9
 
8
10
  require 'rake/testtask'
@@ -1,6 +1,7 @@
1
1
  module RocketJobMissionControl
2
2
  class ActiveWorkersController < RocketJobMissionControl::ApplicationController
3
3
  def index
4
+ authorize! :read, RocketJob::Worker
4
5
  @server_name = params[:server_name]
5
6
  if job_id = params[:job_id]
6
7
  @job = RocketJob::Job.find(job_id)
@@ -6,10 +6,23 @@ module RocketJobMissionControl
6
6
 
7
7
  private
8
8
 
9
- def with_time_zone
9
+ def with_time_zone(&block)
10
10
  if time_zone = session['time_zone'] || 'UTC'
11
- Time.use_zone(time_zone) { yield }
11
+ Time.use_zone(time_zone, &block)
12
12
  end
13
13
  end
14
+
15
+ def current_policy
16
+ @current_policy ||= begin
17
+ args =
18
+ if Config.authorization_callback
19
+ instance_exec(&Config.authorization_callback)
20
+ else
21
+ {roles: %i[admin]}
22
+ end
23
+ AccessPolicy.new(Authorization.new(args))
24
+ end
25
+ end
26
+
14
27
  end
15
28
  end
@@ -1,13 +1,20 @@
1
1
  module RocketJobMissionControl
2
2
  class DirmonEntriesController < RocketJobMissionControl::ApplicationController
3
3
  if Rails.version.to_i < 5
4
- before_filter :find_entry_or_redirect, except: [:index, :disabled, :enabled, :failed, :pending, :new, :create]
4
+ before_filter :find_entry_or_redirect, except: %i[index disabled enabled failed pending new create]
5
+ before_filter :authorize_read, only: %i[index disabled enabled failed pending]
5
6
  before_filter :show_sidebar
6
7
  else
7
- before_action :find_entry_or_redirect, except: [:index, :disabled, :enabled, :failed, :pending, :new, :create]
8
+ before_action :find_entry_or_redirect, except: %i[index disabled enabled failed pending new create]
9
+ before_action :authorize_read, only: %i[index disabled enabled failed pending]
8
10
  before_action :show_sidebar
9
11
  end
10
12
 
13
+ rescue_from AccessGranted::AccessDenied do |exception|
14
+ raise exception if Rails.env.development? || Rails.env.test?
15
+ redirect_to :back, alert: 'Access not authorized.'
16
+ end
17
+
11
18
  def index
12
19
  @data_table_url = dirmon_entries_url(format: 'json')
13
20
  render_datatable(RocketJob::DirmonEntry.all, 'All')
@@ -46,6 +53,7 @@ module RocketJobMissionControl
46
53
  end
47
54
 
48
55
  def create
56
+ authorize! :create, RocketJob::DirmonEntry
49
57
  @dirmon_entry = RocketJob::DirmonEntry.new(dirmon_params)
50
58
  if properties = params[:rocket_job_dirmon_entry][:properties]
51
59
  @dirmon_entry.properties = JobSanitizer.sanitize(properties, @dirmon_entry.job_class, @dirmon_entry, false)
@@ -59,14 +67,17 @@ module RocketJobMissionControl
59
67
  end
60
68
 
61
69
  def destroy
70
+ authorize! :destroy, @dirmon_entry
62
71
  @dirmon_entry.destroy
63
72
  redirect_to(dirmon_entries_path)
64
73
  end
65
74
 
66
75
  def edit
76
+ authorize! :edit, @dirmon_entry
67
77
  end
68
78
 
69
79
  def update
80
+ authorize! :update, @dirmon_entry
70
81
  if properties = params[:rocket_job_dirmon_entry][:properties]
71
82
  @dirmon_entry.properties = JobSanitizer.sanitize(properties, @dirmon_entry.job_class, @dirmon_entry, false)
72
83
  end
@@ -78,6 +89,7 @@ module RocketJobMissionControl
78
89
  end
79
90
 
80
91
  def enable
92
+ authorize! :enable, @dirmon_entry
81
93
  if @dirmon_entry.may_enable?
82
94
  @dirmon_entry.enable!
83
95
  redirect_to(rocket_job_mission_control.dirmon_entry_path(@dirmon_entry))
@@ -88,6 +100,7 @@ module RocketJobMissionControl
88
100
  end
89
101
 
90
102
  def disable
103
+ authorize! :disable, @dirmon_entry
91
104
  if @dirmon_entry.may_disable?
92
105
  @dirmon_entry.disable!
93
106
  redirect_to(rocket_job_mission_control.dirmon_entry_path(@dirmon_entry))
@@ -104,6 +117,10 @@ module RocketJobMissionControl
104
117
 
105
118
  private
106
119
 
120
+ def authorize_read
121
+ authorize! :read, RocketJob::DirmonEntry
122
+ end
123
+
107
124
  def show_sidebar
108
125
  @dirmon_sidebar = true
109
126
  end
@@ -1,12 +1,15 @@
1
1
  module RocketJobMissionControl
2
2
  class JobsController < RocketJobMissionControl::ApplicationController
3
3
  if Rails.version.to_i < 5
4
- before_filter :find_job_or_redirect, except: [:index, :aborted, :completed, :failed, :paused, :queued, :running, :scheduled]
4
+ before_filter :find_job_or_redirect, except: %i[index aborted completed failed paused queued running scheduled]
5
+ before_filter :authorize_read, only: %i[index running paused completed aborted failed queued scheduled]
5
6
  before_filter :show_sidebar
6
7
  else
7
- before_action :find_job_or_redirect, except: [:index, :aborted, :completed, :failed, :paused, :queued, :running, :scheduled]
8
+ before_action :find_job_or_redirect, except: %i[index aborted completed failed paused queued running scheduled]
9
+ before_action :authorize_read, only: %i[index running paused completed aborted failed queued scheduled]
8
10
  before_action :show_sidebar
9
11
  end
12
+
10
13
  rescue_from StandardError, with: :error_occurred
11
14
 
12
15
  def index
@@ -17,10 +20,14 @@ module RocketJobMissionControl
17
20
  end
18
21
 
19
22
  def running
20
- jobs = RocketJob::Job.running.only(JobsDatatable::RUNNING_FIELDS)
23
+ # Prevent throttled jobs from displaying.
24
+ jobs = RocketJob::Job.
25
+ running.
26
+ where(:started_at.lte => (Time.now - 0.1)).
27
+ only(JobsDatatable::RUNNING_FIELDS)
21
28
  @data_table_url = running_jobs_url(format: 'json')
22
29
 
23
- render_datatable(jobs, 'Running', JobsDatatable::RUNNING_COLUMNS, started_at: :desc)
30
+ render_datatable(jobs, 'Running', JobsDatatable::RUNNING_COLUMNS, priority: :asc, created_at: :asc)
24
31
  end
25
32
 
26
33
  def paused
@@ -55,7 +62,7 @@ module RocketJobMissionControl
55
62
  jobs = RocketJob::Job.queued_now.only(JobsDatatable::QUEUED_FIELDS)
56
63
  @data_table_url = queued_jobs_url(format: 'json')
57
64
 
58
- render_datatable(jobs, 'Queued', JobsDatatable::QUEUED_COLUMNS, completed_at: :desc)
65
+ render_datatable(jobs, 'Queued', JobsDatatable::QUEUED_COLUMNS, priority: :asc, created_at: :asc)
59
66
  end
60
67
 
61
68
  def scheduled
@@ -66,6 +73,7 @@ module RocketJobMissionControl
66
73
  end
67
74
 
68
75
  def update
76
+ authorize! :update, @job
69
77
  permitted_params = JobSanitizer.sanitize(params[:job], @job.class, @job)
70
78
  if @job.errors.empty? && @job.valid? && @job.update_attributes(permitted_params)
71
79
  redirect_to job_path(@job)
@@ -75,64 +83,75 @@ module RocketJobMissionControl
75
83
  end
76
84
 
77
85
  def abort
86
+ authorize! :abort, @job
78
87
  @job.abort!
79
88
  redirect_to(job_path(@job))
80
89
  end
81
90
 
82
91
  def destroy
92
+ authorize! :destroy, @job
83
93
  @job.destroy
84
94
  redirect_to(jobs_path)
85
95
  end
86
96
 
87
97
  def retry
98
+ authorize! :retry, @job
88
99
  @job.retry!
89
100
  redirect_to(job_path(@job))
90
101
  end
91
102
 
92
103
  def pause
104
+ authorize! :pause, @job
93
105
  @job.pause!
94
106
  redirect_to(job_path(@job))
95
107
  end
96
108
 
97
109
  def resume
110
+ authorize! :resume, @job
98
111
  @job.resume!
99
112
  redirect_to(job_path(@job))
100
113
  end
101
114
 
102
115
  def run_now
116
+ authorize! :run_now, @job
103
117
  @job.unset(:run_at) if @job.scheduled?
104
118
  redirect_to(job_path(@job))
105
119
  end
106
120
 
107
121
  def fail
122
+ authorize! :fail, @job
108
123
  @job.fail!
109
124
 
110
125
  redirect_to(job_path(@job))
111
126
  end
112
127
 
113
128
  def show
129
+ authorize! :read, @job
114
130
  end
115
131
 
116
132
  def edit
133
+ authorize! :edit, @job
117
134
  end
118
135
 
119
136
  def exceptions
137
+ authorize! :read, @job
120
138
  @exceptions = @job.input.group_exceptions
121
139
  end
122
140
 
123
141
  def exception
142
+ authorize! :read, @job
124
143
  error_type = params[:error_type]
125
144
  offset = params.fetch(:offset, 0).to_i
126
145
 
127
146
  unless error_type.present?
128
- flash[:notice] = t(:no_errors, scope: [:job, :failures])
147
+ flash[:notice] = t(:no_errors, scope: %i[job failures])
129
148
  redirect_to(job_path(@job))
130
149
  end
131
150
 
132
151
  scope = @job.input.failed.where('exception.class_name' => error_type)
133
152
  count = scope.count
134
153
  unless count > 0
135
- flash[:notice] = t(:no_errors, scope: [:job, :failures])
154
+ flash[:notice] = t(:no_errors, scope: %i[job failures])
136
155
  redirect_to(job_path(@job))
137
156
  end
138
157
 
@@ -141,19 +160,23 @@ module RocketJobMissionControl
141
160
 
142
161
  @pagination = {
143
162
  offset: offset,
144
- total: (count - 1),
163
+ total: (count - 1)
145
164
  }
146
165
  end
147
166
 
148
167
  private
149
168
 
169
+ def authorize_read
170
+ authorize! :read, RocketJob::Job
171
+ end
172
+
150
173
  def show_sidebar
151
174
  @jobs_sidebar = true
152
175
  end
153
176
 
154
177
  def find_job_or_redirect
155
178
  unless @job = RocketJob::Job.where(id: params[:id]).first
156
- flash[:alert] = t(:failure, scope: [:job, :find], id: params[:id])
179
+ flash[:alert] = t(:failure, scope: %i[job find], id: params[:id])
157
180
 
158
181
  redirect_to(jobs_path)
159
182
  end
@@ -169,8 +192,14 @@ module RocketJobMissionControl
169
192
  else
170
193
  logger.error "Error loading a job. #{exception.class}: #{exception.message}\n#{(exception.backtrace || []).join("\n")}"
171
194
  end
172
- flash[:danger] = 'Error loading jobs.'
173
- raise exception if Rails.env.development? || Rails.env.test?
195
+
196
+ flash[:danger] = if exception.is_a?(AccessGranted::AccessDenied)
197
+ 'Access not authorized.'
198
+ else
199
+ 'Error loading jobs.'
200
+ end
201
+
202
+ raise exception if Rails.env.development? || Rails.env.test?
174
203
  redirect_to :back
175
204
  end
176
205
 
@@ -184,7 +213,7 @@ module RocketJobMissionControl
184
213
  end
185
214
  format.json do
186
215
  query = RocketJobMissionControl::Query.new(jobs, sort_order)
187
- query.search_columns = [:_type, :description]
216
+ query.search_columns = %i[_type description]
188
217
  query.display_columns = columns.collect { |c| c[:field] }.compact
189
218
  render(json: JobsDatatable.new(view_context, query, columns))
190
219
  end
@@ -194,13 +223,12 @@ module RocketJobMissionControl
194
223
  def build_table_layout(columns)
195
224
  index = 0
196
225
  columns.collect do |column|
197
- h = {data: index.to_s}
198
- h[:width] = column[:width] if column.has_key?(:width)
199
- h[:orderable] = column[:orderable] if column.has_key?(:orderable)
200
- index += 1
226
+ h = { data: index.to_s }
227
+ h[:width] = column[:width] if column.key?(:width)
228
+ h[:orderable] = column[:orderable] if column.key?(:orderable)
229
+ index += 1
201
230
  h
202
231
  end
203
232
  end
204
-
205
233
  end
206
234
  end
@@ -1,13 +1,20 @@
1
1
  module RocketJobMissionControl
2
2
  class ServersController < RocketJobMissionControl::ApplicationController
3
3
  if Rails.version.to_i < 5
4
- before_filter :find_server_or_redirect, only: [:stop, :pause, :resume, :destroy]
4
+ before_filter :find_server_or_redirect, only: %i[stop pause resume destroy]
5
+ before_filter :authorize_read, only: %i[index starting running paused stopping zombie]
5
6
  before_filter :show_sidebar
6
7
  else
7
- before_action :find_server_or_redirect, only: [:stop, :pause, :resume, :destroy]
8
+ before_action :find_server_or_redirect, only: %i[stop pause resume destroy]
9
+ before_action :authorize_read, only: %i[index starting running paused stopping zombie]
8
10
  before_action :show_sidebar
9
11
  end
10
12
 
13
+ rescue_from AccessGranted::AccessDenied do |exception|
14
+ raise exception if Rails.env.development? || Rails.env.test?
15
+ redirect_to :back, alert: 'Access not authorized.'
16
+ end
17
+
11
18
  def index
12
19
  @data_table_url = servers_url(format: 'json')
13
20
  @actions = [:pause_all, :resume_all, :stop_all, :destroy_zombies]
@@ -47,6 +54,7 @@ module RocketJobMissionControl
47
54
  VALID_ACTIONS = [:stop_all, :pause_all, :resume_all, :destroy_zombies]
48
55
 
49
56
  def update_all
57
+ authorize! :destroy, RocketJob::Server
50
58
  server_action = params[:server_action].to_sym
51
59
  if VALID_ACTIONS.include?(server_action)
52
60
  RocketJob::Server.public_send(server_action.to_sym)
@@ -61,6 +69,7 @@ module RocketJobMissionControl
61
69
  end
62
70
 
63
71
  def stop
72
+ authorize! :stop, @server
64
73
  if @server.may_stop?
65
74
  @server.stop!
66
75
  else
@@ -73,6 +82,7 @@ module RocketJobMissionControl
73
82
  end
74
83
 
75
84
  def destroy
85
+ authorize! :destroy, @server
76
86
  @server.destroy
77
87
  flash[:notice] = t(:success, scope: [:server, :destroy])
78
88
 
@@ -82,6 +92,7 @@ module RocketJobMissionControl
82
92
  end
83
93
 
84
94
  def pause
95
+ authorize! :pause, @server
85
96
  if @server.may_pause?
86
97
  @server.pause!
87
98
  else
@@ -94,6 +105,7 @@ module RocketJobMissionControl
94
105
  end
95
106
 
96
107
  def resume
108
+ authorize! :resume, @server
97
109
  if @server.may_resume?
98
110
  @server.resume!
99
111
  else
@@ -107,6 +119,10 @@ module RocketJobMissionControl
107
119
 
108
120
  private
109
121
 
122
+ def authorize_read
123
+ authorize! :read, RocketJob::Server
124
+ end
125
+
110
126
  def render_datatable(servers, description)
111
127
  respond_to do |format|
112
128
  format.html do
@@ -48,7 +48,6 @@ module RocketJobMissionControl
48
48
  def extract_sort(order)
49
49
  return nil unless order.present?
50
50
 
51
- ap order
52
51
  sort_by = {}
53
52
  order.each_pair do |key, value|
54
53
  name = query.display_columns[value[:column].to_i]
@@ -4,7 +4,7 @@ module RocketJobMissionControl
4
4
  :abort_job_path, :job_path, :fail_job_path, :run_now_job_path, :pause_job_path,
5
5
  :resume_job_path, :retry_job_path, :exception_job_path, :job_action_link, :exceptions_job_path, to: :@view
6
6
 
7
- COMMON_FIELDS = [:id, :_type, :description, :completed_at, :created_at, :started_at, :state, :worker_name].freeze
7
+ COMMON_FIELDS = [:id, :_type, :description, :completed_at, :created_at, :started_at, :state, :worker_name, :login].freeze
8
8
 
9
9
  ABORTED_COLUMNS = [
10
10
  {display: 'Class', value: :class_with_link, field: '_type', width: '30%'},
@@ -156,19 +156,21 @@ module RocketJobMissionControl
156
156
  def action_buttons(job)
157
157
  events = valid_events(job)
158
158
  buttons = "<div class='inline-job-actions'>"
159
- if job.scheduled?
159
+ if job.scheduled? && view.can?(:run_now, job)
160
160
  buttons += "#{ job_action_link('Run', run_now_job_path(job), :patch) }"
161
161
  end
162
- if events.include?(:pause)
162
+ if events.include?(:pause) && view.can?(:pause, job)
163
163
  buttons += "#{ job_action_link('Pause', pause_job_path(job), :patch) }"
164
164
  end
165
- if events.include?(:resume)
165
+ if events.include?(:resume) && view.can?(:resume, job)
166
166
  buttons += "#{ job_action_link('Resume', resume_job_path(job), :patch) }"
167
167
  end
168
- if events.include?(:retry)
168
+ if events.include?(:retry) && view.can?(:retry, job)
169
169
  buttons += "#{ job_action_link('Retry', retry_job_path(job), :patch) }"
170
170
  end
171
- buttons += "#{ job_action_link('Destroy', job_path(job), :delete) }"
171
+ if view.can?(:destroy, job)
172
+ buttons += "#{ job_action_link('Destroy', job_path(job), :delete) }"
173
+ end
172
174
  buttons += "</div>"
173
175
  end
174
176