pimon 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.travis.yml +6 -0
- data/Capfile +2 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +77 -0
- data/README.md +77 -0
- data/Rakefile +13 -0
- data/WTFPL-LICENSE +13 -0
- data/bin/clean_redis_stats +1 -0
- data/bin/free.c +12 -0
- data/bin/makefile +2 -0
- data/bin/pimon +19 -0
- data/bin/random.c +21 -0
- data/bin/random.h +1 -0
- data/bin/vmstat.c +12 -0
- data/config/config.ru +4 -0
- data/config/config_dev.ru +11 -0
- data/config/deploy.rb +65 -0
- data/config/development.yml +25 -0
- data/config/production.yml +27 -0
- data/config/test.yml +27 -0
- data/config/test_broken.yml +22 -0
- data/config/thin/config.yml +13 -0
- data/lib/pimon.rb +63 -0
- data/lib/pimon/hash_extensions.rb +12 -0
- data/lib/pimon/pimon_config.rb +75 -0
- data/lib/pimon/probe/cpu_usage.rb +11 -0
- data/lib/pimon/probe/disk_usage.rb +11 -0
- data/lib/pimon/probe/memory_usage.rb +13 -0
- data/lib/pimon/probe/probe.rb +13 -0
- data/lib/pimon/probe/swap_usage.rb +13 -0
- data/lib/pimon/probe/system_memory.rb +19 -0
- data/lib/pimon/probe/temperature.rb +16 -0
- data/lib/pimon/public/favicon.ico +0 -0
- data/lib/pimon/stats_collector.rb +65 -0
- data/lib/pimon/version.rb +3 -0
- data/lib/pimon/views/index.haml +10 -0
- data/lib/pimon/views/index.js.haml +111 -0
- data/pimon.gemspec +34 -0
- data/spec/pimon_config_spec.rb +34 -0
- data/spec/pimon_spec.rb +35 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/stats_collector_spec.rb +61 -0
- metadata +272 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Capfile
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gem 'capistrano'
|
4
|
+
gem 'haml'
|
5
|
+
gem 'redis'
|
6
|
+
gem 'sinatra', :require => 'sinatra/base'
|
7
|
+
gem 'thin'
|
8
|
+
|
9
|
+
gem 'pry', :group => [:development, :test]
|
10
|
+
|
11
|
+
group :test do
|
12
|
+
gem 'mock_redis', '~> 0.5.0'
|
13
|
+
gem 'rack-test'
|
14
|
+
gem 'rspec', '~> 2.11.0'
|
15
|
+
gem 'simplecov', :require => false
|
16
|
+
gem 'simplecov-rcov'
|
17
|
+
gem 'timecop'
|
18
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
capistrano (2.13.3)
|
5
|
+
highline
|
6
|
+
net-scp (>= 1.0.0)
|
7
|
+
net-sftp (>= 2.0.0)
|
8
|
+
net-ssh (>= 2.0.14)
|
9
|
+
net-ssh-gateway (>= 1.1.0)
|
10
|
+
coderay (1.0.7)
|
11
|
+
daemons (1.1.9)
|
12
|
+
diff-lcs (1.1.3)
|
13
|
+
eventmachine (0.12.10)
|
14
|
+
haml (3.1.7)
|
15
|
+
highline (1.6.13)
|
16
|
+
method_source (0.8)
|
17
|
+
mock_redis (0.5.0)
|
18
|
+
multi_json (1.0.4)
|
19
|
+
net-scp (1.0.4)
|
20
|
+
net-ssh (>= 1.99.1)
|
21
|
+
net-sftp (2.0.5)
|
22
|
+
net-ssh (>= 2.0.9)
|
23
|
+
net-ssh (2.5.2)
|
24
|
+
net-ssh-gateway (1.1.0)
|
25
|
+
net-ssh (>= 1.99.1)
|
26
|
+
pry (0.9.10)
|
27
|
+
coderay (~> 1.0.5)
|
28
|
+
method_source (~> 0.8)
|
29
|
+
slop (~> 3.3.1)
|
30
|
+
rack (1.4.1)
|
31
|
+
rack-protection (1.2.0)
|
32
|
+
rack
|
33
|
+
rack-test (0.6.1)
|
34
|
+
rack (>= 1.0)
|
35
|
+
redis (3.0.1)
|
36
|
+
rspec (2.11.0)
|
37
|
+
rspec-core (~> 2.11.0)
|
38
|
+
rspec-expectations (~> 2.11.0)
|
39
|
+
rspec-mocks (~> 2.11.0)
|
40
|
+
rspec-core (2.11.1)
|
41
|
+
rspec-expectations (2.11.2)
|
42
|
+
diff-lcs (~> 1.1.3)
|
43
|
+
rspec-mocks (2.11.2)
|
44
|
+
simplecov (0.6.1)
|
45
|
+
multi_json (~> 1.0)
|
46
|
+
simplecov-html (~> 0.5.3)
|
47
|
+
simplecov-html (0.5.3)
|
48
|
+
simplecov-rcov (0.2.3)
|
49
|
+
simplecov (>= 0.4.1)
|
50
|
+
sinatra (1.3.2)
|
51
|
+
rack (~> 1.3, >= 1.3.6)
|
52
|
+
rack-protection (~> 1.2)
|
53
|
+
tilt (~> 1.3, >= 1.3.3)
|
54
|
+
slop (3.3.2)
|
55
|
+
thin (1.4.1)
|
56
|
+
daemons (>= 1.0.9)
|
57
|
+
eventmachine (>= 0.12.6)
|
58
|
+
rack (>= 1.0.0)
|
59
|
+
tilt (1.3.3)
|
60
|
+
timecop (0.3.5)
|
61
|
+
|
62
|
+
PLATFORMS
|
63
|
+
ruby
|
64
|
+
|
65
|
+
DEPENDENCIES
|
66
|
+
capistrano
|
67
|
+
haml
|
68
|
+
mock_redis (~> 0.5.0)
|
69
|
+
pry
|
70
|
+
rack-test
|
71
|
+
redis
|
72
|
+
rspec (~> 2.11.0)
|
73
|
+
simplecov
|
74
|
+
simplecov-rcov
|
75
|
+
sinatra
|
76
|
+
thin
|
77
|
+
timecop
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Pimon
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/pedrocarrico/pimon.png)](http://travis-ci.org/pedrocarrico/pimon) [![Dependency Status](https://gemnasium.com/pedrocarrico/pimon.png?travis)](https://gemnasium.com/pedrocarrico/pimon) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/pedrocarrico/pimon)
|
4
|
+
|
5
|
+
![Pimon](http://pedrocarrico.net/pimon.jpg "Pimon")
|
6
|
+
|
7
|
+
## Description
|
8
|
+
Pimon is a simple server monitor designed for the Raspberry Pi.
|
9
|
+
It uses redis lists to keep the latest observed statistics and also uses
|
10
|
+
highcharts to display some nice charts on your web browser.
|
11
|
+
|
12
|
+
## What do I need to get it to work?
|
13
|
+
1. Install redis an configure it to run on a socket on /tmp/redis.sock
|
14
|
+
2. bundle
|
15
|
+
3. bin/pimon start # run the sinatra app
|
16
|
+
4. go to http://localhost:3000 and PROFIT!
|
17
|
+
Optionally you may install it as a gem and run it, please check "Installing as a gem" further down.
|
18
|
+
|
19
|
+
## Configuration
|
20
|
+
1. basic_auth - enable or disable, configure username and password
|
21
|
+
2. redis - location of the redis socket
|
22
|
+
3. chart - colors for each chart
|
23
|
+
4. queues - redis list names for the series in the charts
|
24
|
+
5. stats - configure number of stats and time period between them
|
25
|
+
|
26
|
+
## Deployment
|
27
|
+
To deploy on your raspberry pi you just have to have ssh enabled and your keys authorized.
|
28
|
+
Then you can deploy with capistrano using:
|
29
|
+
```
|
30
|
+
cap deploy:setup
|
31
|
+
cap deploy:cold
|
32
|
+
```
|
33
|
+
|
34
|
+
This will setup your raspberry pi and deploy the application.
|
35
|
+
The username and password for the basic_auth in the production environment will be asked in the
|
36
|
+
first deploy.
|
37
|
+
To start and stop the application you have the usual:
|
38
|
+
```
|
39
|
+
cap deploy:start
|
40
|
+
cap deploy:stop
|
41
|
+
```
|
42
|
+
|
43
|
+
## Running tests
|
44
|
+
To run the coverage suite:
|
45
|
+
```
|
46
|
+
rake coverage:spec
|
47
|
+
```
|
48
|
+
Results will be in coverage/index.html directory.
|
49
|
+
|
50
|
+
## Installing as a gem
|
51
|
+
```
|
52
|
+
gem install pimon
|
53
|
+
```
|
54
|
+
After installation just do _pimon start_ and go to http://localhost:3000 and check your stats
|
55
|
+
(This will only work on your Raspberry Pi and perhaps some other linux distros, check the quirks section for more info).
|
56
|
+
|
57
|
+
## Quirks
|
58
|
+
Pimon uses _vmstat_ and _free_ to collect it's stats from the operating system and these are only
|
59
|
+
available on operating systems that have the /proc filesystem.
|
60
|
+
So if you want to develop on a Mac you may use the mock implementations that are in the bin directory.
|
61
|
+
The mock implementations are programmed in C and mimic the output of _vmstat_ and _free_.
|
62
|
+
They just change and generate some random values on the observed stats using /dev/urandom.
|
63
|
+
To use them you must first compile them using _make_ and then include the bin directory of this project
|
64
|
+
in your $PATH to have them available when you run the sinatra application.
|
65
|
+
The temperature stat is only available with the latest Raspbian distro (2012-09-18) on your Raspberry Pi and will (may)
|
66
|
+
not work if you're developing on other systems.
|
67
|
+
|
68
|
+
## TODO
|
69
|
+
1. Improve disk stats, have a way of having custom mount points
|
70
|
+
2. Capistrano task to reset production basic_auth username and password
|
71
|
+
3. Show uptime
|
72
|
+
4. Change configuration in realtime
|
73
|
+
5. Daemonize if running in production through bin/pimon (usefull for production environments without deploying through
|
74
|
+
capistrano)
|
75
|
+
|
76
|
+
## Copyright
|
77
|
+
Licensed under the [WTFPL](http://en.wikipedia.org/wiki/WTFPL "Do What The Fuck You Want To Public License") license.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
desc 'run specs'
|
4
|
+
RSpec::Core::RakeTask.new
|
5
|
+
|
6
|
+
namespace :coverage do
|
7
|
+
desc 'run rspec code coverage'
|
8
|
+
task :spec do
|
9
|
+
ENV['COVERAGE'] = 'on'
|
10
|
+
FileUtils.rm_r 'coverage', :force => true
|
11
|
+
Rake::Task[:spec].execute
|
12
|
+
end
|
13
|
+
end
|
data/WTFPL-LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
2
|
+
Version 2, December 2004
|
3
|
+
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
5
|
+
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
7
|
+
copies of this license document, and changing it is allowed as long
|
8
|
+
as the name is changed.
|
9
|
+
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
12
|
+
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
@@ -0,0 +1 @@
|
|
1
|
+
/Users/pecarrico/opt/redis/src/redis-cli -s /tmp/redis.sock del pimon_mem del pimon_swap del pimon_cpu del pimon_time del pimon_disk pimon_temp
|
data/bin/free.c
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
int main (int argc, char *argv[])
|
5
|
+
{
|
6
|
+
int mem_used = generate_random();
|
7
|
+
int swap_used = generate_random();
|
8
|
+
|
9
|
+
printf(" total used free shared buffers cached\nMem: 215 %d %d 0 4 110\nSwap: 100 %d %d\n", mem_used, 215 - mem_used, swap_used, 100 - swap_used);
|
10
|
+
|
11
|
+
exit (0);
|
12
|
+
}
|
data/bin/makefile
ADDED
data/bin/pimon
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
action = ARGV[0]
|
3
|
+
environment = ARGV[1]
|
4
|
+
|
5
|
+
case action
|
6
|
+
when "start"
|
7
|
+
require 'rack'
|
8
|
+
|
9
|
+
puts 'Pimon is starting at http://localhost:3000'
|
10
|
+
config = "#{File.dirname(__FILE__)}/../config/config.ru"
|
11
|
+
|
12
|
+
ARGV[1] ? ENV['RACK_ENV'] = environment : ENV['RACK_ENV'] = 'development'
|
13
|
+
|
14
|
+
puts "Running in #{ENV['RACK_ENV']} mode."
|
15
|
+
server = Rack::Server.new(:config => config, :Port => 3000, :server => 'thin')
|
16
|
+
server.start
|
17
|
+
else
|
18
|
+
puts "Usage: pimon start <environment>"
|
19
|
+
end
|
data/bin/random.c
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <unistd.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <math.h>
|
5
|
+
|
6
|
+
int generate_random()
|
7
|
+
{
|
8
|
+
FILE *urandom;
|
9
|
+
unsigned int seed;
|
10
|
+
int cpu_idle;
|
11
|
+
|
12
|
+
urandom = fopen ("/dev/urandom", "r");
|
13
|
+
if (urandom == NULL) {
|
14
|
+
fprintf (stderr, "ERROR: Cannot open /dev/urandom!\n");
|
15
|
+
exit (1);
|
16
|
+
}
|
17
|
+
fread (&seed, sizeof (seed), 1, urandom);
|
18
|
+
srand (seed);
|
19
|
+
|
20
|
+
return ((int) floor (rand() * 100.0 / ((double) RAND_MAX + 1) ) + 1);
|
21
|
+
}
|
data/bin/random.h
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
extern int generate_random();
|
data/bin/vmstat.c
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include "random.h"
|
4
|
+
|
5
|
+
int main (int argc, char *argv[])
|
6
|
+
{
|
7
|
+
int cpu_idle = generate_random();
|
8
|
+
|
9
|
+
printf("procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----\n r b swpd free buff cache si so bi bo in cs us sy id wa\n 1 0 10976 50992 4900 113188 1 2 109 244 101 183 11 10 77 1\n 0 0 10976 50992 4900 113188 0 0 0 0 8366 315 10 5 %d 0\n", cpu_idle);
|
10
|
+
|
11
|
+
exit (0);
|
12
|
+
}
|
data/config/config.ru
ADDED
data/config/deploy.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
set :application, "pimon"
|
2
|
+
set :user, "pi"
|
3
|
+
|
4
|
+
set :scm, :git
|
5
|
+
|
6
|
+
set :repository, "git://github.com/pedrocarrico/pimon.git"
|
7
|
+
|
8
|
+
set :deploy_to, '/home/pi/app/pimon'
|
9
|
+
set :deploy_via, :remote_cache # quicker checkouts from github
|
10
|
+
|
11
|
+
set :domain, 'raspberrypi'
|
12
|
+
role :app, domain
|
13
|
+
role :web, domain
|
14
|
+
|
15
|
+
set :runner, user
|
16
|
+
set :use_sudo, false
|
17
|
+
|
18
|
+
after 'deploy:update_code', 'deploy:bundle_install'
|
19
|
+
|
20
|
+
namespace :deploy do
|
21
|
+
task :start, :roles => [:web, :app] do
|
22
|
+
run "cd #{deploy_to}/current && nohup thin -C config/thin/config.yml -R config/config.ru start"
|
23
|
+
end
|
24
|
+
|
25
|
+
task :stop, :roles => [:web, :app] do
|
26
|
+
run "cd #{deploy_to}/current && nohup thin -C config/thin/config.yml -R config/config.ru stop"
|
27
|
+
end
|
28
|
+
|
29
|
+
task :restart, :roles => [:web, :app] do
|
30
|
+
deploy.stop
|
31
|
+
deploy.check_basic_auth
|
32
|
+
deploy.start
|
33
|
+
end
|
34
|
+
|
35
|
+
task :cold do
|
36
|
+
deploy.update
|
37
|
+
deploy.check_basic_auth
|
38
|
+
deploy.start
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "After deploying check if there's need for a new username/password for the basic_auth"
|
42
|
+
task :check_basic_auth, :roles => :app do
|
43
|
+
require "yaml"
|
44
|
+
set :username, proc { Capistrano::CLI.ui.ask("username : ") }
|
45
|
+
set :password, proc { Capistrano::CLI.password_prompt("password : ") }
|
46
|
+
set :shared_config, "#{deploy_to}/shared/production.yml"
|
47
|
+
|
48
|
+
if 'true' == capture("if [ -e #{shared_config} ]; then echo 'true'; fi").strip
|
49
|
+
run "cp #{shared_config} #{deploy_to}/current/config/production.yml"
|
50
|
+
else
|
51
|
+
production_config = YAML::load_file('config/production.yml')
|
52
|
+
production_config['basic_auth']['username'] = username
|
53
|
+
production_config['basic_auth']['password'] = password
|
54
|
+
|
55
|
+
put YAML::dump(production_config), shared_config, :mode => 0664
|
56
|
+
run "cp #{shared_config} #{deploy_to}/current/config/production.yml"
|
57
|
+
puts "DONE"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "run 'bundle install' to install Bundler's packaged gems for the current deploy"
|
62
|
+
task :bundle_install, :roles => :app do
|
63
|
+
run "cd #{deploy_to}/current && bundle install --without test development"
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
basic_auth:
|
2
|
+
enabled: false
|
3
|
+
redis:
|
4
|
+
socket: /tmp/redis.sock
|
5
|
+
chart:
|
6
|
+
cpu:
|
7
|
+
color: '#D2691E'
|
8
|
+
disk:
|
9
|
+
color: '#CDC673'
|
10
|
+
mem:
|
11
|
+
color: '#87CEFA'
|
12
|
+
temp:
|
13
|
+
color: '#FF9B04'
|
14
|
+
swap:
|
15
|
+
color: '#3CB371'
|
16
|
+
queues:
|
17
|
+
time: pimon_time
|
18
|
+
cpu: pimon_cpu
|
19
|
+
disk: pimon_disk
|
20
|
+
mem: pimon_mem
|
21
|
+
swap: pimon_swap
|
22
|
+
temp: pimon_temp
|
23
|
+
stats_collector:
|
24
|
+
number_of_stats: 6
|
25
|
+
time_period_in_min: 1
|
@@ -0,0 +1,27 @@
|
|
1
|
+
basic_auth:
|
2
|
+
enabled: true
|
3
|
+
username: changed_on_deploy
|
4
|
+
password: changed_on_deploy
|
5
|
+
redis:
|
6
|
+
socket: /tmp/redis.sock
|
7
|
+
chart:
|
8
|
+
cpu:
|
9
|
+
color: '#D2691E'
|
10
|
+
disk:
|
11
|
+
color: '#CDC673'
|
12
|
+
mem:
|
13
|
+
color: '#87CEFA'
|
14
|
+
temp:
|
15
|
+
color: '#FF9B04'
|
16
|
+
swap:
|
17
|
+
color: '#3CB371'
|
18
|
+
queues:
|
19
|
+
time: pimon_time
|
20
|
+
cpu: pimon_cpu
|
21
|
+
disk: pimon_disk
|
22
|
+
mem: pimon_mem
|
23
|
+
swap: pimon_swap
|
24
|
+
temp: pimon_temp
|
25
|
+
stats_collector:
|
26
|
+
number_of_stats: 12
|
27
|
+
time_period_in_min: 5
|