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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 426902fcecc63ec81acf9352f4bafba9fa1988d4
4
- data.tar.gz: 36838e6272731efce01b25f8c8773d4ed8622cfe
3
+ metadata.gz: bae9eee51f945b6f2ba014af73f5cdfa8fa6ab03
4
+ data.tar.gz: 3253602c339568d245a4a448abbd3990cf89479f
5
5
  SHA512:
6
- metadata.gz: a4e06d529a4d1d00f2beba82bd5c118b662fedd4b5b70856d39fadbd9a28781c3a9c2243ab9670dac271c69ace4ad6e8961c6988590b296536816a941995d146
7
- data.tar.gz: 2bb970e51ed715718b85078c46c34218d25f4596994136215cf99d313e32a78822ebcba13120848e4b38d542caee7726a4f7a75fc15dd17fc8dd0550339abe02
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
- ARGV.options do |opts|
7
+ OptionParser.new do |opts|
8
8
  opts.banner = "Usage: perus-pinger [options]"
9
9
 
10
- opts.on('-c', '--config', String, "Path to config file (default: #{Perus::Pinger::DEFAULT_PINGER_OPTIONS_PATH})") do |c|
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
- ARGV.options do |opts|
8
+ OptionParser.new do |opts|
8
9
  opts.banner = "Usage: perus-server [options]"
9
10
 
10
- opts.on('-c', '--config', String, "Path to config file (default: #{Perus::Server::DEFAULT_SERVER_OPTIONS_PATH})") do |c|
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
- opts.parse!
20
- end
21
-
22
- server = Perus::Server::Server.new(options_path)
30
+ server = Perus::Server::Server.new(options_path, environment)
23
31
  server.run
@@ -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
@@ -17,6 +17,9 @@ module Perus::Pinger
17
17
  else
18
18
  result = false
19
19
  end
20
+
21
+ # clean up any memory used by the executed command
22
+ send_command('{"id":2,"method":"Runtime.releaseObjectGroup","params":{"objectGroup":"perus"}}')
20
23
  end
21
24
  end
22
25
 
@@ -6,8 +6,8 @@ module Perus::Pinger
6
6
  option :signal, default: 'KILL'
7
7
 
8
8
  def run
9
- result = `killall -#{option.signal} #{option.process_name}`
10
- result.include?('no process found') ? result : true
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 = `sudo gem upgrade perus`
8
+ result = shell('sudo gem upgrade perus')
9
9
  else
10
- result = `gem upgrade perus`
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 `uname -s`.strip == 'Darwin'
9
- percent = 100 - `iostat -n 0`.split("\n")[2].split[2].to_i
8
+ if darwin?
9
+ percent = 100 - shell('iostat dxxvdfs -n 0').split("\n")[2].split[2].to_i
10
10
  else
11
- percent = `grep 'cpu ' /proc/stat | awk '{print (1 - ($5 / ($2+$3+$4+$5+$6+$7+$8)))*100}'`
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}
@@ -7,7 +7,7 @@ module Perus::Pinger
7
7
 
8
8
  def run
9
9
  regex = "/^#{options.drive.gsub("/", "\\/")}/"
10
- percent = `df -h / | awk '#{regex} {print $5}'`
10
+ percent = shell("df -h / | awk '#{regex} {print $5}'")
11
11
  {hd_used: percent.to_i}
12
12
  end
13
13
  end
@@ -4,7 +4,7 @@ module Perus::Pinger
4
4
  metric!
5
5
 
6
6
  def run
