perus 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/perus-pinger +3 -5
- data/exe/perus-server +14 -6
- data/lib/perus/pinger/command.rb +15 -0
- data/lib/perus/pinger/commands/chrome_execute.rb +3 -0
- data/lib/perus/pinger/commands/kill_process.rb +2 -2
- data/lib/perus/pinger/commands/upgrade.rb +2 -2
- data/lib/perus/pinger/metrics/cpu.rb +3 -3
- data/lib/perus/pinger/metrics/hd.rb +1 -1
- data/lib/perus/pinger/metrics/mem.rb +1 -1
- data/lib/perus/pinger/metrics/process.rb +6 -5
- data/lib/perus/pinger/metrics/screenshot.rb +12 -6
- data/lib/perus/pinger/metrics/temp.rb +3 -3
- data/lib/perus/pinger/metrics/uptime.rb +1 -1
- data/lib/perus/pinger/metrics/value.rb +2 -1
- data/lib/perus/pinger/pinger.rb +19 -11
- data/lib/perus/server/admin.rb +1 -0
- data/lib/perus/server/app.rb +0 -2
- data/lib/perus/server/db.rb +62 -0
- data/lib/perus/server/form.rb +5 -2
- data/lib/perus/server/helpers.rb +4 -0
- data/lib/perus/server/models/config.rb +4 -0
- data/lib/perus/server/models/group.rb +12 -0
- data/lib/perus/server/models/metric.rb +13 -0
- data/lib/perus/server/models/script.rb +5 -0
- data/lib/perus/server/models/system.rb +13 -0
- data/lib/perus/server/public/css/style.css +10 -3
- data/lib/perus/server/server.rb +4 -2
- data/lib/perus/server/views/admin/index.erb +18 -2
- data/lib/perus/server/views/command_config.erb +1 -1
- data/lib/perus/server/views/errors.erb +1 -1
- data/lib/perus/server/views/system.erb +1 -1
- data/lib/perus/version.rb +1 -1
- data/lib/perus.rb +15 -0
- data/perus.gemspec +0 -2
- metadata +2 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bae9eee51f945b6f2ba014af73f5cdfa8fa6ab03
|
4
|
+
data.tar.gz: 3253602c339568d245a4a448abbd3990cf89479f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a88068ed77a22b0e7fa210394931994053dcca0d0e8b025f01e1638623f462024ebabf83a9e67c8a4f442879bdaa6f5dbda86485698bc86d57af327c253bd36
|
7
|
+
data.tar.gz: e7611359ef127aef4bbad47f0ed74baf32cf59fd808e7484fd658e108d2b0f93008655d41b672b022143ddea8cac3358629a963c274e187f13e4955bfe0e720c
|
data/exe/perus-pinger
CHANGED
@@ -4,10 +4,10 @@ require 'optparse'
|
|
4
4
|
|
5
5
|
options_path = Perus::Pinger::DEFAULT_PINGER_OPTIONS_PATH
|
6
6
|
|
7
|
-
|
7
|
+
OptionParser.new do |opts|
|
8
8
|
opts.banner = "Usage: perus-pinger [options]"
|
9
9
|
|
10
|
-
opts.on('-c', '--config',
|
10
|
+
opts.on('-c', '--config PATH', "Path to config file (default: #{Perus::Pinger::DEFAULT_PINGER_OPTIONS_PATH})") do |c|
|
11
11
|
options_path = c
|
12
12
|
end
|
13
13
|
|
@@ -15,9 +15,7 @@ ARGV.options do |opts|
|
|
15
15
|
puts opts
|
16
16
|
exit
|
17
17
|
end
|
18
|
-
|
19
|
-
opts.parse!
|
20
|
-
end
|
18
|
+
end.parse!
|
21
19
|
|
22
20
|
pinger = Perus::Pinger::Pinger.new(options_path)
|
23
21
|
pinger.run
|
data/exe/perus-server
CHANGED
@@ -3,21 +3,29 @@ require 'perus'
|
|
3
3
|
require 'optparse'
|
4
4
|
|
5
5
|
options_path = Perus::Server::DEFAULT_SERVER_OPTIONS_PATH
|
6
|
+
environment = 'development'
|
6
7
|
|
7
|
-
|
8
|
+
OptionParser.new do |opts|
|
8
9
|
opts.banner = "Usage: perus-server [options]"
|
9
10
|
|
10
|
-
opts.on('-c', '--config',
|
11
|
+
opts.on('-c', '--config PATH', "Path to config file (default: #{Perus::Server::DEFAULT_SERVER_OPTIONS_PATH})") do |c|
|
11
12
|
options_path = c
|
12
13
|
end
|
13
14
|
|
15
|
+
opts.on('-e', '--env ENV', "Environment (values: development (default), production)") do |e|
|
16
|
+
environment = e
|
17
|
+
|
18
|
+
unless %w{development production}.include?(e)
|
19
|
+
puts 'Environment must be "development" or "production"'
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
14
24
|
opts.on('-h', '--help', 'Prints this help') do
|
15
25
|
puts opts
|
16
26
|
exit
|
17
27
|
end
|
28
|
+
end.parse!
|
18
29
|
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
server = Perus::Server::Server.new(options_path)
|
30
|
+
server = Perus::Server::Server.new(options_path, environment)
|
23
31
|
server.run
|
data/lib/perus/pinger/command.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ostruct'
|
2
|
+
require 'open3'
|
2
3
|
|
3
4
|
module Perus::Pinger
|
4
5
|
class Option
|
@@ -119,5 +120,19 @@ module Perus::Pinger
|
|
119
120
|
# called after sending data to server. remove temporary
|
120
121
|
# files etc.
|
121
122
|
end
|
123
|
+
|
124
|
+
# helper function to run shell commands and return early if anything
|
125
|
+
# is written to stderr or the command didn't run successfully
|
126
|
+
class ShellCommandError < StandardError; end
|
127
|
+
def shell(command)
|
128
|
+
out, err, status = Open3.capture3(command)
|
129
|
+
raise ShellCommandError.new(err.strip) unless err.empty?
|
130
|
+
raise ShellCommandError.new(out.strip) if status.exitstatus > 0
|
131
|
+
out
|
132
|
+
end
|
133
|
+
|
134
|
+
def darwin?
|
135
|
+
shell('uname -s').strip == 'Darwin'
|
136
|
+
end
|
122
137
|
end
|
123
138
|
end
|
@@ -6,8 +6,8 @@ module Perus::Pinger
|
|
6
6
|
option :signal, default: 'KILL'
|
7
7
|
|
8
8
|
def run
|
9
|
-
result =
|
10
|
-
|
9
|
+
result = shell("killall -#{option.signal} #{option.process_name}")
|
10
|
+
true # shell will capture any errors
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -5,9 +5,9 @@ module Perus::Pinger
|
|
5
5
|
|
6
6
|
def run
|
7
7
|
if options.sudo
|
8
|
-
result =
|
8
|
+
result = shell('sudo gem upgrade perus')
|
9
9
|
else
|
10
|
-
result =
|
10
|
+
result = shell('gem upgrade perus')
|
11
11
|
end
|
12
12
|
|
13
13
|
result.include?('ERROR') ? result : true
|
@@ -5,10 +5,10 @@ module Perus::Pinger
|
|
5
5
|
metric!
|
6
6
|
|
7
7
|
def run
|
8
|
-
if
|
9
|
-
percent = 100 -
|
8
|
+
if darwin?
|
9
|
+
percent = 100 - shell('iostat dxxvdfs -n 0').split("\n")[2].split[2].to_i
|
10
10
|
else
|
11
|
-
percent =
|
11
|
+
percent = shell("grep 'cpu ' /proc/stat | awk '{print (1 - ($5 / ($2+$3+$4+$5+$6+$7+$8)))*100}'")
|
12
12
|
end
|
13
13
|
|
14
14
|
{cpu_all: percent.to_f}
|
@@ -4,7 +4,7 @@ module Perus::Pinger
|
|
4
4
|
metric!
|
5
5
|
|
6
6
|
def run
|
7
|
-
percent =
|
7
|
+
percent = shell(%q[cat /proc/meminfo | awk '{if ($1=="MemTotal:") total = $2; if ($1 == "MemFree:") free = $2;} END {print (1 - (free / total))*100}'])
|
8
8
|
{mem_all: percent.to_f}
|
9
9
|
end
|
10
10
|
end
|
@@ -10,12 +10,13 @@ module Perus::Pinger
|
|
10
10
|
metric!
|
11
11
|
|
12
12
|
def run
|
13
|
-
path = options.process_path.gsub("/", "
|
14
|
-
cpu, mem =
|
15
|
-
|
16
|
-
|
13
|
+
path = options.process_path.gsub("/", "\\/")
|
14
|
+
cpu, mem = shell("ps aux | awk '/#{path}/ {cpu += $3; mem += $4} END {print cpu, mem;}'").split
|
15
|
+
|
16
|
+
if darwin?
|
17
|
+
core_count = shell('sysctl -n hw.ncpu')
|
17
18
|
else
|
18
|
-
core_count =
|
19
|
+
core_count = shell("cat /proc/cpuinfo | grep processor | awk '{count += 1} END {print count}'")
|
19
20
|
end
|
20
21
|
|
21
22
|
{
|
@@ -9,19 +9,22 @@ module Perus::Pinger
|
|
9
9
|
metric!
|
10
10
|
|
11
11
|
def run
|
12
|
-
if
|
12
|
+
if darwin?
|
13
13
|
if options.resize[-1] != '%'
|
14
14
|
raise 'Non percent resize option unsupported by OS X currently'
|
15
15
|
else
|
16
16
|
percent = options.resize.to_f / 100
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
width =
|
21
|
-
height =
|
19
|
+
shell("screencapture -m -t jpg -x #{options.path}")
|
20
|
+
width = shell("sips -g pixelWidth #{options.path}").match(/pixelWidth: (\d+)/)[1]
|
21
|
+
height = shell("sips -g pixelHeight #{options.path}").match(/pixelHeight: (\d+)/)[1]
|
22
|
+
|
23
|
+
# sips helpfully prints data to stderr, so it's run with
|
24
|
+
# backticks to avoid thowing an exception on success
|
22
25
|
`sips -z #{height.to_i * percent} #{width.to_i * percent} #{options.path}`
|
23
26
|
else
|
24
|
-
|
27
|
+
shell("export DISPLAY=:0; import -window root -resize #{options.resize} #{options.path}")
|
25
28
|
end
|
26
29
|
|
27
30
|
@screenshot_file = File.new(options.path)
|
@@ -29,7 +32,10 @@ module Perus::Pinger
|
|
29
32
|
end
|
30
33
|
|
31
34
|
def cleanup
|
32
|
-
@screenshot_file.
|
35
|
+
unless @screenshot_file.nil? || @screenshot_file.closed?
|
36
|
+
@screenshot_file.close
|
37
|
+
end
|
38
|
+
|
33
39
|
File.delete(options.path)
|
34
40
|
end
|
35
41
|
end
|
@@ -6,10 +6,10 @@ module Perus::Pinger
|
|
6
6
|
metric!
|
7
7
|
|
8
8
|
def run
|
9
|
-
if
|
10
|
-
degrees =
|
9
|
+
if darwin?
|
10
|
+
degrees = shell('istats cpu temp').split[2].match(/([0-9\.]+)/)[0]
|
11
11
|
else
|
12
|
-
degrees =
|
12
|
+
degrees = shell(%q[sensors | grep "#{options.device}:"]).match(/#{options.device}:\s+(\S+)/)[1]
|
13
13
|
end
|
14
14
|
|
15
15
|
{temp: degrees.to_f}
|
@@ -10,7 +10,8 @@ module Perus::Pinger
|
|
10
10
|
metric!
|
11
11
|
|
12
12
|
def run
|
13
|
-
|
13
|
+
grep = optipns.grep.gsub('"', '\\"')
|
14
|
+
line = shell(%q[cat #{options.path} | egrep "#{grep}"])
|
14
15
|
value = line.match(Regexp.compile(options.match))[1]
|
15
16
|
{options.name => value}
|
16
17
|
end
|
data/lib/perus/pinger/pinger.rb
CHANGED
@@ -51,8 +51,8 @@ module Perus::Pinger
|
|
51
51
|
|
52
52
|
# cache urls on initialisation since the urls depend on values known
|
53
53
|
# at startup and that won't change over the object lifetime
|
54
|
-
config_path = URI("
|
55
|
-
pinger_path = URI("
|
54
|
+
config_path = URI("systems/#{Pinger.options.system_id}/config")
|
55
|
+
pinger_path = URI("systems/#{Pinger.options.system_id}/ping")
|
56
56
|
server_uri = URI(Pinger.options.server)
|
57
57
|
|
58
58
|
@config_url = (server_uri + config_path).to_s
|
@@ -92,10 +92,10 @@ module Perus::Pinger
|
|
92
92
|
@metric_errors[metric.name] ||= []
|
93
93
|
@metrics << metric.new(config['options'])
|
94
94
|
else
|
95
|
-
@metric_errors[config['type']] = e
|
95
|
+
@metric_errors[config['type']] = format_exception(e)
|
96
96
|
end
|
97
97
|
rescue => e
|
98
|
-
@metric_errors[metric.name] << e
|
98
|
+
@metric_errors[metric.name] << format_exception(e)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -105,7 +105,7 @@ module Perus::Pinger
|
|
105
105
|
@actions << command.new(config['options'], config['id'])
|
106
106
|
rescue => e
|
107
107
|
if config['id']
|
108
|
-
@action_results[config['id']] = e
|
108
|
+
@action_results[config['id']] = format_exception(e)
|
109
109
|
else
|
110
110
|
puts 'Error - action does not have an associated id'
|
111
111
|
p config
|
@@ -117,13 +117,21 @@ module Perus::Pinger
|
|
117
117
|
#----------------------
|
118
118
|
# run
|
119
119
|
#----------------------
|
120
|
+
def format_exception(e)
|
121
|
+
if e.backtrace.empty?
|
122
|
+
e.inspect
|
123
|
+
else
|
124
|
+
"#{e.inspect}\n#{e.backtrace.first}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
120
128
|
def run_metrics
|
121
129
|
@metrics.each do |metric|
|
122
130
|
begin
|
123
131
|
result = metric.run
|
124
132
|
@metric_results.merge!(result)
|
125
133
|
rescue => e
|
126
|
-
@metric_errors[metric.class.name] << e
|
134
|
+
@metric_errors[metric.class.name] << format_exception(e)
|
127
135
|
end
|
128
136
|
end
|
129
137
|
end
|
@@ -141,7 +149,7 @@ module Perus::Pinger
|
|
141
149
|
@action_results[action.id] = result
|
142
150
|
|
143
151
|
rescue => e
|
144
|
-
@action_results[action.id] = e
|
152
|
+
@action_results[action.id] = format_exception(e)
|
145
153
|
end
|
146
154
|
end
|
147
155
|
end
|
@@ -179,7 +187,7 @@ module Perus::Pinger
|
|
179
187
|
RestClient.post(@pinger_url, payload)
|
180
188
|
rescue => e
|
181
189
|
puts 'Ping failed with exception'
|
182
|
-
puts e
|
190
|
+
puts format_exception(e)
|
183
191
|
end
|
184
192
|
end
|
185
193
|
|
@@ -192,7 +200,7 @@ module Perus::Pinger
|
|
192
200
|
metric.cleanup
|
193
201
|
rescue => e
|
194
202
|
puts 'Error running metric cleanup'
|
195
|
-
puts e
|
203
|
+
puts format_exception(e)
|
196
204
|
end
|
197
205
|
end
|
198
206
|
|
@@ -201,7 +209,7 @@ module Perus::Pinger
|
|
201
209
|
action.cleanup
|
202
210
|
rescue => e
|
203
211
|
puts 'Error running action cleanup'
|
204
|
-
puts e
|
212
|
+
puts format_exception(e)
|
205
213
|
end
|
206
214
|
end
|
207
215
|
|
@@ -210,7 +218,7 @@ module Perus::Pinger
|
|
210
218
|
code.call
|
211
219
|
rescue => e
|
212
220
|
puts 'Error running late action'
|
213
|
-
puts e
|
221
|
+
puts format_exception(e)
|
214
222
|
end
|
215
223
|
end
|
216
224
|
end
|
data/lib/perus/server/admin.rb
CHANGED
data/lib/perus/server/app.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'sinatra/base'
|
2
|
-
require 'sinatra/synchrony'
|
3
2
|
require 'sinatra/reloader'
|
4
3
|
require 'sequel'
|
5
4
|
require 'json'
|
@@ -10,7 +9,6 @@ module Perus::Server
|
|
10
9
|
#----------------------
|
11
10
|
# config
|
12
11
|
#----------------------
|
13
|
-
register Sinatra::Synchrony
|
14
12
|
helpers Helpers
|
15
13
|
|
16
14
|
configure do
|
data/lib/perus/server/db.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'sequel'
|
2
2
|
require 'sequel/plugins/serialization'
|
3
|
+
require 'concurrent'
|
3
4
|
|
4
5
|
module Perus::Server
|
5
6
|
module DB
|
7
|
+
def self.db
|
8
|
+
@db
|
9
|
+
end
|
10
|
+
|
6
11
|
def self.start
|
12
|
+
puts 'Loading database'
|
7
13
|
Sequel.extension :migration
|
8
14
|
Sequel.extension :inflector
|
9
15
|
|
@@ -24,6 +30,62 @@ module Perus::Server
|
|
24
30
|
require File.join(__dir__, 'models', 'command_config')
|
25
31
|
require File.join(__dir__, 'models', 'script_command')
|
26
32
|
require File.join(__dir__, 'models', 'config_metric')
|
33
|
+
|
34
|
+
# attempt to run vacuum twice a day. this is done to increase
|
35
|
+
# performance rather than reclaim unused space. as old values and
|
36
|
+
# metrics are deleted the data become very fragmented. vacuuming
|
37
|
+
# restructures the db so system records in the values index should
|
38
|
+
# be sequentially stored
|
39
|
+
vacuum_task = Concurrent::TimerTask.new do
|
40
|
+
@db.execute('vacuum')
|
41
|
+
end
|
42
|
+
|
43
|
+
# fire every 12 hours
|
44
|
+
vacuum_task.execution_interval = 60 * 60 * 12
|
45
|
+
vacuum_task.execute
|
46
|
+
|
47
|
+
# a fixed number of hours of data are kept in the database. once an
|
48
|
+
# hour, old values and files are removed. if all values of a metric
|
49
|
+
# are removed from a system, the accompanying metric record is also
|
50
|
+
# removed.
|
51
|
+
cleanup_task = Concurrent::TimerTask.new do
|
52
|
+
Perus::Server::DB.cleanup
|
53
|
+
end
|
54
|
+
|
55
|
+
# fire every hour
|
56
|
+
cleanup_task.execution_interval = 60 * 60
|
57
|
+
cleanup_task.execute
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.cleanup
|
61
|
+
puts 'Cleaning old values and metrics'
|
62
|
+
keep_hours = Server.options.keep_hours
|
63
|
+
|
64
|
+
# remove old values
|
65
|
+
min_timestamp = Time.now.to_i - (keep_hours * 60)
|
66
|
+
values = Value.where("timestamp < #{min_timestamp}")
|
67
|
+
puts "Deleting #{values.count} values"
|
68
|
+
values.each(&:destroy)
|
69
|
+
|
70
|
+
# remove metrics from systems if they no longer have any values
|
71
|
+
empty_deleted = 0
|
72
|
+
file_deleted = 0
|
73
|
+
|
74
|
+
Metric.each do |metric|
|
75
|
+
if metric.file
|
76
|
+
path = metric.path
|
77
|
+
if !File.exists?(path) || File.mtime(path).to_i < min_timestamp
|
78
|
+
metric.destroy
|
79
|
+
file_deleted += 1
|
80
|
+
end
|
81
|
+
elsif metric.values_dataset.empty?
|
82
|
+
metric.destroy
|
83
|
+
empty_deleted += 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
puts "#{empty_deleted} metrics were deleted as they had no values"
|
88
|
+
puts "#{file_deleted} metrics were deleted as they had old files"
|
27
89
|
end
|
28
90
|
end
|
29
91
|
end
|
data/lib/perus/server/form.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Perus::Server
|
2
2
|
class Form
|
3
|
+
include Helpers
|
4
|
+
|
3
5
|
def initialize(record)
|
4
6
|
@record = record
|
5
7
|
end
|
@@ -33,7 +35,8 @@ module Perus::Server
|
|
33
35
|
end
|
34
36
|
|
35
37
|
def input(field, options)
|
36
|
-
|
38
|
+
value = escape_quotes(@record.send(field))
|
39
|
+
"<input type=\"text\" name=\"record[#{field}]\" value=\"#{value}\">"
|
37
40
|
end
|
38
41
|
|
39
42
|
def textarea(field, options)
|
@@ -56,7 +59,7 @@ module Perus::Server
|
|
56
59
|
existing = @record.send(field)
|
57
60
|
option_rows = options.collect do |(value, name)|
|
58
61
|
selected = existing == value ? 'selected' : ''
|
59
|
-
"<option value=\"#{value}\" #{selected}>#{name || value}</option>"
|
62
|
+
"<option value=\"#{escape_quotes(value)}\" #{selected}>#{name || value}</option>"
|
60
63
|
end
|
61
64
|
|
62
65
|
"<select name=\"record[#{field}]\">#{option_rows.join("\n")}</select>"
|
data/lib/perus/server/helpers.rb
CHANGED
@@ -8,5 +8,17 @@ module Perus::Server
|
|
8
8
|
validates_presence :name
|
9
9
|
validates_unique :name
|
10
10
|
end
|
11
|
+
|
12
|
+
def after_destroy
|
13
|
+
super
|
14
|
+
|
15
|
+
# rather than deleting all systems in a group, each system in the
|
16
|
+
# group is just removed from the group instead. this is better than
|
17
|
+
# accidentally removing a group and all related system data.
|
18
|
+
systems.each do |system|
|
19
|
+
system.group_id = nil
|
20
|
+
system.save
|
21
|
+
end
|
22
|
+
end
|
11
23
|
end
|
12
24
|
end
|
@@ -24,6 +24,19 @@ module Perus::Server
|
|
24
24
|
(prefix + path).to_s
|
25
25
|
end
|
26
26
|
|
27
|
+
def path
|
28
|
+
File.join(system.uploads_dir, file['filename'])
|
29
|
+
end
|
30
|
+
|
31
|
+
def values_dataset
|
32
|
+
system.values_dataset.where(metric: name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def after_destroy
|
36
|
+
super
|
37
|
+
File.unlink(path) if file && File.exists?(path)
|
38
|
+
end
|
39
|
+
|
27
40
|
def self.add(name, system_id, type, file_data = nil)
|
28
41
|
existing = Metric.where(system_id: system_id, name: name, type: type).first
|
29
42
|
|
@@ -2,6 +2,7 @@ module Perus::Server
|
|
2
2
|
class Script < Sequel::Model
|
3
3
|
plugin :validation_helpers
|
4
4
|
one_to_many :script_commands, order: 'name asc'
|
5
|
+
one_to_many :actions
|
5
6
|
|
6
7
|
def code_name
|
7
8
|
name.gsub(' ', '_').camelize
|
@@ -25,6 +26,10 @@ module Perus::Server
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
29
|
+
def can_delete?
|
30
|
+
actions_dataset.empty?
|
31
|
+
end
|
32
|
+
|
28
33
|
def validate
|
29
34
|
super
|
30
35
|
validates_presence :name
|
@@ -18,6 +18,19 @@ module Perus::Server
|
|
18
18
|
validates_unique :name
|
19
19
|
end
|
20
20
|
|
21
|
+
def after_destroy
|
22
|
+
super
|
23
|
+
|
24
|
+
# remove dependent records
|
25
|
+
metrics.each(&:destroy)
|
26
|
+
values.each(&:destroy)
|
27
|
+
actions.each(&:destroy)
|
28
|
+
collection_errors.each(&:destroy)
|
29
|
+
|
30
|
+
# remove any uploaded files
|
31
|
+
FileUtils.rm_rf([uploads_dir], secure: true)
|
32
|
+
end
|
33
|
+
|
21
34
|
def pending_actions
|
22
35
|
actions_dataset.where(timestamp: nil).all
|
23
36
|
end
|
@@ -252,14 +252,21 @@ main {
|
|
252
252
|
#meta img {
|
253
253
|
display: inline-block;
|
254
254
|
vertical-align: top;
|
255
|
-
width: 450px;
|
256
255
|
margin-right: 30px;
|
257
256
|
}
|
258
257
|
|
258
|
+
#meta.portrait img, #meta.other img {
|
259
|
+
width: 250px;
|
260
|
+
}
|
261
|
+
|
262
|
+
#meta.landscape img {
|
263
|
+
width: 450px;
|
264
|
+
}
|
265
|
+
|
259
266
|
#meta dl {
|
260
267
|
display: inline-block;
|
261
268
|
vertical-align: top;
|
262
|
-
width:
|
269
|
+
width: 450px;
|
263
270
|
}
|
264
271
|
|
265
272
|
#meta dt, #meta dd {
|
@@ -275,7 +282,7 @@ main {
|
|
275
282
|
}
|
276
283
|
|
277
284
|
#meta dd {
|
278
|
-
width:
|
285
|
+
width: 390px;
|
279
286
|
line-height: 16px;
|
280
287
|
}
|
281
288
|
|
data/lib/perus/server/server.rb
CHANGED
@@ -8,14 +8,16 @@ DEFAULT_SERVER_OPTIONS = {
|
|
8
8
|
'listen' => '0.0.0.0',
|
9
9
|
'port' => 3000,
|
10
10
|
'site_name' => 'Perus',
|
11
|
-
'url_prefix' => '/'
|
11
|
+
'url_prefix' => '/',
|
12
|
+
'keep_hours' => 24
|
12
13
|
}
|
13
14
|
}
|
14
15
|
|
15
16
|
module Perus::Server
|
16
17
|
class Server
|
17
|
-
def initialize(options_path = DEFAULT_SERVER_OPTIONS_PATH)
|
18
|
+
def initialize(options_path = DEFAULT_SERVER_OPTIONS_PATH, environment = 'development')
|
18
19
|
self.class.options.load(options_path, DEFAULT_SERVER_OPTIONS)
|
20
|
+
ENV['RACK_ENV'] = environment
|
19
21
|
DB.start
|
20
22
|
end
|
21
23
|
|
@@ -5,8 +5,17 @@
|
|
5
5
|
<table>
|
6
6
|
<% @records.each do |record| %>
|
7
7
|
<tr>
|
8
|
-
<td
|
9
|
-
|
8
|
+
<td>
|
9
|
+
<a href="<%= url_prefix %>admin/<%= @plural %>/<%= record.id %>"><%= record.name %></a>
|
10
|
+
</td>
|
11
|
+
<td>
|
12
|
+
<% if !record.respond_to?(:can_delete?) || record.can_delete? %>
|
13
|
+
<form class="delete-row" action="<%= url_prefix %>admin/<%= @plural %>/<%= record.id %>" method="POST">
|
14
|
+
<input type="hidden" name="_method" value="DELETE">
|
15
|
+
<input type="submit" value="Delete">
|
16
|
+
</form>
|
17
|
+
<% end %>
|
18
|
+
</td>
|
10
19
|
</tr>
|
11
20
|
<% end %>
|
12
21
|
</table>
|
@@ -16,3 +25,10 @@
|
|
16
25
|
</section>
|
17
26
|
|
18
27
|
<p class="actions"><a href="<%= url_prefix %>admin/<%= @plural %>/new">New <%= @title.downcase %></a></p>
|
28
|
+
|
29
|
+
<script>
|
30
|
+
$('form.delete-row').submit(function(event) {
|
31
|
+
if (!confirm('Are you sure you want to delete this <%= @singular %>?'))
|
32
|
+
event.preventDefault();
|
33
|
+
});
|
34
|
+
</script>
|
@@ -19,7 +19,7 @@
|
|
19
19
|
<% end %>
|
20
20
|
</select>
|
21
21
|
<% else %>
|
22
|
-
<input type="text" name="options[<%= option.name %>]" placeholder="<%= option.default %>" value="<%= command_options[option.name.to_s] if defined?(command_options) %>">
|
22
|
+
<input type="text" name="options[<%= option.name %>]" placeholder="<%= option.default %>" value="<%= escape_quotes(command_options[option.name.to_s]) if defined?(command_options) %>">
|
23
23
|
<% end %>
|
24
24
|
</span>
|
25
25
|
</p>
|
data/lib/perus/version.rb
CHANGED
data/lib/perus.rb
CHANGED
@@ -7,6 +7,21 @@ end
|
|
7
7
|
|
8
8
|
if ARGV[0] == 'server'
|
9
9
|
Perus::Server::Server.new.run
|
10
|
+
|
10
11
|
elsif ARGV[0] == 'pinger'
|
11
12
|
Perus::Pinger::Pinger.new.run
|
13
|
+
|
14
|
+
elsif ARGV[0] == 'console'
|
15
|
+
require 'irb'
|
16
|
+
|
17
|
+
# start in the Server namespace
|
18
|
+
include Perus::Server
|
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
|
23
|
+
|
24
|
+
# remove the arg otherwise irb will try to load a file named 'console'
|
25
|
+
ARGV.shift
|
26
|
+
IRB.start
|
12
27
|
end
|
data/perus.gemspec
CHANGED
@@ -26,8 +26,6 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_dependency 'faye-websocket', '~> 0.9'
|
27
27
|
spec.add_dependency 'rest-client', '~> 1.8'
|
28
28
|
spec.add_dependency 'sinatra', '~> 1.4'
|
29
|
-
spec.add_dependency 'sinatra-synchrony', '~> 0.4'
|
30
|
-
spec.add_dependency 'sinatra-websocket', '~> 0.3'
|
31
29
|
spec.add_dependency 'sinatra-contrib', '~> 1.4'
|
32
30
|
spec.add_dependency 'sqlite3', '~> 1.3'
|
33
31
|
spec.add_dependency 'sequel', '~> 4.23'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Will Cannings
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,34 +108,6 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.4'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: sinatra-synchrony
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0.4'
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0.4'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: sinatra-websocket
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - "~>"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0.3'
|
132
|
-
type: :runtime
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - "~>"
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0.3'
|
139
111
|
- !ruby/object:Gem::Dependency
|
140
112
|
name: sinatra-contrib
|
141
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -352,4 +324,3 @@ signing_key:
|
|
352
324
|
specification_version: 4
|
353
325
|
summary: Simple system overview server
|
354
326
|
test_files: []
|
355
|
-
has_rdoc:
|