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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 50163f19be6adf3f481d868e88b7efe33d563425
|
|
4
|
+
data.tar.gz: 46fbde86dcfb9d0f6194849517f9b6bae81ec8cd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 504e5ec4a3c322c18de258f2ee67eea50267bb82aff92473eca31b2205091b4058e16f1f3ef17a8d2581b536d0bf99fadd8b7eae87c3b6b0632a3f2aec87404a
|
|
7
|
+
data.tar.gz: faa25da90c07daac501192daac00106c568ab73e177fa93578de5116abbb333f50697706d31e2fbf8ded7327c8709f4d0e38f5f656a06abcaa73b45980ba036b
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 ACA
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Perus
|
|
2
|
+
|
|
3
|
+
A simple system management and monitoring service. Systems ping a server with screenshots and data, and the server provides a simple overview page.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
Install on a server and each system you'd like to monitor
|
|
9
|
+
|
|
10
|
+
$ gem install perus
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## License
|
|
14
|
+
|
|
15
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
16
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "perus"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/exe/perus-pinger
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'perus'
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
options_path = Perus::Pinger::DEFAULT_PINGER_OPTIONS_PATH
|
|
6
|
+
|
|
7
|
+
ARGV.options do |opts|
|
|
8
|
+
opts.banner = "Usage: perus-pinger [options]"
|
|
9
|
+
|
|
10
|
+
opts.on('-c', '--config', String, "Path to config file (default: #{Perus::Pinger::DEFAULT_PINGER_OPTIONS_PATH})") do |c|
|
|
11
|
+
options_path = c
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
opts.on('-h', '--help', 'Prints this help') do
|
|
15
|
+
puts opts
|
|
16
|
+
exit
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
opts.parse!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
pinger = Perus::Pinger::Pinger.new(options_path)
|
|
23
|
+
pinger.run
|
data/exe/perus-server
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'perus'
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
options_path = Perus::Server::DEFAULT_SERVER_OPTIONS_PATH
|
|
6
|
+
|
|
7
|
+
ARGV.options do |opts|
|
|
8
|
+
opts.banner = "Usage: perus-server [options]"
|
|
9
|
+
|
|
10
|
+
opts.on('-c', '--config', String, "Path to config file (default: #{Perus::Server::DEFAULT_SERVER_OPTIONS_PATH})") do |c|
|
|
11
|
+
options_path = c
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
opts.on('-h', '--help', 'Prints this help') do
|
|
15
|
+
puts opts
|
|
16
|
+
exit
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
opts.parse!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
server = Perus::Server::Server.new(options_path)
|
|
23
|
+
server.run
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'iniparse'
|
|
2
|
+
|
|
3
|
+
module Perus
|
|
4
|
+
class Options
|
|
5
|
+
def initialize()
|
|
6
|
+
@defaults = {}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def load(path, defaults)
|
|
10
|
+
if File.exists?(path)
|
|
11
|
+
user_options = IniParse.parse(IO.read(path)).to_h
|
|
12
|
+
else
|
|
13
|
+
user_options = {}
|
|
14
|
+
end
|
|
15
|
+
@options = defaults.merge(user_options)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def method_missing(name, *params, &block)
|
|
19
|
+
if @options.include?(name.to_s)
|
|
20
|
+
@options[name.to_s]
|
|
21
|
+
else
|
|
22
|
+
@options['__anonymous__'][name.to_s]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def [](name)
|
|
27
|
+
@options[name]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'faye/websocket'
|
|
2
|
+
require 'eventmachine'
|
|
3
|
+
require 'rest-client'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Perus::Pinger
|
|
7
|
+
class ChromeCommand < Command
|
|
8
|
+
option :timeout_seconds, default: 2
|
|
9
|
+
option :host, default: 'localhost'
|
|
10
|
+
option :port, default: 9222
|
|
11
|
+
abstract!
|
|
12
|
+
|
|
13
|
+
def send_command(command)
|
|
14
|
+
@ws.send(command)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def execute(commands, &message_callback)
|
|
18
|
+
# discover the first page shown in chrome
|
|
19
|
+
pages = JSON.parse(RestClient.get("http://#{options.host}:#{options.port}/json"))
|
|
20
|
+
pages.reject! {|page| page['url'].include?('chrome-extension')}
|
|
21
|
+
@page = pages.first
|
|
22
|
+
|
|
23
|
+
EM.run do
|
|
24
|
+
@ws = Faye::WebSocket::Client.new(@page['webSocketDebuggerUrl'])
|
|
25
|
+
|
|
26
|
+
@ws.on :error do |event|
|
|
27
|
+
puts "Chrome error: #{event}"
|
|
28
|
+
EM.stop_event_loop
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
@ws.on :close do |event|
|
|
32
|
+
EM.stop_event_loop
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@ws.on :message do |event|
|
|
36
|
+
if block_given?
|
|
37
|
+
json = JSON.parse(event.data)
|
|
38
|
+
message_callback.call(json)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# send each command, responses will appear
|
|
43
|
+
commands.each do |command|
|
|
44
|
+
send_command(command)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# cutoff console message loading after N seconds
|
|
48
|
+
EM.add_timer(options.timeout_seconds) do
|
|
49
|
+
@ws.close
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'ostruct'
|
|
2
|
+
|
|
3
|
+
module Perus::Pinger
|
|
4
|
+
class Option
|
|
5
|
+
attr_reader :name, :default, :restricted
|
|
6
|
+
|
|
7
|
+
def initialize(name, settings, command)
|
|
8
|
+
@name = name
|
|
9
|
+
@command = command
|
|
10
|
+
@default = settings[:default]
|
|
11
|
+
@restricted = settings[:restricted] == true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def boolean?
|
|
15
|
+
default.is_a?(TrueClass) || default.is_a?(FalseClass)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def process(results, values)
|
|
19
|
+
value = values[name.to_s]
|
|
20
|
+
value = value || default
|
|
21
|
+
|
|
22
|
+
if value.nil?
|
|
23
|
+
raise "#{name} is a required option"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if restricted
|
|
27
|
+
allowed = Pinger.options[@command.name.demodulize][@name.to_s]
|
|
28
|
+
raise "the value passed to #{@name} is not allowed" unless allowed.include?(value)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
results[name] = value
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Command
|
|
36
|
+
attr_reader :options, :id
|
|
37
|
+
|
|
38
|
+
def self.human_name
|
|
39
|
+
name.demodulize.underscore.humanize.titlecase
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# set or get command/metric description
|
|
43
|
+
def self.description(text = nil)
|
|
44
|
+
if text
|
|
45
|
+
@description = text
|
|
46
|
+
else
|
|
47
|
+
@description
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# add an option to the command/metric. both the class and instances
|
|
52
|
+
# of the class have an options method. the class version returns a
|
|
53
|
+
# list of Option objects representing possible options for the
|
|
54
|
+
# command. the object version returns an OpenStruct hash of options
|
|
55
|
+
# and their values (defaults merged with provided values)
|
|
56
|
+
def self.option(name, option_settings = {})
|
|
57
|
+
@options ||= []
|
|
58
|
+
@options << Option.new(name, option_settings, self)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.options
|
|
62
|
+
@options ||= []
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.inherited(subclass)
|
|
66
|
+
subclass.options.concat(self.options)
|
|
67
|
+
Command.subclasses << subclass
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.subclasses
|
|
71
|
+
@subclasses ||= []
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# command classes which are intended to run as metrics call this method
|
|
75
|
+
def self.metric!
|
|
76
|
+
@metric = true
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.metric?
|
|
80
|
+
@metric
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.abstract!
|
|
84
|
+
@abstract = true
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.abstract?
|
|
88
|
+
@abstract
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# create a command instance and initialise it with the provided option
|
|
92
|
+
# values (hash where keys are option names). any restricted options are
|
|
93
|
+
# validated first, and an exception is thrown if the provided value is
|
|
94
|
+
# not one of the allowed values for the option.
|
|
95
|
+
def initialize(option_values, id = nil)
|
|
96
|
+
@options = OpenStruct.new
|
|
97
|
+
self.class.options.each do |option|
|
|
98
|
+
option.process(@options, option_values)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# commands (not metrics) have ids that uniquely identify a command
|
|
102
|
+
# instance and its response
|
|
103
|
+
@id = id
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def run
|
|
107
|
+
# run command/metric, return types for a command are:
|
|
108
|
+
# true: successful (will show as success on the server)
|
|
109
|
+
# string: failed, string should provide the reason
|
|
110
|
+
# file: file to upload
|
|
111
|
+
# proc: code to run after returning success to server
|
|
112
|
+
# hash: metrics are expected to only return a hash with
|
|
113
|
+
# keys indicating metric names, and values restricted to
|
|
114
|
+
# files, numerics and strings.
|
|
115
|
+
# exceptions are caught and shown as errors on the server.
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def cleanup
|
|
119
|
+
# called after sending data to server. remove temporary
|
|
120
|
+
# files etc.
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class ChromeExecute < ChromeCommand
|
|
3
|
+
description 'Executes JavaScript in the top Chrome window. The result
|
|
4
|
+
of the execution is stored and sent to the server.'
|
|
5
|
+
option :js
|
|
6
|
+
|
|
7
|
+
def run
|
|
8
|
+
result = false
|
|
9
|
+
command = '{"id":1,"method":"Runtime.evaluate","params":{"expression":"' + options.js.gsub('"', '\\"') + '","objectGroup":"perus","returnByValue":true}}'
|
|
10
|
+
|
|
11
|
+
execute([command]) do |message|
|
|
12
|
+
if message.include?('id') && message['id'] == 1
|
|
13
|
+
if message.include?('result')
|
|
14
|
+
result = message['result'].to_s
|
|
15
|
+
elsif message.include?('error')
|
|
16
|
+
result = message['error'].to_s
|
|
17
|
+
else
|
|
18
|
+
result = false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class ChromeNavigate < ChromeCommand
|
|
3
|
+
description 'Changes the URL of the top Chrome window to "url"'
|
|
4
|
+
option :url
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
result = false
|
|
8
|
+
command = '{"id":1,"method":"Page.navigate","params":{"url":"' + options.url + '"}}'
|
|
9
|
+
|
|
10
|
+
execute([command]) do |message|
|
|
11
|
+
if message.include?('id') && message['id'] == 1
|
|
12
|
+
if message.include?('result')
|
|
13
|
+
result = true
|
|
14
|
+
elsif message.include?('error')
|
|
15
|
+
result = message['error'].to_s
|
|
16
|
+
else
|
|
17
|
+
result = message.to_s
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
result
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class ChromeReload < ChromeCommand
|
|
3
|
+
description 'Reloads the top Chrome window. When "ignore_cache" is true
|
|
4
|
+
the effect is equivalent to performing a force reload.'
|
|
5
|
+
option :ignore_cache, default: false
|
|
6
|
+
|
|
7
|
+
def run
|
|
8
|
+
result = false
|
|
9
|
+
|
|
10
|
+
execute(['{"id":1,"method":"Page.reload"}']) do |message|
|
|
11
|
+
if message.include?('id') && message['id'] == 1
|
|
12
|
+
if message.include?('result')
|
|
13
|
+
if message['result'] == {}
|
|
14
|
+
result = true
|
|
15
|
+
else
|
|
16
|
+
result = message['result'].to_s
|
|
17
|
+
end
|
|
18
|
+
elsif message.include?('error')
|
|
19
|
+
result = message['error'].to_s
|
|
20
|
+
else
|
|
21
|
+
result = message.to_s
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
result
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class KillProcess < Command
|
|
3
|
+
description 'Kills all instances of a process. Valid values for
|
|
4
|
+
"process_name" are contained in the pinger config file.'
|
|
5
|
+
option :process_name, restricted: true
|
|
6
|
+
option :signal, default: 'KILL'
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
result = `killall -#{option.signal} #{option.process_name}`
|
|
10
|
+
result.include?('no process found') ? result : true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require'fileutils'
|
|
2
|
+
|
|
3
|
+
module Perus::Pinger
|
|
4
|
+
class RemovePath < Command
|
|
5
|
+
description 'Deletes a file or folder. If "path" is a folder, all files
|
|
6
|
+
and folders within the folder are deleted as well. Valid
|
|
7
|
+
values for "path" are contained in the pinger config file.'
|
|
8
|
+
option :path, restricted: true
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
FileUtils.rm_rf([File.expand_path(options.path)], secure: true)
|
|
12
|
+
true # with no exceptions, the removal was successful
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class Replace < Command
|
|
3
|
+
description 'Looks for the string matched by "grep" in the file
|
|
4
|
+
specified by "path" and replaces it with "replacement".
|
|
5
|
+
Valid values for "path" are contained in the pinger
|
|
6
|
+
config file.'
|
|
7
|
+
option :path, restricted: true
|
|
8
|
+
option :grep
|
|
9
|
+
option :replacement
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
text = IO.read(options.path)
|
|
13
|
+
text.gsub!(/#{options.grep}/, options.replacement)
|
|
14
|
+
IO.write(options.path, text)
|
|
15
|
+
true
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class Script < Command
|
|
3
|
+
option :commands
|
|
4
|
+
abstract!
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
actions = []
|
|
8
|
+
results = []
|
|
9
|
+
late_actions = []
|
|
10
|
+
|
|
11
|
+
options.commands.each do |config|
|
|
12
|
+
begin
|
|
13
|
+
command = ::Perus::Pinger.const_get(config['type'])
|
|
14
|
+
actions << command.new(config['options'], config['id'])
|
|
15
|
+
rescue => e
|
|
16
|
+
if config['id']
|
|
17
|
+
results[config['id']] = e.inspect
|
|
18
|
+
else
|
|
19
|
+
puts 'Error - action does not have an associated id'
|
|
20
|
+
p config
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
actions.each do |action|
|
|
26
|
+
begin
|
|
27
|
+
result = action.run
|
|
28
|
+
|
|
29
|
+
if result.instance_of?(Proc)
|
|
30
|
+
late_actions << result
|
|
31
|
+
result = true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
results << result
|
|
35
|
+
rescue => e
|
|
36
|
+
results << e.inspect
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
failed = results.any? {|result| result.is_a?(String)}
|
|
41
|
+
return results.join(', ') if failed
|
|
42
|
+
|
|
43
|
+
if late_actions.empty?
|
|
44
|
+
true
|
|
45
|
+
else
|
|
46
|
+
Proc.new do
|
|
47
|
+
late_actions.each do |code|
|
|
48
|
+
begin
|
|
49
|
+
code.call
|
|
50
|
+
rescue => e
|
|
51
|
+
puts 'Error running late action'
|
|
52
|
+
puts e.inspect
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class Upgrade < Command
|
|
3
|
+
description 'Upgrades Perus on the client machine'
|
|
4
|
+
option :sudo, default: false
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
if options.sudo
|
|
8
|
+
result = `sudo gem upgrade perus`
|
|
9
|
+
else
|
|
10
|
+
result = `gem upgrade perus`
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
result.include?('ERROR') ? result : true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class Upload < Command
|
|
3
|
+
description 'Uploads a file from the client to the server. Valid values
|
|
4
|
+
for "path" are contained in the pinger config file.'
|
|
5
|
+
option :path, restricted: true
|
|
6
|
+
|
|
7
|
+
def run
|
|
8
|
+
@file = File.new(options.path)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def cleanup
|
|
12
|
+
@file.close unless @file.nil? || @file.closed?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class Chrome < ChromeCommand
|
|
3
|
+
description 'Connects to Chrome with the remote debugger and counts the
|
|
4
|
+
number of warnings and errors currently in the console of
|
|
5
|
+
the top Chrome window. The URL of the page is also sent
|
|
6
|
+
and can be compared to an expected string in an alert.'
|
|
7
|
+
metric!
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
# we use a debugging protocol connection to read the console messages
|
|
11
|
+
# in the top level window to count the number of warnings and errors
|
|
12
|
+
warning_count = 0
|
|
13
|
+
error_count = 0
|
|
14
|
+
|
|
15
|
+
execute(['{"id":1,"method":"Console.enable"}']) do |json|
|
|
16
|
+
if json['method'] == 'Console.messageAdded'
|
|
17
|
+
level = json['params']['message']['level']
|
|
18
|
+
if level == 'error'
|
|
19
|
+
error_count += 1
|
|
20
|
+
elsif level == 'warning'
|
|
21
|
+
warning_count += 1
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
chrome_warnings: warning_count,
|
|
28
|
+
chrome_errors: error_count,
|
|
29
|
+
chrome_url: @page['url']
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class CPU < Command
|
|
3
|
+
description 'Measures overall system CPU usage as a percentage on the
|
|
4
|
+
client.'
|
|
5
|
+
metric!
|
|
6
|
+
|
|
7
|
+
def run
|
|
8
|
+
if `uname -s`.strip == 'Darwin'
|
|
9
|
+
percent = 100 - `iostat -n 0`.split("\n")[2].split[2].to_i
|
|
10
|
+
else
|
|
11
|
+
percent = `grep 'cpu ' /proc/stat | awk '{print (1 - ($5 / ($2+$3+$4+$5+$6+$7+$8)))*100}'`
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
{cpu_all: percent.to_f}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Perus::Pinger
|
|
2
|
+
class HD < Command
|
|
3
|
+
description 'Measures the percentage of disk space currently used on
|
|
4
|
+
the specified drive.'
|
|
5
|
+
option :drive
|
|
6
|
+
metric!
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
regex = "/^#{options.drive.gsub("/", "\\/")}/"
|
|
10
|
+
percent = `df -h / | awk '#{regex} {print $5}'`
|
|
11
|
+
{hd_used: percent.to_i}
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|