7
- percent = `cat /proc/meminfo | awk '{if ($1=="MemTotal:") total = $2; if ($1 == "MemFree:") free = $2;} END {print (1 - (free / total))*100}'`
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 = `ps aux | awk '/#{path}/ {cpu += $3; mem += $4} END {print cpu, mem;}'`.split
15
- if `uname -s`.strip == 'Darwin'
16
- core_count = `sysctl -n hw.ncpu`
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 = `cat /proc/cpuinfo | grep processor | awk '{count += 1} END {print 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 `uname -s`.strip == 'Darwin'
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
- `screencapture -m -t jpg -x #{options.path}`
20
- width = `sips -g pixelWidth #{options.path}`.match(/pixelWidth: (\d+)/)[1]
21
- height = `sips -g pixelHeight #{options.path}`.match(/pixelHeight: (\d+)/)[1]
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
- `export DISPLAY=:0; import -window root -resize #{options.resize} #{options.path}`
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.close unless @screenshot_file.closed?
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 `uname -s`.strip == 'Darwin'
10
- degrees = `istats cpu temp`.split[2].match(/([0-9\.]+)/)[0]
9
+ if darwin?
10
+ degrees = shell('istats cpu temp').split[2].match(/([0-9\.]+)/)[0]
11
11
  else
12
- degrees = `sensors | grep "#{options.device}:"`.match(/#{options.device}:\s+(\S+)/)[1]
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}
@@ -4,7 +4,7 @@ module Perus::Pinger
4
4
  metric!
5
5
 
6
6
  def run
7
- {uptime: `uptime`.strip}
7
+ {uptime: shell('uptime').strip}
8
8
  end
9
9
  end
10
10
  end
@@ -10,7 +10,8 @@ module Perus::Pinger
10
10
  metric!
11
11
 
12
12
  def run
13
- line = `cat #{options.path} | grep #{options.grep}`
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
@@ -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("/systems/#{Pinger.options.system_id}/config")
55
- pinger_path = URI("/systems/#{Pinger.options.system_id}/ping")
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.inspect
95
+ @metric_errors[config['type']] = format_exception(e)
96
96
  end
97
97
  rescue => e
98
- @metric_errors[metric.name] << e.inspect
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.inspect
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.inspect
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.inspect
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.inspect
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.inspect
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.inspect
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.inspect
221
+ puts format_exception(e)
214
222
  end
215
223
  end
216
224
  end
@@ -11,6 +11,7 @@ module Perus::Server
11
11
  helpers Helpers
12
12
 
13
13
  before do
14
+ @singular = '#{singular}'
14
15
  @plural = '#{plural}'
15
16
  @title = '#{title}'
16
17
  load_site_information
@@ -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
@@ -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
@@ -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
- "<input type=\"text\" name=\"record[#{field}]\" value=\"#{@record.send(field)}\">"
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>"
@@ -39,6 +39,10 @@ module Perus::Server
39
39
  text.gsub('<', '&lt;').gsub('>', '&gt;')
40
40
  end
41
41
 
42
+ def escape_quotes(text)
43
+ text.to_s.gsub('"', '&quot;')
44
+ end
45
+
42
46
  def url_prefix
43
47
  Server.options.url_prefix
44
48
  end
@@ -16,6 +16,10 @@ module Perus::Server
16
16
  end
17
17
  end
18
18
 
19
+ def can_delete?
20
+ systems_dataset.empty?
21
+ end
22
+
19
23
  def validate
20
24
  super
21
25
  validates_presence :name
@@ -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: 300px;
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: 190px;
285
+ width: 390px;
279
286
  line-height: 16px;
280
287
  }
281
288
 
@@ -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><a href="<%= url_prefix %>admin/<%= @plural %>/<%= record.id %>"><%= record.name %></a></td>
9
- <td><a href="<%= url_prefix %>admin/<%= @plural %>/<%= record.id %>">Delete</a></td>
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>
@@ -1,6 +1,6 @@
1
1
  <% errors.each do |error| %>
2
2
  <li>
3
3
  <h1><%= error.module %> - <%= Time.at(error.timestamp).ctime %></h1>
4
- <p><%= clean_arrows(error.description) %></p>
4
+ <p><%= clean_arrows(error.description).gsub("\n", "<br>") %></p>
5
5
  </li>
6
6
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <h1>System: <%= @system.name %></h1>
2
2
 
3
- <section id="meta">
3
+ <section id="meta" class="<%= @system.orientation.downcase %>">
4
4
  <img src="<%= @uploads['screenshot'] %>">
5
5
  <dl>
6
6
  <% unless @system.logical_name.empty? %>
data/lib/perus/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Perus
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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.2
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-10 00:00:00.000000000 Z
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: