rhea 0.0.1 → 0.1.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.
- 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
|