perus 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +16 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/perus-pinger +23 -0
- data/exe/perus-server +23 -0
- data/lib/perus/options.rb +30 -0
- data/lib/perus/pinger/chrome_command.rb +54 -0
- data/lib/perus/pinger/command.rb +123 -0
- data/lib/perus/pinger/commands/chrome_execute.rb +26 -0
- data/lib/perus/pinger/commands/chrome_navigate.rb +25 -0
- data/lib/perus/pinger/commands/chrome_reload.rb +29 -0
- data/lib/perus/pinger/commands/kill_process.rb +13 -0
- data/lib/perus/pinger/commands/remove_path.rb +15 -0
- data/lib/perus/pinger/commands/replace.rb +18 -0
- data/lib/perus/pinger/commands/restart.rb +9 -0
- data/lib/perus/pinger/commands/script.rb +59 -0
- data/lib/perus/pinger/commands/upgrade.rb +16 -0
- data/lib/perus/pinger/commands/upload.rb +15 -0
- data/lib/perus/pinger/metrics/chrome.rb +33 -0
- data/lib/perus/pinger/metrics/cpu.rb +17 -0
- data/lib/perus/pinger/metrics/hd.rb +14 -0
- data/lib/perus/pinger/metrics/mem.rb +11 -0
- data/lib/perus/pinger/metrics/process.rb +27 -0
- data/lib/perus/pinger/metrics/screenshot.rb +36 -0
- data/lib/perus/pinger/metrics/temp.rb +18 -0
- data/lib/perus/pinger/metrics/uptime.rb +10 -0
- data/lib/perus/pinger/metrics/value.rb +18 -0
- data/lib/perus/pinger/pinger.rb +218 -0
- data/lib/perus/pinger.rb +38 -0
- data/lib/perus/server/admin.rb +83 -0
- data/lib/perus/server/app.rb +304 -0
- data/lib/perus/server/db.rb +29 -0
- data/lib/perus/server/form.rb +73 -0
- data/lib/perus/server/helpers.rb +36 -0
- data/lib/perus/server/migrations/001_create_systems.rb +20 -0
- data/lib/perus/server/migrations/002_create_configs.rb +12 -0
- data/lib/perus/server/migrations/003_create_values.rb +23 -0
- data/lib/perus/server/migrations/004_create_groups.rb +12 -0
- data/lib/perus/server/migrations/005_create_errors.rb +15 -0
- data/lib/perus/server/migrations/006_create_alerts.rb +14 -0
- data/lib/perus/server/migrations/007_create_actions.rb +18 -0
- data/lib/perus/server/migrations/008_create_metrics.rb +16 -0
- data/lib/perus/server/migrations/009_create_command_config.rb +13 -0
- data/lib/perus/server/migrations/010_create_scripts.rb +13 -0
- data/lib/perus/server/migrations/011_create_script_commands.rb +14 -0
- data/lib/perus/server/migrations/012_create_config_metrics.rb +14 -0
- data/lib/perus/server/models/action.rb +71 -0
- data/lib/perus/server/models/alert.rb +9 -0
- data/lib/perus/server/models/command_config.rb +58 -0
- data/lib/perus/server/models/config.rb +30 -0
- data/lib/perus/server/models/config_metric.rb +15 -0
- data/lib/perus/server/models/error.rb +5 -0
- data/lib/perus/server/models/group.rb +12 -0
- data/lib/perus/server/models/metric.rb +53 -0
- data/lib/perus/server/models/script.rb +39 -0
- data/lib/perus/server/models/script_command.rb +15 -0
- data/lib/perus/server/models/system.rb +160 -0
- data/lib/perus/server/models/value.rb +11 -0
- data/lib/perus/server/public/css/reset.css +102 -0
- data/lib/perus/server/public/css/style.css +461 -0
- data/lib/perus/server/public/fonts/opensans/OpenSans-Italic.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/OpenSans-Light.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/OpenSans-LightItalic.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/OpenSans-Regular.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/OpenSans-Semibold.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/OpenSans-SemiboldItalic.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-light-webfont.eot +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-light-webfont.svg +1824 -0
- data/lib/perus/server/public/fonts/opensans/opensans-light-webfont.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-light-webfont.woff +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-light-webfont.woff2 +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-regular-webfont.eot +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-regular-webfont.svg +1824 -0
- data/lib/perus/server/public/fonts/opensans/opensans-regular-webfont.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-regular-webfont.woff +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-regular-webfont.woff2 +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-semibold-webfont.eot +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-semibold-webfont.svg +1824 -0
- data/lib/perus/server/public/fonts/opensans/opensans-semibold-webfont.ttf +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-semibold-webfont.woff +0 -0
- data/lib/perus/server/public/fonts/opensans/opensans-semibold-webfont.woff2 +0 -0
- data/lib/perus/server/public/fonts/opensans/stylesheet.css +35 -0
- data/lib/perus/server/public/js/dygraph-combined.js +6 -0
- data/lib/perus/server/public/js/jquery.js +4 -0
- data/lib/perus/server/server.rb +32 -0
- data/lib/perus/server/views/admin/edit.erb +9 -0
- data/lib/perus/server/views/admin/index.erb +18 -0
- data/lib/perus/server/views/admin/new.erb +5 -0
- data/lib/perus/server/views/alerts/form.erb +3 -0
- data/lib/perus/server/views/command_config.erb +37 -0
- data/lib/perus/server/views/configs/edit.erb +36 -0
- data/lib/perus/server/views/configs/form.erb +1 -0
- data/lib/perus/server/views/errors.erb +6 -0
- data/lib/perus/server/views/groups/form.erb +1 -0
- data/lib/perus/server/views/index.erb +21 -0
- data/lib/perus/server/views/layout.erb +44 -0
- data/lib/perus/server/views/scripts/edit.erb +36 -0
- data/lib/perus/server/views/scripts/form.erb +2 -0
- data/lib/perus/server/views/system.erb +202 -0
- data/lib/perus/server/views/systems/form.erb +6 -0
- data/lib/perus/server/views/systems.erb +17 -0
- data/lib/perus/server.rb +24 -0
- data/lib/perus/version.rb +3 -0
- data/lib/perus.rb +10 -0
- data/perus.gemspec +36 -0
- metadata +354 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
require 'sinatra/base'
|
|
2
|
+
require 'sinatra/synchrony'
|
|
3
|
+
require 'sinatra/reloader'
|
|
4
|
+
require 'sequel'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'uri'
|
|
7
|
+
|
|
8
|
+
module Perus::Server
|
|
9
|
+
class App < Sinatra::Application
|
|
10
|
+
#----------------------
|
|
11
|
+
# config
|
|
12
|
+
#----------------------
|
|
13
|
+
register Sinatra::Synchrony
|
|
14
|
+
helpers Helpers
|
|
15
|
+
|
|
16
|
+
configure do
|
|
17
|
+
set :root, File.join(__dir__)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
configure :development do
|
|
21
|
+
register Sinatra::Reloader
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
before do
|
|
25
|
+
load_site_information
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
#----------------------
|
|
30
|
+
# admin pages
|
|
31
|
+
#----------------------
|
|
32
|
+
extend Admin
|
|
33
|
+
|
|
34
|
+
admin :system
|
|
35
|
+
admin :group
|
|
36
|
+
admin :alert
|
|
37
|
+
admin :config, true
|
|
38
|
+
admin :script, true
|
|
39
|
+
|
|
40
|
+
# static admin index page
|
|
41
|
+
get '/admin' do
|
|
42
|
+
redirect '/admin/systems'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
post '/admin/scripts/:id/commands' do
|
|
46
|
+
script = Script.with_pk!(params['id'])
|
|
47
|
+
script_command = ScriptCommand.new
|
|
48
|
+
script_command.script_id = params['id']
|
|
49
|
+
script_command.order = script.largest_order + 1
|
|
50
|
+
|
|
51
|
+
command_config = CommandConfig.create_with_params(params)
|
|
52
|
+
script_command.command_config_id = command_config.id
|
|
53
|
+
|
|
54
|
+
begin
|
|
55
|
+
script_command.save
|
|
56
|
+
rescue
|
|
57
|
+
if script_command.command_config_id
|
|
58
|
+
CommandConfig.with_pk!(script_command.command_config_id).destroy
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
redirect "#{url_prefix}admin/scripts/#{params['id']}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
post '/admin/scripts/:script_id/commands/:id' do
|
|
66
|
+
script_command = ScriptCommand.with_pk!(params['id'])
|
|
67
|
+
if params['action'] == 'Delete'
|
|
68
|
+
script_command.destroy
|
|
69
|
+
elsif params['action'] == 'Update'
|
|
70
|
+
script_command.command_config.update_options!(params)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
redirect "#{url_prefix}admin/scripts/#{params['script_id']}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
post '/admin/configs/:id/metrics' do
|
|
77
|
+
config = Config.with_pk!(params['id'])
|
|
78
|
+
config_metric = ConfigMetric.new
|
|
79
|
+
config_metric.config_id = params['id']
|
|
80
|
+
config_metric.order = config.largest_order + 1
|
|
81
|
+
|
|
82
|
+
command_config = CommandConfig.create_with_params(params)
|
|
83
|
+
config_metric.command_config_id = command_config.id
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
config_metric.save
|
|
87
|
+
rescue
|
|
88
|
+
if config_metric.command_config_id
|
|
89
|
+
CommandConfig.with_pk!(config_metric.command_config_id).destroy
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
redirect "#{url_prefix}admin/configs/#{params['id']}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
post '/admin/configs/:config_id/metrics/:id' do
|
|
97
|
+
config_metric = ConfigMetric.with_pk!(params['id'])
|
|
98
|
+
if params['action'] == 'Delete'
|
|
99
|
+
config_metric.destroy
|
|
100
|
+
elsif params['action'] == 'Update'
|
|
101
|
+
config_metric.command_config.update_options!(params)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
redirect "#{url_prefix}admin/configs/#{params['config_id']}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
#----------------------
|
|
109
|
+
# API
|
|
110
|
+
#----------------------
|
|
111
|
+
# csv for graphs shown on system page
|
|
112
|
+
get '/systems/:id/values' do
|
|
113
|
+
system = System.with_pk!(params['id'])
|
|
114
|
+
metrics = params[:metrics].to_s.split(',')
|
|
115
|
+
|
|
116
|
+
# find all values for the requested metrics
|
|
117
|
+
dataset = system.values_dataset.where(metric: metrics)
|
|
118
|
+
|
|
119
|
+
# the graphing library requires multiple series to be provided in
|
|
120
|
+
# row format (date, series 1, series 2 etc) so each value is
|
|
121
|
+
# grouped into a timestamp update window
|
|
122
|
+
updates = dataset.all.group_by(&:timestamp)
|
|
123
|
+
|
|
124
|
+
# loop from start to end generating the response csv
|
|
125
|
+
timestamps = updates.keys.sort
|
|
126
|
+
csv = "Date,#{params['metrics']}\n"
|
|
127
|
+
|
|
128
|
+
timestamps.each do |timestamp|
|
|
129
|
+
date = Time.at(timestamp).strftime('%Y-%m-%d %H:%M:%S')
|
|
130
|
+
csv << date << ','
|
|
131
|
+
|
|
132
|
+
values = Array.new(metrics.length)
|
|
133
|
+
records = updates[timestamp]
|
|
134
|
+
|
|
135
|
+
records.each do |record|
|
|
136
|
+
values[metrics.index(record.metric)] = record.num_value
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
csv << values.join(',') << "\n"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
csv
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# receive data from a client
|
|
146
|
+
post '/systems/:id/ping' do
|
|
147
|
+
timestamp = Time.now.to_i
|
|
148
|
+
|
|
149
|
+
# update the system with its last known ip and update time
|
|
150
|
+
system = System.with_pk!(params['id'])
|
|
151
|
+
system.last_updated = timestamp
|
|
152
|
+
system.ip = request.ip
|
|
153
|
+
|
|
154
|
+
# errors is either nil or a hash of the format - module: [err, ...]
|
|
155
|
+
system.save_metric_errors(params, timestamp)
|
|
156
|
+
|
|
157
|
+
# add each new value, a later process cleans up old values
|
|
158
|
+
system.save_values(params, timestamp)
|
|
159
|
+
|
|
160
|
+
# save action return values and prevent them from running again
|
|
161
|
+
system.save_actions(params, timestamp)
|
|
162
|
+
|
|
163
|
+
# ip, last updated, uploads and metrics are now updated. these are
|
|
164
|
+
# stored on the system.
|
|
165
|
+
system.save
|
|
166
|
+
content_type :json
|
|
167
|
+
{success: true}.to_json
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# system config
|
|
171
|
+
get '/systems/:id/config' do
|
|
172
|
+
system = System.with_pk!(params['id'])
|
|
173
|
+
config = {
|
|
174
|
+
metrics: system.config.metric_hashes,
|
|
175
|
+
actions: system.pending_actions.map(&:config_hash).flatten
|
|
176
|
+
}
|
|
177
|
+
content_type :json
|
|
178
|
+
config.to_json
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# render all errors in html to replace the shortened subset on the system page
|
|
182
|
+
get '/systems/:id/errors' do
|
|
183
|
+
system = System.with_pk!(params['id'])
|
|
184
|
+
errors = system.collection_errors
|
|
185
|
+
erb :errors, layout: false, locals: {errors: errors}
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# clear collection errors
|
|
189
|
+
delete '/systems/:id/errors' do
|
|
190
|
+
system = System.with_pk!(params['id'])
|
|
191
|
+
system.collection_errors.each(&:delete)
|
|
192
|
+
redirect "#{url_prefix}systems/#{system.id}"
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# create a new action
|
|
196
|
+
post '/systems/:id/actions' do
|
|
197
|
+
action = Action.new
|
|
198
|
+
action.system_id = params['id']
|
|
199
|
+
|
|
200
|
+
if params['script_id']
|
|
201
|
+
action.script_id = params['script_id']
|
|
202
|
+
else
|
|
203
|
+
command_config = CommandConfig.create_with_params(params)
|
|
204
|
+
action.command_config_id = command_config.id
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
begin
|
|
208
|
+
action.save
|
|
209
|
+
rescue
|
|
210
|
+
if action.command_config_id
|
|
211
|
+
CommandConfig.with_pk!(action.command_config_id).destroy
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
redirect "#{url_prefix}systems/#{params['id']}#actions"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# delete an action. deletion also clears any uploaded files.
|
|
219
|
+
delete '/systems/:system_id/actions/:id' do
|
|
220
|
+
action = Action.with_pk!(params['id'])
|
|
221
|
+
action.destroy
|
|
222
|
+
redirect "#{url_prefix}systems/#{params['system_id']}#actions"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
#----------------------
|
|
227
|
+
# frontend
|
|
228
|
+
#----------------------
|
|
229
|
+
# overview
|
|
230
|
+
get '/' do
|
|
231
|
+
systems = System.all
|
|
232
|
+
alerts = Alert.all
|
|
233
|
+
results = alerts.collect do |alert|
|
|
234
|
+
begin
|
|
235
|
+
alert.execute(systems)
|
|
236
|
+
rescue => e
|
|
237
|
+
"An error occurred running this alert: #{e.inspect}"
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
@alerts = Hash[alerts.zip(results)]
|
|
242
|
+
erb :index
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# list of systems
|
|
246
|
+
get '/systems' do
|
|
247
|
+
@systems = System.all.group_by(&:orientation)
|
|
248
|
+
@title = 'All Systems'
|
|
249
|
+
erb :systems
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# list of systems by group
|
|
253
|
+
get '/groups/:id/systems' do
|
|
254
|
+
group = Group.with_pk!(params['id'])
|
|
255
|
+
@systems = group.systems.group_by(&:orientation)
|
|
256
|
+
@title = group.name
|
|
257
|
+
erb :systems
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# info page for a system
|
|
261
|
+
get '/systems/:id' do
|
|
262
|
+
@system = System.with_pk!(params['id'])
|
|
263
|
+
@uploads = @system.upload_urls
|
|
264
|
+
metrics = @system.metrics
|
|
265
|
+
|
|
266
|
+
# we're only interested in the latest value for string metrics
|
|
267
|
+
@str_metrics = {}
|
|
268
|
+
metrics.select(&:string?).each do |metric|
|
|
269
|
+
value = @system.latest(metric.name)
|
|
270
|
+
name = "#{metric.name.titlecase}:"
|
|
271
|
+
@str_metrics[name] = value ? value.str_value : ''
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# numeric values are grouped together by their first name component
|
|
275
|
+
# and drawn on a graph. e.g cpu_all and cpu_chrome are shown together
|
|
276
|
+
num_metrics = metrics.select(&:numeric?).map(&:name)
|
|
277
|
+
@num_metrics = num_metrics.group_by {|n| n.split('_')[0]}
|
|
278
|
+
|
|
279
|
+
# make links clickable
|
|
280
|
+
@links = @system.links.to_s.gsub("\n", "<br>")
|
|
281
|
+
URI::extract(@links).each {|uri| @links.gsub!(uri, %Q{<a href="#{uri}">#{uri}</a>})}
|
|
282
|
+
|
|
283
|
+
# last updated is a timestamp, conver
|
|
284
|
+
if @system.last_updated
|
|
285
|
+
@last_updated = Time.at(@system.last_updated).ctime
|
|
286
|
+
else
|
|
287
|
+
@last_updated = 'never updated'
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
@errors = @system.collection_errors_dataset.limit(5).all
|
|
291
|
+
@total_error_count = @system.collection_errors_dataset.count
|
|
292
|
+
@scripts = Script.all
|
|
293
|
+
erb :system
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# helper to make uploads publicly accessible
|
|
297
|
+
get '/uploads/*' do
|
|
298
|
+
path = params['splat'][0]
|
|
299
|
+
raise 'Invalid path' if path.include?('..')
|
|
300
|
+
full_path = File.join(Server.options.uploads_dir, path)
|
|
301
|
+
send_file full_path
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'sequel'
|
|
2
|
+
require 'sequel/plugins/serialization'
|
|
3
|
+
|
|
4
|
+
module Perus::Server
|
|
5
|
+
module DB
|
|
6
|
+
def self.start
|
|
7
|
+
Sequel.extension :migration
|
|
8
|
+
Sequel.extension :inflector
|
|
9
|
+
|
|
10
|
+
# connect/create the database and run any new migrations
|
|
11
|
+
@db = Sequel.sqlite(Server.options.db_path, integer_booleans: true)
|
|
12
|
+
Sequel::Migrator.run(@db, File.join(__dir__, 'migrations'))
|
|
13
|
+
|
|
14
|
+
# load models - these rely on an existing db connection
|
|
15
|
+
require File.join(__dir__, 'models', 'system')
|
|
16
|
+
require File.join(__dir__, 'models', 'config')
|
|
17
|
+
require File.join(__dir__, 'models', 'value')
|
|
18
|
+
require File.join(__dir__, 'models', 'group')
|
|
19
|
+
require File.join(__dir__, 'models', 'error')
|
|
20
|
+
require File.join(__dir__, 'models', 'alert')
|
|
21
|
+
require File.join(__dir__, 'models', 'action')
|
|
22
|
+
require File.join(__dir__, 'models', 'metric')
|
|
23
|
+
require File.join(__dir__, 'models', 'script')
|
|
24
|
+
require File.join(__dir__, 'models', 'command_config')
|
|
25
|
+
require File.join(__dir__, 'models', 'script_command')
|
|
26
|
+
require File.join(__dir__, 'models', 'config_metric')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Perus::Server
|
|
2
|
+
class Form
|
|
3
|
+
def initialize(record)
|
|
4
|
+
@record = record
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def field(field, type = nil, options = nil)
|
|
8
|
+
field = field.to_s
|
|
9
|
+
|
|
10
|
+
if type.nil?
|
|
11
|
+
if @record.class.association_reflections.include?(field.to_sym)
|
|
12
|
+
type = 'association'
|
|
13
|
+
else
|
|
14
|
+
type = @record.db_schema[field.to_sym][:db_type]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
html = "<p><label for=\"#{field}\">#{field.titlecase}:</label><span>"
|
|
19
|
+
|
|
20
|
+
case type
|
|
21
|
+
when 'varchar(255)'
|
|
22
|
+
html << input(field, options)
|
|
23
|
+
when 'text'
|
|
24
|
+
html << textarea(field, options)
|
|
25
|
+
when 'association'
|
|
26
|
+
html << association(field, options)
|
|
27
|
+
when 'select'
|
|
28
|
+
html << select(field, options)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# return the field plus any errors
|
|
32
|
+
html << "</span></p>" << errors_for(field)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def input(field, options)
|
|
36
|
+
"<input type=\"text\" name=\"record[#{field}]\" value=\"#{@record.send(field)}\">"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def textarea(field, options)
|
|
40
|
+
"<textarea name=\"record[#{field}]\">#{@record.send(field)}</textarea>"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def association(field, options)
|
|
44
|
+
reflection = @record.class.association_reflections[field.to_sym]
|
|
45
|
+
other_model = reflection[:class_name].constantize
|
|
46
|
+
id_field = reflection[:key]
|
|
47
|
+
|
|
48
|
+
values = other_model.all.collect do |record|
|
|
49
|
+
[record.id, record.name]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
select(id_field, values)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def select(field, options)
|
|
56
|
+
existing = @record.send(field)
|
|
57
|
+
option_rows = options.collect do |(value, name)|
|
|
58
|
+
selected = existing == value ? 'selected' : ''
|
|
59
|
+
"<option value=\"#{value}\" #{selected}>#{name || value}</option>"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
"<select name=\"record[#{field}]\">#{option_rows.join("\n")}</select>"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def errors_for(field)
|
|
66
|
+
errors = @record.errors.on(field.to_sym)
|
|
67
|
+
return '' unless errors
|
|
68
|
+
field_name = field.titlecase
|
|
69
|
+
descriptions = errors.map {|error| "#{field_name} #{error}"}
|
|
70
|
+
"<p class=\"errors\">#{descriptions.join(', ')}</p>"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Perus::Server
|
|
2
|
+
module Helpers
|
|
3
|
+
def load_site_information
|
|
4
|
+
@site_name = Server.options.site_name
|
|
5
|
+
@groups = Group.all
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def nav_item(path, name, li = true)
|
|
9
|
+
if path.start_with?('/admin/')
|
|
10
|
+
klass = request.path_info.start_with?(path) ? 'selected' : ''
|
|
11
|
+
else
|
|
12
|
+
klass = request.path_info == path ? 'selected' : ''
|
|
13
|
+
end
|
|
14
|
+
anchor = "<a class=\"#{klass}\" href=\"#{path}\">#{name}</a>"
|
|
15
|
+
li ? "<li>#{anchor}</li>" : anchor
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def command_actions
|
|
19
|
+
commands = Perus::Pinger::Command.subclasses.reject(&:metric?)
|
|
20
|
+
commands.reject(&:abstract?)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def command_metrics
|
|
24
|
+
metrics = Perus::Pinger::Command.subclasses.select(&:metric?)
|
|
25
|
+
metrics.reject(&:abstract?)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def clean_arrows(text)
|
|
29
|
+
text.gsub('<', '<').gsub('>', '>')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def url_prefix
|
|
33
|
+
Server.options.url_prefix
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:systems) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
String :name, null: false, unique: true
|
|
6
|
+
String :logical_name
|
|
7
|
+
String :orientation
|
|
8
|
+
Integer :group_id
|
|
9
|
+
Integer :config_id
|
|
10
|
+
String :links, text: true
|
|
11
|
+
String :ip
|
|
12
|
+
String :metrics, text: true
|
|
13
|
+
Integer :last_updated
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
down do
|
|
18
|
+
drop_table(:systems)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:values) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
Integer :system_id, null: false
|
|
6
|
+
Integer :timestamp, null: false
|
|
7
|
+
String :metric, null: false
|
|
8
|
+
Float :num_value
|
|
9
|
+
String :str_value
|
|
10
|
+
|
|
11
|
+
# a covering index is used so no secondary lookups are required
|
|
12
|
+
# when querying for all metric values for a system. queries are
|
|
13
|
+
# constrained on system_id only. using timestamp as the second
|
|
14
|
+
# component of the index implicitly sorts the rows by timestamp
|
|
15
|
+
# satisfying `order by timestamp'.
|
|
16
|
+
index [:system_id, :timestamp, :metric, :num_value, :str_value]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
down do
|
|
21
|
+
drop_table(:values)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:errors) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
Integer :system_id, null: false
|
|
6
|
+
Integer :timestamp, null: false
|
|
7
|
+
String :module, null: false
|
|
8
|
+
String :description, null: false
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
down do
|
|
13
|
+
drop_table(:errors)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:actions) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
Integer :system_id, null: false
|
|
6
|
+
Integer :command_config_id
|
|
7
|
+
Integer :script_id
|
|
8
|
+
Integer :timestamp
|
|
9
|
+
Boolean :success
|
|
10
|
+
String :response
|
|
11
|
+
String :file, text: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
down do
|
|
16
|
+
drop_table(:actions)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:metrics) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
String :name, null: false
|
|
6
|
+
String :system_id, null: false
|
|
7
|
+
String :type, null: false
|
|
8
|
+
String :file, text: true
|
|
9
|
+
index [:system_id, :name]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
down do
|
|
14
|
+
drop_table(:metrics)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:script_commands) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
Integer :script_id, null: false
|
|
6
|
+
Integer :command_config_id, null:false
|
|
7
|
+
Integer :order, null: false
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
down do
|
|
12
|
+
drop_table(:script_commands)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Sequel.migration do
|
|
2
|
+
up do
|
|
3
|
+
create_table(:config_metrics) do
|
|
4
|
+
primary_key :id
|
|
5
|
+
Integer :config_id, null: false
|
|
6
|
+
Integer :command_config_id, null:false
|
|
7
|
+
Integer :order, null: false
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
down do
|
|
12
|
+
drop_table(:config_metrics)
|
|
13
|
+
end
|
|
14
|
+
end
|