pingmon 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in pingmon.gemspec
4
+ gemspec
@@ -0,0 +1,48 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pingmon (0.1)
5
+ eventmachine (~> 0.12.10)
6
+ pony (~> 1.0.1)
7
+ rufus-scheduler (~> 2.0.6)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activesupport (3.0.1)
13
+ diff-lcs (1.1.2)
14
+ eventmachine (0.12.10)
15
+ i18n (0.4.2)
16
+ mail (2.2.9)
17
+ activesupport (>= 2.3.6)
18
+ i18n (~> 0.4.1)
19
+ mime-types (~> 1.16)
20
+ treetop (~> 1.4.8)
21
+ mime-types (1.16)
22
+ polyglot (0.3.1)
23
+ pony (1.0.1)
24
+ mail (> 2.0)
25
+ rspec (2.0.1)
26
+ rspec-core (~> 2.0.1)
27
+ rspec-expectations (~> 2.0.1)
28
+ rspec-mocks (~> 2.0.1)
29
+ rspec-core (2.0.1)
30
+ rspec-expectations (2.0.1)
31
+ diff-lcs (>= 1.1.2)
32
+ rspec-mocks (2.0.1)
33
+ rspec-core (~> 2.0.1)
34
+ rspec-expectations (~> 2.0.1)
35
+ rufus-scheduler (2.0.6)
36
+ treetop (1.4.8)
37
+ polyglot (>= 0.3.1)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ bundler (>= 1.0.0)
44
+ eventmachine (~> 0.12.10)
45
+ pingmon!
46
+ pony (~> 1.0.1)
47
+ rspec (~> 2.0.1)
48
+ rufus-scheduler (~> 2.0.6)
@@ -0,0 +1,73 @@
1
+ # PingMon: A stupid local-networking host 'ping' monitoring tool
2
+
3
+ One day at work I needed to periodically ping a host on our local network. Then I
4
+ thought it would be great (well... just nice) that when the pings were unsuccessful
5
+ I would get notified by email.
6
+
7
+ I was learning Ruby at that time and, instead of writing a simple shell script and set a cron job
8
+ I thought... *Maybe I could write a script in Ruby for this*, *Maybe I could practice
9
+ writing some tests*, *I could even create a gem and learn how it's done*, etc.
10
+
11
+ And this is the result:
12
+
13
+ A *stupid* monitoring tool which periodically pings a host and sends an email
14
+ notification when it becomes unavailable.
15
+
16
+ *It's been done merely for learning purposes so don't be too harsh on the code.*
17
+
18
+ ### Installation & Usage
19
+
20
+ 1. Install the gem as usual by entering:
21
+ $ gem install pingmon
22
+
23
+ 2. PingMon needs a *YAML configuration file* to operate, which is usually:
24
+ `~/.pingmon.yml`. To make PingMon create that file for you, type:
25
+ $ pingmon build-config
26
+
27
+ 3. Edit `~/.pingmon.yml` to suit your needs.
28
+
29
+ 4. Finally, type `pingmon` on your prompt and have fun! ;)
30
+
31
+ #### .pingmon.yml options
32
+
33
+ There are a number of options you can tweak in the `.pingmon.yml` config file. They
34
+ are pretty self-explanatory but I'll explain some of them here:
35
+
36
+ - **host:** specifies the host to 'ping' to.
37
+ - **mode:** PingMon operation mode which should be one of `monitor` or `ping`. In
38
+ `ping` mode, PingMon will ping the host specified one time only (for testing
39
+ purposes). When in `monitor` mode, PingMon will ping the host specified periodically
40
+ following the `monitor_interval` option.
41
+ - **monitor_interval:** when set to `monitor` mode it specifies the delay between
42
+ *pings* to check the host status. ex: Setting it to `15m` will ping the `host`
43
+ *every* 15 minutes.
44
+ - **notify_when_down:** `true` or `false`. Tells PingMon to send an email notification
45
+ when host can't be reached.
46
+ - **notify_to:** whom to notify (if more than one, comma separated). ex: `user@domain.com`
47
+ - **transport:** `:sendmail` or `:smtp`. `:sendmail` may only work on unix/linux OS
48
+ variants.
49
+ - **smtp_options:** when `transport:` is set to `:smtp` you should specify this
50
+ options. They are passed *as is* to `Pony.mail` method.
51
+
52
+ For more help, please take a look at the sample config file `config/pingmon.yml` or
53
+ at the one PingMon generates for you when you type `pingmon build-config` which is
54
+ usually located at: `$HOME/.pingmon.yml`.
55
+
56
+ ### External Dependencies
57
+
58
+ PingMon depends on the following gems:
59
+
60
+ - [eventmachine](http://github.com/eventmachine/eventmachine) ~> 0.12.10
61
+ - [rufus-scheduler](http://github.com/jmettraux/rufus-scheduler) ~> 2.0.6
62
+ - [pony](http://github.com/adamwiggins/pony) ~> 1.0.1
63
+
64
+ Notes:
65
+
66
+ - [eventmachine](http://github.com/eventmachine/eventmachine) and [rufus-scheduler](http://github.com/jmettraux/rufus-scheduler) are used when doing "pings" in monitor mode.
67
+ - [Pony](http://github.com/adamwiggins/pony) adds the mail sending logic
68
+ - This requirements are specified in the gemspec as well.
69
+
70
+ ---
71
+
72
+ Coded by Estanislau Trepat, released under the MIT License: [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)
73
+
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../lib"
4
+ require 'pingmon'
5
+
6
+ def usage(why = nil)
7
+ puts "failed because: #{why}" if why
8
+ puts "usage:\tpingmon [build-config] [/path/to/pingmon.yml]"
9
+ end
10
+
11
+ usage("wrong number of args") if ARGV.size != 0 && ARGV.size != 1
12
+
13
+ if ARGV.size == 1 && ARGV.first.strip == 'build-config'
14
+ PingMon::Config.build_config
15
+ ARGV.shift
16
+ end
17
+
18
+ begin
19
+ PingMon.log = ENV['PINGMON_LOG'] || 'stdout'
20
+ PingMon.execute_from_config(ARGV.first || PingMon::DEFAULT_CONFIG_FILE)
21
+ rescue PingMon::ConfigFileNotFound => e
22
+ puts "WTF! #{e.message}"
23
+ puts "If this is your first time using pingmon you should run \`pingmon build-config\`." if ARGV.size == 0
24
+ rescue StandardError => e
25
+ puts "WTF! #{e.message}"
26
+ rescue SystemExit, Interrupt
27
+ puts "See ya!"
28
+ end
29
+
@@ -0,0 +1,26 @@
1
+ # pingmon config options
2
+ config:
3
+ # host to be monitored
4
+ host: 192.168.0.7
5
+ # mode (ping/monitor)
6
+ mode: monitor
7
+ # monitor (ping) host every 2 minutes (if set to monitor mode)
8
+ monitor_interval: 2m
9
+ # wether it should send 'down' notifications by email
10
+ notify_when_down: true
11
+ # whom to notify (if more than one, comma separated)
12
+ notify_to: estanis.trepat@inson.es
13
+ # from address
14
+ from_address: estanis.trepat@inson.es
15
+ # :sendmail or :smtp (options below). :sendmail may only work on unix/linux
16
+ transport: :sendmail
17
+ # smtp_options ( if transport is set to :smtp. They are passed *as is* to `Pony.mail` method )
18
+ smtp_options:
19
+ address: your.smtpserver.com
20
+ port: 25
21
+ enable_starttls_auto: false
22
+ user_name: auser
23
+ password: apassword
24
+ authentication: :plain
25
+ domain: smtpserver.com
26
+
@@ -0,0 +1,88 @@
1
+ require 'ping'
2
+ require 'erb'
3
+ require 'yaml'
4
+ require 'rubygems'
5
+ require 'pony'
6
+ require 'eventmachine'
7
+ require 'rufus/scheduler'
8
+
9
+ require File.dirname(__FILE__) + '/pingmon/config.rb'
10
+ require File.dirname(__FILE__) + '/pingmon/pinger.rb'
11
+ require File.dirname(__FILE__) + '/pingmon/monitor.rb'
12
+ require File.dirname(__FILE__) + '/pingmon/version.rb'
13
+
14
+ module PingMon
15
+ DEFAULT_CONFIG_FILE = File.expand_path('~/.pingmon.yml')
16
+
17
+ def self.ping(config=PingMon::Config.new)
18
+ p = PingMon::Pinger.new(config)
19
+ p.ping
20
+ end
21
+
22
+ def self.monitor(config=PingMon::Config.new)
23
+ m = PingMon::Monitor.new(config)
24
+ m.monitor
25
+ end
26
+
27
+ def self.execute_from_config(config_file=PingMon::DEFAULT_CONFIG_FILE)
28
+ config = PingMon::Config.new(config_file).load
29
+ raise "wrong mode" unless %w(ping monitor).include?(config.mode)
30
+
31
+ case config.mode
32
+ when "ping"
33
+ self.ping(config)
34
+ when "monitor"
35
+ self.monitor(config)
36
+ end
37
+ end
38
+
39
+ @@log = nil
40
+
41
+ # value may be a logger instance or a string: 'stdout'|'stderr'|'an actual filename'
42
+ def self.log= log
43
+ @@log = create_log log
44
+ end
45
+
46
+ def self.log
47
+ @@log
48
+ end
49
+
50
+ # Create a log that respond to << like a logger
51
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
52
+ def self.create_log param
53
+ if param
54
+ if param.is_a? String
55
+ if param == 'stdout'
56
+ stdout_logger = Class.new do
57
+ def << obj
58
+ STDOUT.puts obj
59
+ end
60
+ end
61
+ stdout_logger.new
62
+ elsif param == 'stderr'
63
+ stderr_logger = Class.new do
64
+ def << obj
65
+ STDERR.puts obj
66
+ end
67
+ end
68
+ stderr_logger.new
69
+ else
70
+ file_logger = Class.new do
71
+ attr_writer :target_file
72
+
73
+ def << obj
74
+ File.open(@target_file, 'a') { |f| f.puts obj }
75
+ end
76
+ end
77
+ logger = file_logger.new
78
+ logger.target_file = param
79
+ logger
80
+ end
81
+ else
82
+ param
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+
@@ -0,0 +1,46 @@
1
+ require 'ftools'
2
+
3
+ module PingMon
4
+ class ConfigFileNotFound < StandardError
5
+ end
6
+
7
+ class Config
8
+ def initialize(config_file=PingMon::DEFAULT_CONFIG_FILE)
9
+ @config_file = config_file
10
+ @loaded = false
11
+ end
12
+
13
+ attr_accessor :config_file
14
+
15
+ def load
16
+ raise ConfigFileNotFound.new("Configuration file '#{config_file}' could not be found!") unless File.exists?(config_file)
17
+
18
+ PingMon.log << "Loading configuration from '#{@config_file}'" if PingMon.log
19
+
20
+ text = ERB.new(File.read(config_file)).result
21
+ hash = YAML.load(text)
22
+
23
+ base_config = (hash.symbolize_keys[:config]).stringify_keys
24
+ base_config.keys.each do |key|
25
+ instance_variable_set("@#{key}", base_config[key])
26
+ self.class.class_eval do
27
+ define_method(key.to_sym) { instance_variable_get("@#{key}") }
28
+ end
29
+ end
30
+ @loaded = true
31
+
32
+ self
33
+ end
34
+
35
+ def loaded?
36
+ @loaded
37
+ end
38
+
39
+ def self.build_config(where=PingMon::DEFAULT_CONFIG_FILE)
40
+ from = File.dirname(__FILE__) + '/../../config/pingmon.yml'
41
+ File.copy(File.expand_path(from), where)
42
+ PingMon.Log << "Created configuration file '#{where}'." if PingMon.log
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,23 @@
1
+ module PingMon
2
+ class Monitor
3
+ def initialize(configuration=Config.new)
4
+ @config = configuration
5
+ end
6
+
7
+ def monitor
8
+ @config.load unless @config.loaded?
9
+
10
+ PingMon.log << "Monitoring host '#{@config.host}'. Will ping every '#{@config.monitor_interval}'." if PingMon.log
11
+
12
+ EM.run {
13
+ pinger = Pinger.new(@config)
14
+ scheduler = Rufus::Scheduler::EmScheduler.start_new
15
+
16
+ scheduler.every @config.monitor_interval do
17
+ pinger.ping
18
+ end
19
+ }
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,49 @@
1
+ module PingMon
2
+ class Pinger
3
+ def self.ping(host)
4
+ ::Ping.pingecho(host)
5
+ end
6
+
7
+ def initialize(configuration=Config.new)
8
+ @config = configuration
9
+ end
10
+
11
+ def ping
12
+ @config.load unless @config.loaded?
13
+
14
+ PingMon.log << "[#{Time.now}] - Pinging host '#{@config.host}'." if PingMon.log
15
+ result = PingMon::Pinger.ping(@config.host)
16
+ unless result
17
+ PingMon.log << "[#{Time.now}] - '#{@config.host}' appears to be: DOWN. Sending notification." if PingMon.log
18
+ notify_down_status if @config.notify_when_down
19
+ else
20
+ PingMon.log << "[#{Time.now}] - '#{@config.host}' appears to be: UP." if PingMon.log
21
+ end
22
+
23
+ result
24
+ end
25
+
26
+ def host
27
+ @config.host if @config.loaded?
28
+ end
29
+
30
+ protected
31
+ def notify_down_status
32
+ params = build_pony_params_hash
33
+ Pony.mail(params)
34
+ end
35
+
36
+ def build_pony_params_hash
37
+ hash = {
38
+ :to => @config.notify_to,
39
+ :from => @config.from_address,
40
+ :subject => "Monitored host '#{@config.host}' seems to be down",
41
+ :body => "Ping to #{@config.host} failed at #{Time.now}!",
42
+ :via => @config.transport
43
+ }
44
+ hash[:via_options] = @config.smtp_options.symbolize_keys if hash[:via] == :smtp
45
+ return hash
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,8 @@
1
+ module PingMon
2
+ def self.version
3
+ version_path = File.dirname(__FILE__) + "/../../VERSION"
4
+ return File.read(version_path).chomp if File.file?(version_path)
5
+ "0.0"
6
+ end
7
+ end
8
+
@@ -0,0 +1,45 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/pingmon/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = %q{pingmon}
6
+ s.version = PingMon.version
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Estanislau Trepat"]
9
+ s.email = %q{estanis@etrepat.com}
10
+ s.homepage = "http://github.com/etrepat/pingmon"
11
+ s.summary = "A stupid local-networking host 'ping' monitoring tool"
12
+ s.description = %[
13
+ A stupid monitoring tool which periodically pings a host and sends an email
14
+ notification when it becomes unavailable. It was created merely for learning
15
+ purposes and became my first gem.
16
+ ]
17
+ s.date = %q{2010-07-24}
18
+
19
+ s.required_rubygems_version = ">= 1.3.6"
20
+ s.rubyforge_project = "pingmon"
21
+
22
+ s.add_development_dependency "bundler", ">= 1.0.0"
23
+ s.add_development_dependency "rspec", "~> 2.0.1"
24
+
25
+ s.add_dependency "pony", "~> 1.0.1"
26
+ s.add_dependency "eventmachine", "~> 0.12.10"
27
+ s.add_dependency "rufus-scheduler", "~> 2.0.6"
28
+
29
+ s.files = `git ls-files`.split("\n")
30
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
31
+ s.require_path = 'lib'
32
+ s.default_executable = %q{pingmon}
33
+
34
+ s.post_install_message = %[
35
+ ===========================================================================
36
+ Welcome to PingMon!
37
+
38
+ You may need to run \`pingmon build-config\` now if this is your first time
39
+ using pingmon. If not... well... you should just do... nothing ;).
40
+
41
+ Cheers!
42
+ ===========================================================================
43
+ ]
44
+ end
45
+
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pingmon
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ version: "0.2"
10
+ platform: ruby
11
+ authors:
12
+ - Estanislau Trepat
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-24 00:00:00 +02:00
18
+ default_executable: pingmon
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: bundler
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 23
29
+ segments:
30
+ - 1
31
+ - 0
32
+ - 0
33
+ version: 1.0.0
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 13
45
+ segments:
46
+ - 2
47
+ - 0
48
+ - 1
49
+ version: 2.0.1
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: pony
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 21
61
+ segments:
62
+ - 1
63
+ - 0
64
+ - 1
65
+ version: 1.0.1
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: eventmachine
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 59
77
+ segments:
78
+ - 0
79
+ - 12
80
+ - 10
81
+ version: 0.12.10
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: rufus-scheduler
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 2
95
+ - 0
96
+ - 6
97
+ version: 2.0.6
98
+ type: :runtime
99
+ version_requirements: *id005
100
+ description: "\n\
101
+ A stupid monitoring tool which periodically pings a host and sends an email\n\
102
+ notification when it becomes unavailable. It was created merely for learning\n\
103
+ purposes and became my first gem.\n "
104
+ email: estanis@etrepat.com
105
+ executables:
106
+ - pingmon
107
+ extensions: []
108
+
109
+ extra_rdoc_files: []
110
+
111
+ files:
112
+ - .gitignore
113
+ - Gemfile
114
+ - Gemfile.lock
115
+ - README.md
116
+ - Rakefile
117
+ - VERSION
118
+ - bin/pingmon
119
+ - config/pingmon.yml
120
+ - lib/pingmon.rb
121
+ - lib/pingmon/config.rb
122
+ - lib/pingmon/monitor.rb
123
+ - lib/pingmon/pinger.rb
124
+ - lib/pingmon/version.rb
125
+ - pingmon.gemspec
126
+ has_rdoc: true
127
+ homepage: http://github.com/etrepat/pingmon
128
+ licenses: []
129
+
130
+ post_install_message: "\n\
131
+ ===========================================================================\n\
132
+ Welcome to PingMon!\n\n\
133
+ You may need to run `pingmon build-config` now if this is your first time\n\
134
+ using pingmon. If not... well... you should just do... nothing ;).\n\n\
135
+ Cheers!\n\
136
+ ===========================================================================\n "
137
+ rdoc_options: []
138
+
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ hash: 3
147
+ segments:
148
+ - 0
149
+ version: "0"
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ hash: 23
156
+ segments:
157
+ - 1
158
+ - 3
159
+ - 6
160
+ version: 1.3.6
161
+ requirements: []
162
+
163
+ rubyforge_project: pingmon
164
+ rubygems_version: 1.3.7
165
+ signing_key:
166
+ specification_version: 3
167
+ summary: A stupid local-networking host 'ping' monitoring tool
168
+ test_files: []
169
+