perus 0.1.7 → 0.1.8

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 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: