perus 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cb71157c8e99e2d438be1de8effd475492a88e20
4
- data.tar.gz: 937cae814206ed5fc94d1ef613d76881b1139247
3
+ metadata.gz: c691e0803e6d3cd8e4f71844229b16cbd9c86eff
4
+ data.tar.gz: 4b50581cb82ee72f16cdc7b0ffe91b03e92d0b5e
5
5
  SHA512:
6
- metadata.gz: b29144c8a6f3b45bd0038dbfbeea93d52adde137368557dddf049c9a1faacfe2235c1a9c1e208e07634bf146024dfb3f4a06a672955df683122813af399a4942
7
- data.tar.gz: 9cd259d515b06c7c25da09cfec9f7f133b337688afbcb883ee30263bb040bd42d75cf5602ca037a12d7b6a9cea0e2c4dff2c06619163cb71980618df9320d8ee
6
+ metadata.gz: 95a1cf16ed2e53948382cd64c2b164b26112cfeec66b22ec298e3cbf6ee6e6d97ffafce83a2ba901f17d84aedfed9d20ff06a71ae4d9498a2564bae5ce715d50
7
+ data.tar.gz: 74fae7570dd20724b4f79f1cfc943e0fd89d92c7f4306c8e91a11c02f0863e628fd3ab106fe4dd1b14affe51b5f5fdd5bc36ebb36e0fde378fefb4769de39d9f
@@ -0,0 +1,11 @@
1
+ module Perus::Pinger
2
+ class RunInstalledCommand < Command
3
+ description 'Run the command specified with "path". Valid values for
4
+ "path" are contained in the pinger config file.'
5
+ option :path, restricted: true
6
+
7
+ def run
8
+ shell(options.path)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module Perus::Pinger
2
+ class ServiceStart < Command
3
+ description 'Start the init job specified with "job". Valid values
4
+ for "job" are contained in the pinger config file.'
5
+ option :job, restricted: true
6
+
7
+ def run
8
+ result = shell("sudo service #{option.job} start")
9
+ true # shell will capture any errors
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Perus::Pinger
2
+ class ServiceStop < Command
3
+ description 'Stop the init job specified with "job". Valid values
4
+ for "job" are contained in the pinger config file.'
5
+ option :job, restricted: true
6
+
7
+ def run
8
+ result = shell("sudo service #{option.job} stop")
9
+ true # shell will capture any errors
10
+ end
11
+ end
12
+ end
@@ -5,9 +5,9 @@ module Perus::Pinger
5
5
 
6
6
  def run
7
7
  if options.sudo
8
- result = shell('sudo gem upgrade perus')
8
+ result = shell('sudo gem update perus')
9
9
  else
10
- result = shell('gem upgrade perus')
10
+ result = shell('gem update perus')
11
11
  end
12
12
 
13
13
  result.include?('ERROR') ? result : true
@@ -37,6 +37,30 @@ DEFAULT_PINGER_OPTIONS = {
37
37
 
38
38
  'KillProcess' => {
39
39
  'process_name' => []
40
+ },
41
+
42
+ 'Running' => {
43
+ 'process_path' => []
44
+ },
45
+
46
+ 'UpstartStart' => {
47
+ 'job' => []
48
+ },
49
+
50
+ 'UpstartStop' => {
51
+ 'job' => []
52
+ },
53
+
54
+ 'ServiceStart' => {
55
+ 'job' => []
56
+ },
57
+
58
+ 'ServiceStop' => {
59
+ 'job' => []
60
+ },
61
+
62
+ 'RunInstalledCommand' => {
63
+ 'path' => []
40
64
  }
41
65
  }
42
66
 
data/lib/perus/pinger.rb CHANGED
@@ -17,6 +17,9 @@ module Perus
17
17
  require './pinger/commands/sleep'
18
18
  require './pinger/commands/upstart_start'
19
19
  require './pinger/commands/upstart_stop'
20
+ require './pinger/commands/service_start'
21
+ require './pinger/commands/service_stop'
22
+ require './pinger/commands/run_installed_command'
20
23
 
21
24
  # metrics
22
25
  require './pinger/metrics/chrome'
@@ -197,25 +197,27 @@ module Perus::Server
197
197
 
198
198
  # create a new action
199
199
  post '/systems/:id/actions' do
