rhea 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +165 -2
- data/app/assets/javascripts/rhea/application.js +2 -0
- data/app/assets/javascripts/rhea/main.js +3 -0
- data/app/assets/javascripts/vendor/jquery-1.11.3.js +10351 -0
- data/app/assets/stylesheets/rhea/application.css.sass +1 -0
- data/app/assets/stylesheets/rhea/layout.css.sass +31 -0
- data/app/controllers/rhea/base_controller.rb +26 -0
- data/app/controllers/rhea/commands_controller.rb +168 -0
- data/app/controllers/rhea/events_controller.rb +8 -0
- data/app/controllers/rhea/nodes_controller.rb +7 -0
- data/app/controllers/rhea/system_services_controller.rb +7 -0
- data/app/helpers/rhea/helper.rb +42 -0
- data/app/views/rhea/command_types/_list.html.haml +5 -0
- data/app/views/rhea/commands/_form.html.haml +22 -0
- data/app/views/rhea/commands/_table.html.haml +51 -0
- data/app/views/rhea/commands/index.html.haml +51 -0
- data/app/views/rhea/errors/index.html.haml +2 -0
- data/app/views/rhea/events/index.html.haml +24 -0
- data/app/views/rhea/layouts/application.html.haml +35 -0
- data/app/views/rhea/nodes/index.html.haml +29 -0
- data/app/views/rhea/system_services/index.html.haml +2 -0
- data/config/routes.rb +21 -0
- data/docs/commands.gif +0 -0
- data/docs/commands.mov +0 -0
- data/docs/events.png +0 -0
- data/docs/logo.png +0 -0
- data/docs/nodes.png +0 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_All/_perform/an_existing_rc/returns_the_rc.yml +197 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Delete/_perform/an_existing_rc/deletes_the_rc.yml +163 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Export/_perform/an_existing_rc/returns_the_data.yml +197 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Get/_perform/an_existing_rc/gets_the_rc.yml +196 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Import/_perform/no_existing_rcs/creates_the_rcs.yml +197 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Redeploy/_perform/an_existing_rc/redeploys_the_rc.yml +424 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Reschedule/_perform/an_existing_rc/reschedules_the_rc.yml +421 -0
- data/fixtures/vcr_cassettes/Rhea_Kubernetes_Commands_Scale/_perform/no_existing_rc/creates_an_rc.yml +165 -0
- data/lib/rhea.rb +15 -1
- data/lib/rhea/command.rb +35 -0
- data/lib/rhea/command_type.rb +35 -0
- data/lib/rhea/engine.rb +16 -0
- data/lib/rhea/kubernetes.rb +5 -0
- data/lib/rhea/kubernetes/api.rb +15 -0
- data/lib/rhea/kubernetes/commands/all.rb +16 -0
- data/lib/rhea/kubernetes/commands/base.rb +28 -0
- data/lib/rhea/kubernetes/commands/delete.rb +18 -0
- data/lib/rhea/kubernetes/commands/export.rb +23 -0
- data/lib/rhea/kubernetes/commands/get.rb +18 -0
- data/lib/rhea/kubernetes/commands/import.rb +20 -0
- data/lib/rhea/kubernetes/commands/redeploy.rb +22 -0
- data/lib/rhea/kubernetes/commands/reschedule.rb +21 -0
- data/lib/rhea/kubernetes/commands/scale.rb +108 -0
- data/lib/rhea/kubernetes/configuration.rb +30 -0
- data/lib/rhea/kubernetes/events/recent.rb +23 -0
- data/lib/rhea/kubernetes/nodes/all.rb +45 -0
- data/lib/rhea/kubernetes/system_services.rb +22 -0
- data/lib/rhea/version.rb +1 -1
- data/rhea.gemspec +11 -3
- data/spec/lib/rhea/kubernetes/commands/all_spec.rb +29 -0
- data/spec/lib/rhea/kubernetes/commands/delete_spec.rb +22 -0
- data/spec/lib/rhea/kubernetes/commands/export_spec.rb +31 -0
- data/spec/lib/rhea/kubernetes/commands/get_spec.rb +28 -0
- data/spec/lib/rhea/kubernetes/commands/import_spec.rb +39 -0
- data/spec/lib/rhea/kubernetes/commands/redeploy_spec.rb +35 -0
- data/spec/lib/rhea/kubernetes/commands/reschedule_spec.rb +32 -0
- data/spec/lib/rhea/kubernetes/commands/scale_spec.rb +31 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/kubernetes_spec_helper.rb +43 -0
- data/spec/support/vcr.rb +9 -0
- metadata +170 -11
@@ -0,0 +1 @@
|
|
1
|
+
@import layout
|
@@ -0,0 +1,31 @@
|
|
1
|
+
h1, h2, h3, h4, h5, h6
|
2
|
+
margin-top: 0
|
3
|
+
|
4
|
+
.batch-actions .btn-action
|
5
|
+
margin-left: 0
|
6
|
+
margin-right: 5px
|
7
|
+
|
8
|
+
.btn-action
|
9
|
+
margin-left: 5px
|
10
|
+
|
11
|
+
.btn-file
|
12
|
+
position: relative
|
13
|
+
overflow: hidden
|
14
|
+
|
15
|
+
.btn-file input[type=file]
|
16
|
+
position: absolute
|
17
|
+
top: 0
|
18
|
+
right: 0
|
19
|
+
min-width: 100%
|
20
|
+
min-height: 100%
|
21
|
+
font-size: 100px
|
22
|
+
text-align: right
|
23
|
+
filter: alpha(opacity=0)
|
24
|
+
opacity: 0
|
25
|
+
outline: none
|
26
|
+
background: white
|
27
|
+
cursor: inherit
|
28
|
+
display: block
|
29
|
+
|
30
|
+
.form-horizontal .control-label
|
31
|
+
padding-right: 0
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rhea
|
2
|
+
class BaseController < ActionController::Base
|
3
|
+
protect_from_forgery
|
4
|
+
|
5
|
+
layout 'rhea/layouts/application'
|
6
|
+
|
7
|
+
helper Rhea::Helper
|
8
|
+
|
9
|
+
around_filter :rescue_exceptions
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def rescue_exceptions
|
14
|
+
yield
|
15
|
+
rescue Errno::ECONNREFUSED
|
16
|
+
render_connection_exception
|
17
|
+
rescue Rhea::Kubernetes::ServerError => e
|
18
|
+
flash[:alert] = e.message
|
19
|
+
render_connection_exception
|
20
|
+
end
|
21
|
+
|
22
|
+
def render_connection_exception
|
23
|
+
render 'rhea/errors/index'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Rhea
|
2
|
+
class CommandsController < Rhea::BaseController
|
3
|
+
def index
|
4
|
+
@commands = Rhea::Kubernetes::Commands::All.new.perform
|
5
|
+
@default_image = Rhea.configuration.default_image
|
6
|
+
@images = (@commands.map(&:image) + [@default_image]).uniq.sort
|
7
|
+
params[:image] ||= @default_image
|
8
|
+
if params[:image].present?
|
9
|
+
@commands = @commands.select { |command| command.image == params[:image] }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
command_type_key = params[:command_type_key].presence
|
15
|
+
command_type_input = params[:command_type_input]
|
16
|
+
process_count = params[:process_count].presence.try(:to_i) || 1
|
17
|
+
image = params[:image].presence
|
18
|
+
|
19
|
+
redirect_to :back, flash: { error: 'Blank command_type_key' } and return if command_type_key.blank?
|
20
|
+
redirect_to :back, flash: { error: 'Blank process_count' } and return if process_count.blank?
|
21
|
+
redirect_to :back, flash: { error: 'Blank image' } and return if image.blank?
|
22
|
+
|
23
|
+
command_type = Rhea::CommandType.find(command_type_key)
|
24
|
+
command_expression = command_type.input_to_command_expression(command_type_input)
|
25
|
+
|
26
|
+
Rhea::Kubernetes::Commands::Scale.new(expression: command_expression, image: image, process_count: process_count).perform
|
27
|
+
wait_for_updates_to_persist
|
28
|
+
redirect_to params[:redirect_to], notice: 'Command created!'
|
29
|
+
end
|
30
|
+
|
31
|
+
def batch_update
|
32
|
+
case params[:batch_action]
|
33
|
+
when 'redeploy'
|
34
|
+
batch_redeploy
|
35
|
+
when 'reschedule'
|
36
|
+
batch_reschedule
|
37
|
+
when 'scale'
|
38
|
+
batch_scale
|
39
|
+
when 'stop'
|
40
|
+
batch_stop
|
41
|
+
else
|
42
|
+
redirect_to params[:redirect_to], notice: 'Invalid action!'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete
|
47
|
+
command_attributes = image_expression_to_command_attributes(params[:image_expression])
|
48
|
+
Rhea::Kubernetes::Commands::Delete.new(command_attributes).perform
|
49
|
+
flash[:notice] = "Command '#{command_attributes[:expression]}' deleted!"
|
50
|
+
redirect_to :back
|
51
|
+
end
|
52
|
+
|
53
|
+
def export
|
54
|
+
data = Rhea::Kubernetes::Commands::Export.new.perform
|
55
|
+
respond_to do |format|
|
56
|
+
format.json { send_data data.to_json, type: :json, disposition: 'attachment', filename: 'rhea.json' }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def import
|
61
|
+
data = ActiveSupport::JSON.decode(params[:data].read)
|
62
|
+
commands = data['commands']
|
63
|
+
if commands.nil?
|
64
|
+
flash[:alert] = 'Invalid file'
|
65
|
+
redirect_to :back
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
Rhea::Kubernetes::Commands::Import.new(data).perform
|
70
|
+
flash[:notice] = "Imported #{commands.length} commands!"
|
71
|
+
redirect_to :back
|
72
|
+
end
|
73
|
+
|
74
|
+
def redeploy
|
75
|
+
command_attributes = image_expression_to_command_attributes(params[:image_expression])
|
76
|
+
Rhea::Kubernetes::Commands::Redeploy.new(command_attributes).perform
|
77
|
+
flash[:notice] = "Command '#{command_attributes[:expression]}' redeployed!"
|
78
|
+
redirect_to :back
|
79
|
+
end
|
80
|
+
|
81
|
+
def reschedule
|
82
|
+
command_attributes = image_expression_to_command_attributes(params[:image_expression])
|
83
|
+
Rhea::Kubernetes::Commands::Reschedule.new(command_attributes).perform
|
84
|
+
flash[:notice] = "Command '#{command_attributes[:expression]}' rescheduled!"
|
85
|
+
redirect_to :back
|
86
|
+
end
|
87
|
+
|
88
|
+
def stop
|
89
|
+
command_attributes = image_expression_to_command_attributes(params[:image_expression])
|
90
|
+
Rhea::Kubernetes::Commands::Scale.new(command_attributes.merge(process_count: 0)).perform
|
91
|
+
flash[:notice] = "Command '#{command_attributes[:expression]}' stopped!"
|
92
|
+
redirect_to :back
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def batch_redeploy
|
98
|
+
image_expressions = params[:batch_image_expressions]
|
99
|
+
redirect_to params[:redirect_to], notice: 'No commands were selected!' and return if image_expressions.blank?
|
100
|
+
threads = image_expressions.map do |image_expression|
|
101
|
+
command_attributes = image_expression_to_command_attributes(image_expression)
|
102
|
+
Thread.new do
|
103
|
+
Rhea::Kubernetes::Commands::Redeploy.new(command_attributes).perform
|
104
|
+
end
|
105
|
+
end
|
106
|
+
threads.map(&:join)
|
107
|
+
wait_for_updates_to_persist
|
108
|
+
redirect_to params[:redirect_to], notice: "Redeployed #{image_expressions.length} #{'command'.pluralize(image_expressions.length)}!"
|
109
|
+
end
|
110
|
+
|
111
|
+
def batch_reschedule
|
112
|
+
image_expressions = params[:batch_image_expressions]
|
113
|
+
redirect_to params[:redirect_to], notice: 'No commands were selected!' and return if image_expressions.blank?
|
114
|
+
threads = image_expressions.map do |image_expression|
|
115
|
+
command_attributes = image_expression_to_command_attributes(image_expression)
|
116
|
+
Thread.new do
|
117
|
+
Rhea::Kubernetes::Commands::Reschedule.new(command_attributes).perform
|
118
|
+
end
|
119
|
+
end
|
120
|
+
threads.map(&:join)
|
121
|
+
wait_for_updates_to_persist
|
122
|
+
redirect_to params[:redirect_to], notice: "Rescheduled #{image_expressions.length} #{'command'.pluralize(image_expressions.length)}!"
|
123
|
+
end
|
124
|
+
|
125
|
+
def batch_scale
|
126
|
+
image_expressions_process_counts = params[:image_expressions_process_counts]
|
127
|
+
scaled_commands_count = 0
|
128
|
+
image_expressions_process_counts.each do |image_expression, process_count|
|
129
|
+
next if process_count.blank?
|
130
|
+
process_count = process_count.to_i
|
131
|
+
command_attributes = image_expression_to_command_attributes(image_expression)
|
132
|
+
Rhea::Kubernetes::Commands::Scale.new(command_attributes.merge(process_count: process_count)).perform
|
133
|
+
scaled_commands_count += 1
|
134
|
+
end
|
135
|
+
wait_for_updates_to_persist
|
136
|
+
redirect_to params[:redirect_to], notice: "Scaled #{scaled_commands_count} #{'command'.pluralize(scaled_commands_count)}!"
|
137
|
+
end
|
138
|
+
|
139
|
+
def batch_stop
|
140
|
+
image_expressions = params[:batch_image_expressions]
|
141
|
+
redirect_to params[:redirect_to], notice: 'No commands were selected!' and return if image_expressions.blank?
|
142
|
+
threads = image_expressions.map do |image_expression|
|
143
|
+
command_attributes = image_expression_to_command_attributes(image_expression)
|
144
|
+
Thread.new do
|
145
|
+
Rhea::Kubernetes::Commands::Scale.new(command_attributes.merge(process_count: 0)).perform
|
146
|
+
end
|
147
|
+
end
|
148
|
+
threads.map(&:join)
|
149
|
+
wait_for_updates_to_persist
|
150
|
+
redirect_to params[:redirect_to], notice: "Stopped #{image_expressions.length} #{'command'.pluralize(image_expressions.length)}!"
|
151
|
+
end
|
152
|
+
|
153
|
+
# Sleep briefly to prevent user needing to refresh the page to see updated counts
|
154
|
+
def wait_for_updates_to_persist
|
155
|
+
sleep 0.2
|
156
|
+
end
|
157
|
+
|
158
|
+
# TODO: Use proper form submissions instead of string concatenation
|
159
|
+
def image_expression_to_command_attributes(image_expression)
|
160
|
+
image_expression = CGI.unescape(image_expression)
|
161
|
+
image, expression = image_expression.split(Rhea::Command::IMAGE_EXPRESSION_SEPARATOR, 2)
|
162
|
+
{
|
163
|
+
image: image,
|
164
|
+
expression: expression
|
165
|
+
}
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rhea
|
2
|
+
module Helper
|
3
|
+
def app_name
|
4
|
+
'Rhea'
|
5
|
+
end
|
6
|
+
|
7
|
+
def root_path
|
8
|
+
Rhea.root_path
|
9
|
+
end
|
10
|
+
|
11
|
+
def humanize_image(image)
|
12
|
+
image.split('/').last
|
13
|
+
end
|
14
|
+
|
15
|
+
ALERT_TYPES = [:success, :info, :warning, :danger] unless const_defined?(:ALERT_TYPES)
|
16
|
+
|
17
|
+
def bootstrap_flash(options = {})
|
18
|
+
flash_messages = []
|
19
|
+
flash.each do |type, message|
|
20
|
+
# Skip empty messages, e.g. for devise messages set to nothing in a locale file.
|
21
|
+
next if message.blank?
|
22
|
+
|
23
|
+
type = type.to_sym
|
24
|
+
type = :success if type == :notice
|
25
|
+
type = :danger if type == :alert
|
26
|
+
type = :danger if type == :error
|
27
|
+
next unless ALERT_TYPES.include?(type)
|
28
|
+
|
29
|
+
tag_class = options.extract!(:class)[:class]
|
30
|
+
tag_options = {
|
31
|
+
class: "alert fade in alert-#{type} #{tag_class}"
|
32
|
+
}.merge(options)
|
33
|
+
|
34
|
+
Array(message).each do |msg|
|
35
|
+
text = content_tag(:div, msg.html_safe, tag_options)
|
36
|
+
flash_messages << text if msg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
flash_messages.join("\n").html_safe
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
= form_tag commands_path, method: 'POST', class: 'form-horizontal' do
|
2
|
+
= hidden_field_tag :redirect_to, request.fullpath
|
3
|
+
.form-group
|
4
|
+
= label_tag :image, 'Image', class: 'col-sm-3 control-label'
|
5
|
+
.col-sm-9
|
6
|
+
= text_field_tag :image, Rhea.configuration.default_image, class: 'form-control', style: 'width: 100%;', placeholder: Rhea.configuration.default_image
|
7
|
+
.form-group
|
8
|
+
= label_tag :command_type_key, 'Type', class: 'col-sm-3 control-label'
|
9
|
+
.col-sm-9
|
10
|
+
= select_tag :command_type_key, options_for_select(Rhea::CommandType.options_for_select, Rhea.configuration.default_command_type_key), class: 'form-control', style: 'width: 90px;', required: 'required'
|
11
|
+
.form-group
|
12
|
+
= label_tag :command_type_input, 'Input', class: 'col-sm-3 control-label'
|
13
|
+
.col-sm-9
|
14
|
+
= text_field_tag :command_type_input, nil, class: 'form-control', style: 'width: 100%;'
|
15
|
+
.form-group
|
16
|
+
= label_tag :process_count, 'Processes', class: 'col-sm-3 control-label'
|
17
|
+
.col-sm-9
|
18
|
+
= text_field_tag :process_count, 1, class: 'form-control', style: 'width: 50px;', placeholder: 1
|
19
|
+
.form-group
|
20
|
+
.col-sm-3
|
21
|
+
.col-sm-9
|
22
|
+
= submit_tag 'Create', class: 'btn btn-default'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
%table.table.table-condensed.table-striped
|
2
|
+
%thead
|
3
|
+
%tr
|
4
|
+
%th
|
5
|
+
%input{type: 'checkbox', id: 'check-all'}
|
6
|
+
%th Image
|
7
|
+
%th Command
|
8
|
+
%th Processes
|
9
|
+
%th Desired Processes
|
10
|
+
%th Deployed
|
11
|
+
%th
|
12
|
+
%tbody
|
13
|
+
- commands.each do |command|
|
14
|
+
- escaped_image_expression = CGI.escape([command.image, command.expression].join(Rhea::Command::IMAGE_EXPRESSION_SEPARATOR))
|
15
|
+
%tr
|
16
|
+
%td= check_box_tag 'batch_image_expressions[]', escaped_image_expression, false, class: 'command-checkbox'
|
17
|
+
%td= humanize_image(command.image)
|
18
|
+
%td= command.expression
|
19
|
+
%td= command.process_count
|
20
|
+
%td
|
21
|
+
= text_field_tag "image_expressions_process_counts[#{escaped_image_expression}]", nil, class: 'form-control', style: 'width: 50px;'
|
22
|
+
%td
|
23
|
+
%small.text-muted
|
24
|
+
= time_ago_in_words(command.created_at.in_time_zone(Time.zone), include_seconds: true)
|
25
|
+
ago
|
26
|
+
%td{ style: 'white-space: nowrap;' }
|
27
|
+
= link_to redeploy_commands_path(image_expression: escaped_image_expression), title: 'Redeploy', class: 'btn btn-info btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
28
|
+
%span.glyphicon.glyphicon-cloud-download
|
29
|
+
= link_to reschedule_commands_path(image_expression: escaped_image_expression), title: 'Reschedule', class: 'btn btn-info btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
30
|
+
%span.glyphicon.glyphicon-fullscreen
|
31
|
+
- if command.process_count == 0
|
32
|
+
= link_to delete_commands_path(image_expression: escaped_image_expression), title: 'Delete', class: 'btn btn-danger btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
33
|
+
%span.glyphicon.glyphicon-remove
|
34
|
+
- else
|
35
|
+
= link_to stop_commands_path(image_expression: escaped_image_expression), title: 'Stop', class: 'btn btn-warning btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
36
|
+
%span.glyphicon.glyphicon-stop
|
37
|
+
%tr
|
38
|
+
%td{ colspan: 2 }
|
39
|
+
.batch-actions{ style: 'display: none;' }
|
40
|
+
= button_tag name: 'batch_action', value: 'redeploy', title: 'Redeploy', class: 'btn btn-info btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
41
|
+
%span.glyphicon.glyphicon-cloud-download
|
42
|
+
= button_tag name: 'batch_action', value: 'reschedule', title: 'Reschedule', class: 'btn btn-info btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
43
|
+
%span.glyphicon.glyphicon-fullscreen
|
44
|
+
= button_tag name: 'batch_action', value: 'stop', title: 'Stop', class: 'btn btn-warning btn-xs btn-action', 'data-toggle': 'tooltip', 'data-placement': 'bottom' do
|
45
|
+
%span.glyphicon.glyphicon-stop
|
46
|
+
%td
|
47
|
+
%td
|
48
|
+
%td
|
49
|
+
= button_tag 'Save', name: 'batch_action', value: 'scale', class: 'btn btn-default'
|
50
|
+
%td
|
51
|
+
%td
|
@@ -0,0 +1,51 @@
|
|
1
|
+
.row
|
2
|
+
.col-md-8
|
3
|
+
.pull-right
|
4
|
+
= form_tag commands_path, method: 'GET', class: 'form-inline' do
|
5
|
+
.form-group
|
6
|
+
= label_tag :image, 'Image:', style: 'margin-right: 5px; font-size: 12px; font-weight: normal;'
|
7
|
+
- image_options = [['All', nil]] + @images.map { |image| [humanize_image(image), image] }
|
8
|
+
= select_tag :image, options_for_select(image_options, params[:image].presence), class: 'form-control input-sm', onchange: "$(this).closest('form').submit();"
|
9
|
+
%h3 Commands
|
10
|
+
- if @commands.blank?
|
11
|
+
%p No commands found.
|
12
|
+
- else
|
13
|
+
= form_tag batch_update_commands_path, method: 'POST' do
|
14
|
+
= hidden_field_tag :redirect_to, request.fullpath
|
15
|
+
= render partial: 'rhea/commands/table', locals: { commands: @commands }
|
16
|
+
= link_to 'Export', export_commands_path(format: 'json'), class: 'btn btn-default'
|
17
|
+
= form_tag import_commands_path, method: 'PUT', multipart: true, style: 'display: inline-block;' do
|
18
|
+
%span.btn.btn-default.btn-file
|
19
|
+
Import
|
20
|
+
= file_field_tag :data, accept: 'application/json', onchange: "$(this).closest('form').submit();"
|
21
|
+
%br
|
22
|
+
%br
|
23
|
+
|
24
|
+
.col-md-4
|
25
|
+
.panel.panel-default
|
26
|
+
.panel-heading
|
27
|
+
%h4 New Command
|
28
|
+
.panel-body
|
29
|
+
= render partial: 'rhea/commands/form'
|
30
|
+
|
31
|
+
.panel.panel-default
|
32
|
+
.panel-heading
|
33
|
+
%h4 Command Types
|
34
|
+
.panel-body
|
35
|
+
= render partial: 'rhea/command_types/list'
|
36
|
+
|
37
|
+
:javascript
|
38
|
+
var checkboxes = $('.command-checkbox');
|
39
|
+
var batchActions = $('.batch-actions');
|
40
|
+
|
41
|
+
var toggleBatchActions = function() {
|
42
|
+
batchActions.toggle(checkboxes.filter(':checked').length > 0);
|
43
|
+
return true;
|
44
|
+
}
|
45
|
+
|
46
|
+
checkboxes.on('click', toggleBatchActions);
|
47
|
+
|
48
|
+
$('#check-all').change(function(){
|
49
|
+
$(".command-checkbox").prop('checked', $(this).prop("checked"));
|
50
|
+
toggleBatchActions()
|
51
|
+
})
|
@@ -0,0 +1,24 @@
|
|
1
|
+
%table.table.table-condensed.table-striped
|
2
|
+
%thead
|
3
|
+
%tr
|
4
|
+
%th Time
|
5
|
+
%th
|
6
|
+
%th Host
|
7
|
+
%th Message
|
8
|
+
%th Type
|
9
|
+
%th Resource Type
|
10
|
+
%th Resource ID
|
11
|
+
%tbody
|
12
|
+
- @events.each do |event|
|
13
|
+
%tr
|
14
|
+
%td{ style: 'white-space: nowrap;' }= event.created_at.in_time_zone(Time.zone)
|
15
|
+
%td{ style: 'white-space: nowrap;' }
|
16
|
+
= time_ago_in_words(event.created_at.in_time_zone(Time.zone), include_seconds: true)
|
17
|
+
ago
|
18
|
+
%td= event.hostname
|
19
|
+
%td= simple_format(event.message)
|
20
|
+
%td= event.type
|
21
|
+
%td= event.resource_type
|
22
|
+
%td= event.resource_id
|
23
|
+
|
24
|
+
= paginate @events
|