perus 0.1.2 → 0.1.3
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/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:
|