200
- action = Action.new
201
- action.system_id = params['id']
200
+ Action.add(params['id'], params)
201
+ redirect "#{url_prefix}systems/#{params['id']}#actions"
202
+ end
202
203
 
203
- if params['script_id']
204
- action.script_id = params['script_id']
205
- else
206
- command_config = CommandConfig.create_with_params(params)
207
- action.command_config_id = command_config.id
204
+ # create an action for all systems in a group
205
+ post '/groups/:id/systems/actions' do
206
+ group = Group.with_pk!(params['id'])
207
+ group.systems.each do |system|
208
+ Action.add(system.id, params)
208
209
  end
209
210
 
210
- begin
211
- action.save
212
- rescue
213
- if action.command_config_id
214
- CommandConfig.with_pk!(action.command_config_id).destroy
215
- end
211
+ redirect "#{url_prefix}groups/#{params['id']}/systems"
212
+ end
213
+
214
+ # create an action for all systems
215
+ post '/systems/actions' do
216
+ System.each do |system|
217
+ Action.add(system.id, params)
216
218
  end
217
219
 
218
- redirect "#{url_prefix}systems/#{params['id']}#actions"
220
+ redirect "#{url_prefix}systems"
219
221
  end
220
222
 
221
223
  # delete an action. deletion also clears any uploaded files.
@@ -232,16 +234,7 @@ module Perus::Server
232
234
  # overview
233
235
  get '/' do
234
236
  systems = System.all
235
- alerts = Alert.all
236
- results = alerts.collect do |alert|
237
- begin
238
- alert.execute(systems)
239
- rescue => e
240
- "An error occurred running this alert: #{e.inspect}"
241
- end
242
- end
243
-
244
- @alerts = Hash[alerts.zip(results)]
237
+ @alerts = Alert.all.sort_by(&:severity_level).reverse
245
238
  erb :index
246
239
  end
247
240
 
@@ -249,6 +242,8 @@ module Perus::Server
249
242
  get '/systems' do
250
243
  @systems = System.all.group_by(&:orientation)
251
244
  @title = 'All Systems'
245
+ @scripts = Script.all
246
+ @action_url = "systems/actions"
252
247
  erb :systems
253
248
  end
254
249
 
@@ -257,6 +252,8 @@ module Perus::Server
257
252
  group = Group.with_pk!(params['id'])
258
253
  @systems = group.systems.group_by(&:orientation)
259
254
  @title = group.name
255
+ @scripts = Script.all
256
+ @action_url = "groups/#{params['id']}/systems/actions"
260
257
  erb :systems
261
258
  end
262
259
 
@@ -281,7 +278,7 @@ module Perus::Server
281
278
 
282
279
  # make links clickable
283
280
  @links = @system.links.to_s.gsub("\n", "<br>")
