rocketjob_mission_control 0.9.2
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +26 -0
- data/app/assets/javascripts/rocket_job_mission_control/application.js +18 -0
- data/app/assets/javascripts/rocket_job_mission_control/base.js.coffee +24 -0
- data/app/assets/javascripts/rocket_job_mission_control/jobs.js.coffee +11 -0
- data/app/assets/stylesheets/rocket_job_mission_control/application.scss +18 -0
- data/app/assets/stylesheets/rocket_job_mission_control/base.scss +468 -0
- data/app/assets/stylesheets/rocket_job_mission_control/bootstrap_and_overrides.scss +6 -0
- data/app/assets/stylesheets/rocket_job_mission_control/callout.scss +40 -0
- data/app/assets/stylesheets/rocket_job_mission_control/jobs.scss +16 -0
- data/app/assets/stylesheets/rocket_job_mission_control/jquery.bootstrap-touchspin.scss +45 -0
- data/app/controllers/rocket_job_mission_control/application_controller.rb +15 -0
- data/app/controllers/rocket_job_mission_control/jobs/inputs_controller.rb +9 -0
- data/app/controllers/rocket_job_mission_control/jobs/slices_controller.rb +10 -0
- data/app/controllers/rocket_job_mission_control/jobs_controller.rb +97 -0
- data/app/controllers/rocket_job_mission_control/workers_controller.rb +79 -0
- data/app/helpers/rocket_job_mission_control/application_helper.rb +16 -0
- data/app/helpers/rocket_job_mission_control/jobs_helper.rb +57 -0
- data/app/helpers/rocket_job_mission_control/workers_helper.rb +14 -0
- data/app/views/layouts/rocket_job_mission_control/application.html.haml +43 -0
- data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +16 -0
- data/app/views/layouts/rocket_job_mission_control/partials/_sidebar.html.haml +20 -0
- data/app/views/rocket_job_mission_control/jobs/_list.html.haml +33 -0
- data/app/views/rocket_job_mission_control/jobs/_status.html.haml +39 -0
- data/app/views/rocket_job_mission_control/jobs/index.html.haml +8 -0
- data/app/views/rocket_job_mission_control/jobs/running.html.haml +37 -0
- data/app/views/rocket_job_mission_control/jobs/show.html.haml +50 -0
- data/app/views/rocket_job_mission_control/workers/_actions.html.haml +9 -0
- data/app/views/rocket_job_mission_control/workers/index.html.haml +51 -0
- data/config/locales/en.yml +57 -0
- data/config/routes.rb +28 -0
- data/lib/rocket_job_mission_control/engine.rb +15 -0
- data/lib/rocket_job_mission_control/version.rb +3 -0
- data/lib/rocketjob_mission_control.rb +4 -0
- data/lib/tasks/rocket_job_mission_control_tasks.rake +4 -0
- data/spec/controllers/application_controller_spec.rb +47 -0
- data/spec/controllers/jobs_controller_spec.rb +217 -0
- data/spec/controllers/workers_controller_spec.rb +125 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +25 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +34 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/log/test.log +2459 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/helpers/jobs_helper_spec.rb +100 -0
- data/spec/rails_helper.rb +47 -0
- data/spec/spec_helper.rb +81 -0
- data/spec/views/workers/index.html.haml_spec.rb +17 -0
- data/vendor/assets/javascripts/jquery.bootstrap-touchspin.js +686 -0
- data/vendor/assets/javascripts/prism.js +6 -0
- data/vendor/assets/stylesheets/jquery.bootstrap-touchspin.css +45 -0
- data/vendor/assets/stylesheets/prism.scss +160 -0
- metadata +319 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
.callout {
|
2
|
+
border: 1px solid #eee;
|
3
|
+
border-left-width: 0.5em;
|
4
|
+
}
|
5
|
+
|
6
|
+
.callout-top {
|
7
|
+
border: 1px solid #eee;
|
8
|
+
border-top-width: 5px;
|
9
|
+
}
|
10
|
+
|
11
|
+
.callout-info-top {
|
12
|
+
border-top-color: #1b809e;
|
13
|
+
}
|
14
|
+
|
15
|
+
.callout-success-top {
|
16
|
+
border-top-color: #3c763d;
|
17
|
+
}
|
18
|
+
|
19
|
+
.callout-warning-top {
|
20
|
+
border-top-color: #aa6708;
|
21
|
+
}
|
22
|
+
|
23
|
+
.callout-alert-top {
|
24
|
+
border-top-color: #ce4844;
|
25
|
+
}
|
26
|
+
.callout-info {
|
27
|
+
border-left-color: #1b809e;
|
28
|
+
}
|
29
|
+
|
30
|
+
.callout-success {
|
31
|
+
border-left-color: #3c763d;
|
32
|
+
}
|
33
|
+
|
34
|
+
.callout-warning {
|
35
|
+
border-left-color: #aa6708;
|
36
|
+
}
|
37
|
+
|
38
|
+
.callout-alert {
|
39
|
+
border-left-color: #ce4844;
|
40
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.job-list {
|
2
|
+
.list {
|
3
|
+
.progress {
|
4
|
+
width: 16em;
|
5
|
+
height: 1em;
|
6
|
+
margin: 5px 0px 0px 10px;
|
7
|
+
-webkit-border-radius: 0 !important;
|
8
|
+
-moz-border-radius: 0 !important;
|
9
|
+
border-radius: 0 !important;
|
10
|
+
}
|
11
|
+
|
12
|
+
.progress-bar {
|
13
|
+
min-width: 1em;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
/*
|
2
|
+
* Bootstrap TouchSpin - v3.0.1
|
3
|
+
* A mobile and touch friendly input spinner component for Bootstrap 3.
|
4
|
+
* http://www.virtuosoft.eu/code/bootstrap-touchspin/
|
5
|
+
*
|
6
|
+
* Made by István Ujj-Mészáros
|
7
|
+
* Under Apache License v2.0 License
|
8
|
+
*/
|
9
|
+
|
10
|
+
.bootstrap-touchspin .input-group-btn-vertical {
|
11
|
+
position: relative;
|
12
|
+
white-space: nowrap;
|
13
|
+
width: 1%;
|
14
|
+
vertical-align: middle;
|
15
|
+
display: table-cell;
|
16
|
+
}
|
17
|
+
|
18
|
+
.bootstrap-touchspin .input-group-btn-vertical > .btn {
|
19
|
+
display: block;
|
20
|
+
float: none;
|
21
|
+
width: 100%;
|
22
|
+
max-width: 100%;
|
23
|
+
padding: 8px 10px;
|
24
|
+
margin-left: -1px;
|
25
|
+
position: relative;
|
26
|
+
}
|
27
|
+
|
28
|
+
.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-up {
|
29
|
+
border-radius: 0;
|
30
|
+
border-top-right-radius: 4px;
|
31
|
+
}
|
32
|
+
|
33
|
+
.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-down {
|
34
|
+
margin-top: -2px;
|
35
|
+
border-radius: 0;
|
36
|
+
border-bottom-right-radius: 4px;
|
37
|
+
}
|
38
|
+
|
39
|
+
.bootstrap-touchspin .input-group-btn-vertical i {
|
40
|
+
position: absolute;
|
41
|
+
top: 3px;
|
42
|
+
left: 5px;
|
43
|
+
font-size: 9px;
|
44
|
+
font-weight: normal;
|
45
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
include ActionController::Live
|
4
|
+
|
5
|
+
around_action :with_time_zone
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def with_time_zone
|
10
|
+
if time_zone = session['time_zone'] || 'UTC'
|
11
|
+
Time.use_zone(time_zone) { yield }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class JobsController < RocketJobMissionControl::ApplicationController
|
3
|
+
before_filter :find_job_or_redirect, except: [:index, :running]
|
4
|
+
rescue_from StandardError, with: :error_occurred
|
5
|
+
|
6
|
+
def running
|
7
|
+
@jobs = RocketJob::Job.where(state: 'running')
|
8
|
+
end
|
9
|
+
|
10
|
+
def update
|
11
|
+
@job.update_attributes!(job_params)
|
12
|
+
|
13
|
+
redirect_to job_path(@job)
|
14
|
+
end
|
15
|
+
|
16
|
+
def abort
|
17
|
+
@job.abort!
|
18
|
+
|
19
|
+
redirect_to(job_path(@job))
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
if @job.completed? || @job.aborted?
|
24
|
+
@job.destroy
|
25
|
+
redirect_to(jobs_path)
|
26
|
+
else
|
27
|
+
flash[:alert] = "Cannot destroy a job unless it is completed or aborted"
|
28
|
+
redirect_to(job_path(@job))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def retry
|
33
|
+
@job.retry!
|
34
|
+
|
35
|
+
redirect_to(job_path(@job))
|
36
|
+
end
|
37
|
+
|
38
|
+
def pause
|
39
|
+
@job.pause!
|
40
|
+
|
41
|
+
redirect_to(job_path(@job))
|
42
|
+
end
|
43
|
+
|
44
|
+
def resume
|
45
|
+
@job.resume!
|
46
|
+
|
47
|
+
redirect_to(job_path(@job))
|
48
|
+
end
|
49
|
+
|
50
|
+
def fail
|
51
|
+
@job.fail!
|
52
|
+
|
53
|
+
redirect_to(job_path(@job))
|
54
|
+
end
|
55
|
+
|
56
|
+
def show
|
57
|
+
load_jobs
|
58
|
+
end
|
59
|
+
|
60
|
+
def index
|
61
|
+
load_jobs
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def load_jobs
|
67
|
+
@states = jobs_params
|
68
|
+
@jobs = RocketJob::Job.limit(1000).sort(created_at: :desc)
|
69
|
+
@jobs = @jobs.where(state: @states) unless @states.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_job_or_redirect
|
73
|
+
@job = RocketJob::Job.find(params[:id])
|
74
|
+
|
75
|
+
if @job.nil?
|
76
|
+
flash[:alert] = t(:failure, scope: [:job, :find], id: params[:id])
|
77
|
+
|
78
|
+
redirect_to(jobs_path)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def jobs_params
|
83
|
+
params.fetch(:states, [])
|
84
|
+
end
|
85
|
+
|
86
|
+
def job_params
|
87
|
+
params.require(:job).permit(:priority)
|
88
|
+
end
|
89
|
+
|
90
|
+
def error_occurred(exception)
|
91
|
+
logger.error "Error loading a job", exception
|
92
|
+
flash[:danger] = "Error loading jobs."
|
93
|
+
raise exception if Rails.env.development?
|
94
|
+
redirect_to :back
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
class WorkersController < RocketJobMissionControl::ApplicationController
|
3
|
+
before_filter :find_worker, only: [:stop, :pause, :resume, :destroy]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@workers = RocketJob::Worker.sort(:name)
|
7
|
+
end
|
8
|
+
|
9
|
+
VALID_STATES = { stop: 'stopped', pause: 'paused', resume: 'resumed' }
|
10
|
+
|
11
|
+
def update_all
|
12
|
+
worker_action = params[:worker_action].to_sym
|
13
|
+
if VALID_STATES.keys.include?(worker_action)
|
14
|
+
RocketJob::Worker.send("#{worker_action}_all".to_sym)
|
15
|
+
flash[:notice] = t(:success, scope: [:worker, :update_all], worker_action: VALID_STATES[worker_action])
|
16
|
+
else
|
17
|
+
flash[:alert] = t(:invalid, scope: [:worker, :update_all])
|
18
|
+
end
|
19
|
+
|
20
|
+
respond_to do |format|
|
21
|
+
format.html { redirect_to workers_path }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop
|
26
|
+
if @worker.stop!
|
27
|
+
flash[:notice] = t(:success, scope: [:worker, :stop])
|
28
|
+
else
|
29
|
+
flash[:alert] = t(:failure, scope: [:worker, :stop])
|
30
|
+
end
|
31
|
+
|
32
|
+
respond_to do |format|
|
33
|
+
format.html { redirect_to workers_path }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy
|
38
|
+
if @worker.destroy
|
39
|
+
flash[:notice] = t(:success, scope: [:worker, :destroy])
|
40
|
+
else
|
41
|
+
flash[:alert] = t(:failure, scope: [:worker, :destroy])
|
42
|
+
end
|
43
|
+
|
44
|
+
respond_to do |format|
|
45
|
+
format.html { redirect_to workers_path }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def pause
|
50
|
+
if @worker.pause!
|
51
|
+
flash[:notice] = t(:success, scope: [:worker, :pause])
|
52
|
+
else
|
53
|
+
flash[:alert] = t(:failure, scope: [:worker, :pause])
|
54
|
+
end
|
55
|
+
|
56
|
+
respond_to do |format|
|
57
|
+
format.html { redirect_to workers_path }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def resume
|
62
|
+
if @worker.resume!
|
63
|
+
flash[:notice] = t(:success, scope: [:worker, :resume])
|
64
|
+
else
|
65
|
+
flash[:alert] = t(:failure, scope: [:worker, :resume])
|
66
|
+
end
|
67
|
+
|
68
|
+
respond_to do |format|
|
69
|
+
format.html { redirect_to workers_path }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def find_worker
|
76
|
+
@worker = RocketJob::Worker.find(params[:id])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
module ApplicationHelper
|
3
|
+
def site_title
|
4
|
+
'Rocket Job Mission Control'
|
5
|
+
end
|
6
|
+
|
7
|
+
def title
|
8
|
+
@page_title ||= params[:controller].to_s.titleize
|
9
|
+
h(@full_title || [@page_title, site_title].compact.join(' | '))
|
10
|
+
end
|
11
|
+
|
12
|
+
def active_page(path)
|
13
|
+
"active" if current_page?(path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
module JobsHelper
|
3
|
+
STATE_ICON_MAP = {
|
4
|
+
queued: 'fa-bed warning',
|
5
|
+
paused: 'fa-pause warning',
|
6
|
+
running: 'fa-cog fa-spin primary',
|
7
|
+
completed: 'fa-check success',
|
8
|
+
aborted: 'fa-times warning',
|
9
|
+
}
|
10
|
+
|
11
|
+
STATE_CLASS_MAP = {
|
12
|
+
queued: 'warning',
|
13
|
+
paused: 'warning',
|
14
|
+
running: 'primary',
|
15
|
+
completed: 'success',
|
16
|
+
aborted: 'danger',
|
17
|
+
failed: 'danger',
|
18
|
+
}
|
19
|
+
|
20
|
+
def job_state_icon(state)
|
21
|
+
STATE_ICON_MAP[state.to_sym] || 'fa-times danger'
|
22
|
+
end
|
23
|
+
|
24
|
+
def job_class(job)
|
25
|
+
STATE_CLASS_MAP[job.state.to_sym] || ""
|
26
|
+
end
|
27
|
+
|
28
|
+
def pretty_print_array_or_hash(arguments)
|
29
|
+
return arguments unless arguments.kind_of?(Array) || arguments.kind_of?(Hash)
|
30
|
+
json_string_options = {space: ' ', indent: ' ', array_nl: '<br />', object_nl: '<br />'}
|
31
|
+
JSON.generate(arguments, json_string_options).html_safe
|
32
|
+
end
|
33
|
+
|
34
|
+
def job_card_class(job)
|
35
|
+
map = {
|
36
|
+
running: 'callout-info',
|
37
|
+
completed: 'callout-success',
|
38
|
+
failed: 'callout-alert',
|
39
|
+
aborted: 'callout-warning',
|
40
|
+
}
|
41
|
+
"card callout " << map[job.state.to_sym].to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def job_selected_class(job, selected_job = nil)
|
45
|
+
if selected_job.present? && job.id == selected_job.id
|
46
|
+
' text-info'
|
47
|
+
else
|
48
|
+
' text-muted'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def job_title(job)
|
53
|
+
perform_method = job.perform_method == :perform ? '' : "##{job.perform_method}"
|
54
|
+
"#{job.class.name}#{perform_method}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RocketJobMissionControl
|
2
|
+
module WorkersHelper
|
3
|
+
|
4
|
+
def worker_card_class(worker)
|
5
|
+
map = {
|
6
|
+
running: 'callout-success-top',
|
7
|
+
paused: 'callout-warning-top',
|
8
|
+
stopping: 'callout-alert-top',
|
9
|
+
}
|
10
|
+
map[worker.state] || 'callout-info-top'
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title= title
|
5
|
+
|
6
|
+
%link{rel: "icon", type: "image/png", href: "/assets/favicon.png"}
|
7
|
+
%link{rel: "apple-touch-icon-precomposed", href: "/assets/apple-touch-icon.png"}
|
8
|
+
|
9
|
+
%meta{'http-equiv' => "Content-Type", content: "text/html; charset=UTF-8"}
|
10
|
+
%meta{'http-equiv' => "Content-Script-Type", content: "text/javascript"}
|
11
|
+
%meta{'http-equiv' =>"X-UA-Compatible", content: "IE=edge" }
|
12
|
+
%meta{name: "viewport", content: "width=device-width, initial-scale=1"}
|
13
|
+
= yield :meta
|
14
|
+
|
15
|
+
|
16
|
+
= stylesheet_link_tag "rocket_job_mission_control/application", :media => "all"
|
17
|
+
= javascript_include_tag "rocket_job_mission_control/application"
|
18
|
+
|
19
|
+
= csrf_meta_tag
|
20
|
+
|
21
|
+
%link{href: "//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css", rel: "stylesheet"}/
|
22
|
+
|
23
|
+
%body.rocket_job
|
24
|
+
#wrapper.toggled
|
25
|
+
= render partial: 'layouts/rocket_job_mission_control/partials/sidebar'
|
26
|
+
|
27
|
+
#page-content-wrapper
|
28
|
+
= render partial: 'layouts/rocket_job_mission_control/partials/header'
|
29
|
+
|
30
|
+
.flash
|
31
|
+
- flash.each do |key, msg|
|
32
|
+
- if msg
|
33
|
+
.alert{class: "alert-#{key} alert-dismissable", role: 'alert'}
|
34
|
+
%button.close{ data: { dismiss: 'alert' } }
|
35
|
+
%span ×
|
36
|
+
-if msg.kind_of? Array
|
37
|
+
%ul.list-unstyled.margin-bottom-0
|
38
|
+
- msg.each do |m|
|
39
|
+
%li= m.html_safe
|
40
|
+
- else
|
41
|
+
= msg.html_safe
|
42
|
+
|
43
|
+
= yield
|