rocketjob_mission_control 3.1.0 → 3.2.0

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