284
- URI::extract(@links).each {|uri| @links.gsub!(uri, %Q{<a href="#{uri}">#{uri}</a>})}
281
+ URI::extract(@links).each {|uri| @links.gsub!(uri, %Q{<a href="#{uri}" target="_new">#{uri}</a>})}
285
282
 
286
283
  # last updated is a timestamp, conver
287
284
  if @system.last_updated
@@ -18,19 +18,24 @@ module Perus::Server
18
18
  Sequel::Migrator.run(@db, File.join(__dir__, 'migrations'))
19
19
 
20
20
  # load models - these rely on an existing db connection
21
- require File.join(__dir__, 'models', 'system')
22
- require File.join(__dir__, 'models', 'config')
23
- require File.join(__dir__, 'models', 'value')
24
- require File.join(__dir__, 'models', 'group')
25
- require File.join(__dir__, 'models', 'error')
26
- require File.join(__dir__, 'models', 'alert')
27
- require File.join(__dir__, 'models', 'action')
28
- require File.join(__dir__, 'models', 'metric')
29
- require File.join(__dir__, 'models', 'script')
30
- require File.join(__dir__, 'models', 'command_config')
31
- require File.join(__dir__, 'models', 'script_command')
32
- require File.join(__dir__, 'models', 'config_metric')
21
+ Dir.chdir(File.join(__dir__, 'models')) do
22
+ require './system'
23
+ require './config'
24
+ require './value'
25
+ require './group'
26
+ require './error'
27
+ require './alert'
28
+ require './action'
29
+ require './metric'
30
+ require './script'
31
+ require './command_config'
32
+ require './script_command'
33
+ require './config_metric'
34
+ require './active_alert'
35
+ end
36
+ end
33
37
 
38
+ def self.start_timers
34
39
  # attempt to run vacuum twice a day. this is done to increase
35
40
  # performance rather than reclaim unused space. as old values and
36
41
  # metrics are deleted the data become very fragmented. vacuuming
@@ -55,6 +60,17 @@ module Perus::Server
55
60
  # fire every hour
56
61
  cleanup_task.execution_interval = 60 * 60
57
62
  cleanup_task.execute
63
+
64
+ # alerts can be process intensive, so to keep page refreshes
65
+ # responsive the 'active' state of an alert for each system is
66
+ # cached so lookups can be done against the db, rather than running
67
+ # each alert for each system on a page load.
68
+ cache_alerts_task = Concurrent::TimerTask.new do
69
+ Perus::Server::Alert.cache_active_alerts
70
+ end
71
+
72
+ cache_alerts_task.execution_interval = Server.options.cache_alerts_mins * 60
73
+ cache_alerts_task.execute
58
74
  end
59
75
 
60
76
  def self.cleanup
@@ -0,0 +1,14 @@
1
+ Sequel.migration do
2
+ up do
3
+ create_table(:active_alerts) do
4
+ primary_key :id
5
+ Integer :alert_id, null: false
6
+ Integer :system_id, null: false
7
+ Integer :timestamp, null:false
8
+ end
9
+ end
10
+
11
+ down do
12
+ drop_table(:active_alerts)
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ Sequel.migration do
2
+ up do
3
+ alter_table(:alerts) do
4
+ add_column :errors, String
5
+ end
6
+ end
7
+
8
+ down do
9
+ alter_table(:alerts) do
10
+ drop_column :errors
11
+ end
12
+ end
13
+ end
@@ -67,5 +67,25 @@ module Perus::Server
67
67
  File.unlink(file_path)
68
68
  end
69
69
  end
70
+
71
+ def self.add(system_id, params)
72
+ action = Action.new
73
+ action.system_id = system_id
74
+
75
+ if params['script_id']
76
+ action.script_id = params['script_id']
77
+ else
78
+ command_config = CommandConfig.create_with_params(params)
79
+ action.command_config_id = command_config.id
80
+ end
81
+
82
+ begin
83
+ action.save
84
+ rescue
85
+ if action.command_config_id
86
+ CommandConfig.with_pk!(action.command_config_id).destroy
87
+ end
88
+ end
89
+ end
70
90
  end
71
91
  end
@@ -0,0 +1,24 @@
1
+ require 'chronic_duration'
2
+
3
+ module Perus::Server
4
+ class ActiveAlert < Sequel::Model
5
+ many_to_one :alert
6
+ many_to_one :system
7
+
8
+ def severity
9
+ alert.severity
10
+ end
11
+
12
+ def active_for
13
+ ChronicDuration.output(Time.now.to_i - timestamp, format: :short)
14
+ end
15
+
16
+ def self.add(alert, system)
17
+ ActiveAlert.create(
18
+ system_id: system.id,
19
+ alert_id: alert.id,
20
+ timestamp: Time.now.to_i
21
+ )
22
+ end
23
+ end
24
+ end
@@ -1,9 +1,68 @@
1
1
  module Perus::Server
2
2
  class Alert < Sequel::Model
3
- def execute(systems)
4
- systems.select do |system|
5
- system.instance_eval(code)
3
+ one_to_many :active_alerts
4
+
5
+ def execute(system)
6
+ system.instance_eval(code)
7
+ end
8
+
9
+ def execute_errors
10
+ values[:errors]
11
+ end
12
+
13
+ def severity_level
14
+ if active_alerts_dataset.empty?
15
+ 0
16
+ elsif severity == 'notice'
17
+ 1
18
+ elsif severity == 'warning'
19
+ 2
20
+ elsif severity == 'error'
21
+ 3
22
+ end
23
+ end
24
+
25
+ def after_destroy
26
+ super
27
+ active_alerts.each(&:destroy)
28
+ end
29
+
30
+ def self.cache_active_alerts
31
+ puts 'Caching active alerts'
32
+ start = Time.now
33
+ systems = System.all
34
+
35
+ Alert.each do |alert|
36
+ begin
37
+ # active_alerts are left as is if they are still active
38
+ currently_active = {}
39
+ alert.active_alerts.each do |active_alert|
40
+ currently_active[active_alert.system_id] = active_alert
41
+ end
42
+
43
+ # remove active alerts if they're no longer valid, add new
44
+ # ones as needed.
45
+ systems.each do |system|
46
+ active = alert.execute(system)
47
+ if active && !currently_active.include?(system.id)
48
+ ActiveAlert.add(alert, system)
49
+ elsif !active && currently_active.include?(system.id)
50
+ currently_active[system.id].destroy
51
+ end
52
+ end
53
+
54
+ # no errors occurred by this point, so remove the error
55
+ # string if it exists from a previous run
56
+ alert.errors = nil
57
+ rescue => e
58
+ alert.errors = e.inspect
59
+ end
60
+
61
+ # update alert.errors
62
+ alert.save
6
63
  end
64
+
65
+ puts "Caching complete, took #{Time.now - start}s"
7
66
  end
8
67
  end
9
68
  end
@@ -10,6 +10,7 @@ module Perus::Server
10
10
  one_to_many :metrics
11
11
  one_to_many :values
12
12
  one_to_many :actions
13
+ one_to_many :active_alerts
13
14
  one_to_many :collection_errors, class_name: 'Perus::Server::Error'
14
15
 
15
16
  def validate
@@ -26,11 +27,20 @@ module Perus::Server
26
27
  values.each(&:destroy)
27
28
  actions.each(&:destroy)
28
29
  collection_errors.each(&:destroy)
30
+ active_alerts.each(&:destroy)
29
31
 
30
32
  # remove any uploaded files
31
33
  FileUtils.rm_rf([uploads_dir], secure: true)
32
34
  end
33
35
 
36
+ def alert_class
37
+ return '' if active_alerts.empty?
38
+ severities = active_alerts.map(&:severity).uniq
39
+ return 'error' if severities.include?('error')
40
+ return 'warning' if severities.include?('warning')
41
+ return 'notice' if severities.include?('notice')
42
+ end
43
+
34
44
  def pending_actions
35
45
  actions_dataset.where(timestamp: nil).all
36
46
  end
@@ -78,6 +78,13 @@ main {
78
78
  margin-bottom: 30px;
79
79
  }
80
80
 
81
+ main > h1 > input {
82
+ float: right;
83
+ width: 180px;
84
+ height: 22px;
85
+ margin-top: 2px;
86
+ }
87
+
81
88
  main > h2.edit {
82
89
  margin-top: 30px;
83
90
  }
@@ -188,11 +195,12 @@ main {
188
195
 
189
196
  /* systems list */
190
197
  .systems {
191
- margin-bottom: 80px;
198
+ margin-bottom: 30px;
192
199
  }
193
200
 
194
201
  .systems a {
195
202
  display: inline-block;
203
+ position: relative;
196
204
  background-color: white;
197
205
  padding: 10px;
198
206
  border-radius: 4px;
@@ -224,6 +232,27 @@ main {
224
232
  font-weight: 300;
225
233
  }
226
234
 
235
+ .systems a div.alert {
236
+ width: 12px;
237
+ height: 12px;
238
+ border-radius: 12px;
239
+ position: absolute;
240
+ bottom: -20px;
241
+ right: 10px;
242
+ }
243
+
244
+ .systems a div.alert.error {
245
+ background-color: red;
246
+ }
247
+
248
+ .systems a div.alert.warning {
249
+ background-color: yellow;
250
+ }
251
+
252
+ .systems a div.alert.notice {
253
+ background-color: blue;
254
+ }
255
+
227
256
  .systems.portrait a {
228
257
  width: 201px;
229
258
  height: 338px;
@@ -297,6 +326,10 @@ article.graph {
297
326
  margin-bottom: 20px;
298
327
  }
299
328
 
329
+ .dygraph-legend {
330
+ background-color: rgba(255, 255, 255, 0.5) !important;
331
+ }
332
+
300
333
  /* metric collection errors */
301
334
  #errors {
302
335
  padding-top: 20px;
@@ -348,39 +381,43 @@ article.graph {
348
381
  }
349
382
 
350
383
  .alert h1 {
351
- margin-bottom: 15px;
384
+ margin-bottom: 5px;
352
385
  }
353
386
 
354
- .alert ul {
387
+ ul.alerts {
355
388
  list-style-type: none;
356
389
  padding: 0px;
357
390
  font-size: 14px;
358
391
  }
359
392
 
360
- .alert ul li {
361
- padding-left: 24px;
393
+ .alert h1 + ul.alerts {
394
+ margin-top: 10px;
395
+ }
396
+
397
+ ul.alerts li {
398
+ padding-left: 20px;
362
399
  position: relative;
363
400
  }
364
401
 
365
- .alert ul li::before {
402
+ ul.alerts li::before {
366
403
  position: absolute;
367
404
  left: 0px;
368
405
  top: 1px;
369
406
  content: ' ';
370
- width: 15px;
371
- height: 15px;
372
- border-radius: 15px;
407
+ width: 12px;
408
+ height: 12px;
409
+ border-radius: 12px;
373
410
  }
374
411
 
375
- .alert.warning ul li::before {
412
+ ul.alerts li.warning::before {
376
413
  background-color: yellow;
377
414
  }
378
415
 
379
- .alert.error ul li::before {
416
+ ul.alerts li.error::before {
380
417
  background-color: red;
381
418
  }
382
419
 
383
- .alert.notice ul li::before {
420
+ ul.alerts li.notice::before {
384
421
  background-color: blue;
385
422
  }
386
423
 
@@ -411,6 +448,10 @@ article.graph {
411
448
  margin-top: 30px;
412
449
  }
413
450
 
451
+ #no-systems + #add-command {
452
+ margin-top: 0px;
453
+ }
454
+
414
455
  #add-command select {
415
456
  margin-left: 7px;
416
457
  }
@@ -9,16 +9,18 @@ DEFAULT_SERVER_OPTIONS = {
9
9
  'port' => 3000,
10
10
  'site_name' => 'Perus',
11
11
  'url_prefix' => '/',
12
- 'keep_hours' => 24
12
+ 'keep_hours' => 24,
13
+ 'cache_alerts_mins' => 1
13
14
  }
14
15
  }
15
16
 
16
17
  module Perus::Server
17
18
  class Server
18
19
  def initialize(options_path = DEFAULT_SERVER_OPTIONS_PATH, environment = 'development')
19
- self.class.options.load(options_path, DEFAULT_SERVER_OPTIONS)
20
+ self.class.load_options(options_path)
20
21
  ENV['RACK_ENV'] = environment
21
22
  DB.start
23
+ DB.start_timers
22
24
  end
23
25
 
24
26
  def run
@@ -32,5 +34,9 @@ module Perus::Server
32
34
  def self.options
33
35
  @options ||= Perus::Options.new
34
36
  end
37
+
38
+ def self.load_options(path = DEFAULT_SERVER_OPTIONS_PATH)
39
+ options.load(path, DEFAULT_SERVER_OPTIONS)
40
+ end
35
41
  end
36
42
  end
@@ -2,19 +2,21 @@
2
2
  <% if @alerts.empty? %>
3
3
  <p>No alerts</p>
4
4
  <% else %>
5
- <% @alerts.each do |alert, systems| %>
6
- <div class="alert <%= alert.severity %>">
5
+ <% @alerts.each do |alert| %>
6
+ <div class="alert">
7
7
  <h1><%= alert.name %></h1>
8
- <% if systems.empty? %>
9
- <p>All systems functioning normally</p>
10
- <% elsif systems.is_a?(String) %>
11
- <p><%= systems.gsub('<', '&lt;').gsub('>', '&gt;') %></p>
8
+ <% unless alert.execute_errors.nil? || alert.execute_errors.empty? %>
9
+ <p>An error occurred running this alert: <%= alert.execute_errors.gsub('<', '&lt;').gsub('>', '&gt;') %></p>
12
10
  <% else %>
13
- <ul>
14
- <% systems.each do |system| %>
15
- <li><a href="<%= url_prefix %>systems/<%= system.id %>"><%= system.name %></a></li>
16
- <% end %>
17
- </ul>
11
+ <% if alert.active_alerts.empty? %>
12
+ <p>All systems functioning normally</p>
13
+ <% else %>
14
+ <ul class="alerts">
15
+ <% alert.active_alerts.each do |active_alert| %>
16
+ <li class="<%= alert.severity %>"><a href="<%= url_prefix %>systems/<%= active_alert.system.id %>"><%= active_alert.system.name %> (<%= active_alert.active_for %>)</a></li>
17
+ <% end %>
18
+ </ul>
19
+ <% end %>
18
20
  <% end %>
19
21
  </div>
20
22
  <% end %>
@@ -10,7 +10,7 @@
10
10
  <dt>Last Updated:</dt>
11
11
  <dd><%= @last_updated %></dd>
12
12
  <dt>IP:</dt>
13
- <dd><%= @system.ip %></dd>
13
+ <dd><%= @system.ip || 'unknown IP' %></dd>
14
14
  <% @str_metrics.each do |name, value| %>
15
15
  <dt><%= name %></dt>
16
16
  <dd><%= value %></dd>
@@ -19,6 +19,16 @@
19
19
  <dt>Links:</dt>
20
20
  <dd><%= @links %></dd>
21
21
  <% end %>
22
+ <% unless @system.active_alerts.empty? %>
23
+ <dt>Alerts:</dt>
24
+ <dd>
25
+ <ul class="alerts">
26
+ <% @system.active_alerts.each do |active_alert| %>
27
+ <li class="<%= active_alert.alert.severity %>"><%= active_alert.alert.name %> (<%= active_alert.active_for %>)</li>
28
+ <% end %>
29
+ </ul>
30
+ </dd>
31
+ <% end %>
22
32
  </dl>
23
33
  </section>
24
34
 
@@ -44,7 +54,14 @@
44
54
  document.getElementById("metric-<%= name %>"),
45
55
  "<%= url_prefix %>systems/<%= @system.id %>/values?metrics=<%= metrics.join(',') %>",
46
56
  {
47
- labelsSeparateLines: true
57
+ labelsSeparateLines: true,
58
+ axes: {
59
+ y: {
60
+ valueFormatter: function(y) {
61
+ return y.toFixed(2);
62
+ }
63
+ }
64
+ }
48
65
  }
49
66
  );
50
67
 
@@ -1,17 +1,86 @@
1
- <h1><%= @title %></h1>
2
-
3
- <% unless @systems.empty? %>
4
- <% @systems.each do |(orientation, systems)| %>
5
- <div class="<%= orientation %> systems">
6
- <% systems.each do |system| %>
7
- <a href="<%= url_prefix %>systems/<%= system.id %>">
8
- <div class="screenshot" style="background-image: url(<%= system.screenshot_url %>)"></div>
9
- <h1><%= system.name %></h1>
10
- <p><%= system.logical_name %> - <%= system.ip || 'unknown IP' %></p>
11
- </a>
1
+ <h1>
2
+ <%= @title %>
3
+ <input type="text" id="system-search" placeholder="search: name, logical name, ip">
4
+ </h1>
5
+
6
+ <% @systems.each do |(orientation, systems)| %>
7
+ <div class="<%= orientation %> systems">
8
+ <% systems.each do |system| %>
9
+ <a href="<%= url_prefix %>systems/<%= system.id %>" class="system">
10
+ <div class="screenshot" style="background-image: url(<%= system.screenshot_url %>)"></div>
11
+ <h1 class="system-id"><%= system.name %></h1>
12
+ <p><span class="system-id"><%= system.logical_name %></span> - <span class="system-id"><%= system.ip || 'unknown IP' %></span></p>
13
+ <div class="alert <%= system.alert_class %>"></div>
14
+ </a>
15
+ <% end %>
16
+ </div>
17
+ <% end %>
18
+ <p id="no-systems" <% unless @systems.empty? %>style="display: none"<% end %>>No Systems</p>
19
+
20
+ <p id="add-command">
21
+ Add action to <%= @title %>:
22
+ <select id="command-select">
23
+ <option></option>
24
+ <optgroup label="Commands">
25
+ <% command_actions.each do |command| %>
26
+ <option value="<%= command.name %>"><%= command.human_name %></option>
12
27
  <% end %>
13
- </div>
14
- <% end %>
15
- <% else %>
16
- <p>No Systems</p>
28
+ </optgroup>
29
+ <optgroup label="Scripts">
30
+ <% @scripts.each do |script| %>
31
+ <option value="<%= script.code_name %>"><%= script.name %></option>
32
+ <% end %>
33
+ </optgroup>
34
+ </select>
35
+ </p>
36
+
37
+ <!-- new commands -->
38
+ <% command_actions.each do |command| %>
39
+ <%= erb :command_config, locals: {command: command, action: "#{url_prefix}#{@action_url}"} %>
40
+ <% end %>
41
+ <% @scripts.each do |script| %>
42
+ <form class="command" data-command="<%= script.code_name %>" style="display: none" method="POST" action="<%= url_prefix %><%= @action_url %>">
43
+ <h1><%= script.name %></h1>
44
+ <p><%= script.description %></p>
45
+ <input type="hidden" name="script_id" value="<%= script.id %>">
46
+ <p class="actions"><input type="submit" value="Add"></p>
47
+ </form>
17
48
  <% end %>
49
+
50
+ <script>
51
+ $('#command-select').change(function() {
52
+ $('form.command').hide();
53
+ $('form[data-command="' + $(this).val() + '"]').show();
54
+ });
55
+
56
+ function filter() {
57
+ var allSystems = $('.system');
58
+ var anyMatching = false;
59
+ var query = $.trim($('#system-search').val()).toLowerCase();;
60
+
61
+ if (query == '') {
62
+ allSystems.show();
63
+ anyMatching = true;
64
+
65
+ } else {
66
+ allSystems.each(function(i, el) {
67
+ var system = $(el);
68
+ var ids = system.find('.system-id').text().toLowerCase();
69
+ if (ids.includes(query)) {
70
+ anyMatching = true;
71
+ system.show();
72
+ } else {
73
+ system.hide();
74
+ }
75
+ });
76
+ }
77
+
78
+ if (anyMatching)
79
+ $('#no-systems').hide();
80
+ else
81
+ $('#no-systems').show();
82
+ }
83
+
84
+ $('#system-search').keyup(filter);
85
+ $('#system-search').change(filter);
86
+ </script>
data/lib/perus/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Perus
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
data/lib/perus.rb CHANGED
@@ -17,9 +17,10 @@ elsif ARGV[0] == 'console'
17
17
  # start in the Server namespace
18
18
  include Perus::Server
19
19
 
20
- # console is used to access the database. initialise a server to load
21
- # default settings and start the database connection.
22
- Server.new
20
+ # console is used to access the database. initialise server options to find
21
+ # the db path and start the database connection.
22
+ Server.load_options
23
+ DB.start
23
24
 
24
25
  # remove the arg otherwise irb will try to load a file named 'console'
25
26
  ARGV.shift
data/perus.gemspec CHANGED
@@ -31,4 +31,5 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency 'sequel', '~> 4.23'
32
32
  spec.add_dependency 'iniparse', '~> 1.4'
33
33
  spec.add_dependency 'thin', '~> 1.6'
34
+ spec.add_dependency 'chronic_duration', '~> 0.10'
34
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Will Cannings
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
180
  version: '1.6'
181
+ - !ruby/object:Gem::Dependency
182
+ name: chronic_duration
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '0.10'
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '0.10'
181
195
  description:
182
196
  email:
183
197
  - me@willcannings.com
@@ -210,7 +224,10 @@ files:
210
224
  - lib/perus/pinger/commands/remove_path.rb
211
225
  - lib/perus/pinger/commands/replace.rb
212
226
  - lib/perus/pinger/commands/restart.rb
227
+ - lib/perus/pinger/commands/run_installed_command.rb
213
228
  - lib/perus/pinger/commands/script.rb
229
+ - lib/perus/pinger/commands/service_start.rb
230
+ - lib/perus/pinger/commands/service_stop.rb
214
231
  - lib/perus/pinger/commands/sleep.rb
215
232
  - lib/perus/pinger/commands/upgrade.rb
216
233
  - lib/perus/pinger/commands/upload.rb
@@ -245,7 +262,10 @@ files:
245
262
  - lib/perus/server/migrations/010_create_scripts.rb
246
263
  - lib/perus/server/migrations/011_create_script_commands.rb
247
264
  - lib/perus/server/migrations/012_create_config_metrics.rb
265
+ - lib/perus/server/migrations/013_create_active_alerts.rb
266
+ - lib/perus/server/migrations/014_alerts_can_have_errors.rb
248
267
  - lib/perus/server/models/action.rb
268
+ - lib/perus/server/models/active_alert.rb
249
269
  - lib/perus/server/models/alert.rb
250
270
  - lib/perus/server/models/command_config.rb
251
271
  - lib/perus/server/models/config.rb
@@ -327,3 +347,4 @@ signing_key:
327
347
  specification_version: 4
328
348
  summary: Simple system overview server
329
349
  test_files: []
350
+ has_rdoc: