servicemonitor 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c21b93e6591e1fdb7d9ab33bfbb185c2fc1a770d
4
+ data.tar.gz: 70a604920114a521584fc6776aa495d0e1893aca
5
+ SHA512:
6
+ metadata.gz: 30e355380f2cad7c5f25592b3d5eb95c2bcf2efcf402001f42e496b6abbafdb27cda3af48faa548d1e40b6350cec7c97cea3aaf136539e8fa5f06f8a5f6e3a59
7
+ data.tar.gz: c177caef1a73ae735546cdef63113a7807710c9c287114395e331a21e227fcad977ee5c5f4907bef01aefc855667274b1e68ca709b7aea06e7d1b985d6d281a3
data/bin/servicemonitor CHANGED
@@ -1,46 +1,45 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- #Add the currently running directory to the start of the load path
3
+ # Add the currently running directory to the start of the load path
4
4
  $:.unshift './'
5
5
 
6
6
  require 'net/smtp'
7
- require "Alert"
8
- require "Alert/Email"
9
- require "MonitorType"
10
- require "MonitorType/Threshold"
11
- require "MonitorType/Beanstalk"
12
- require "MonitorType/Dir"
13
- require "MonitorType/FluidDb"
14
- require "MonitorType/Process"
15
- require "MonitorType/HttpGetJsonList"
16
- require "MonitorManager"
17
- require "helper_functions"
18
-
19
-
20
- #Don't buffer stdout
7
+ require 'Alert'
8
+ require 'Alert/Email'
9
+ require 'MonitorType'
10
+ require 'MonitorType/Threshold'
11
+ require 'MonitorType/Beanstalk'
12
+ require 'MonitorType/Dir'
13
+ require 'MonitorType/FluidDb'
14
+ require 'MonitorType/Process'
15
+ require 'MonitorType/HttpGetJsonList'
16
+ require 'MonitorManager'
17
+ require 'helper_functions'
18
+
19
+ # Don't buffer stdout
21
20
  $stdout.sync = true
22
21
 
23
- abort( "Usage: servicemonitor <path to dsl>" ) if ARGV.length != 1
22
+ abort('Usage: servicemonitor <path to dsl>') if ARGV.length != 1
24
23
 
25
- dslName = ARGV[0]
24
+ dsl_name = ARGV[0]
26
25
 
27
- #Need to remove file name extension
28
- ENV["APP_NAME"] = File.basename( dslName ) if ENV["APP_NAME"].nil?
26
+ # Need to remove file name extension
27
+ ENV['APP_NAME'] = File.basename(dsl_name) if ENV['APP_NAME'].nil?
29
28
 
30
29
  $a = MonitorManager.new
31
30
 
32
- log "Loading dsl, #{dslName}"
31
+ log "Loading dsl, #{dsl_name}"
33
32
  begin
34
- load dslName
35
- $a.run
36
- rescue ArgumentError=>e
37
- puts "*** Your dsl is not formatted correctly"
38
- puts "*** Ensure each line has the format,"
39
- puts "*** <command>, [:arg=>value]"
40
- rescue SystemExit=>e
33
+ load dsl_name
34
+ $a.run
35
+ rescue ArgumentError
36
+ puts "*** Your dsl is not formatted correctly\n" \
37
+ "*** Ensure each line has the format,\n" \
38
+ "*** <command>, [:arg=>value]\n"
39
+ rescue SystemExit
41
40
  # rescue SIGTERM=>e
42
- rescue Exception=>e
43
- puts "What the ..."
44
- puts e.class.name
45
- puts e.message
41
+ rescue StandardError
42
+ puts 'What the ...'
43
+ puts e.class.name
44
+ puts e.message
46
45
  end
@@ -0,0 +1,41 @@
1
+ require 'net/smtp'
2
+ require 'Alert'
3
+
4
+ # Email alert class
5
+ # Uses localhost for sending email - Probably need to change this in the future.
6
+ class AlertEmail
7
+ def initialize(sender, destination, body)
8
+ @sender = sender
9
+ @body = body
10
+
11
+ @smtp_address = ENV['smtp_address'].nil? ? 'localhost' : ENV['smtp_address']
12
+ @smtp_port = ENV['smtp_port'].nil? ? 25 : ENV['smtp_port']
13
+
14
+ @destination = destination
15
+ if destination.is_a? Array
16
+ @destination_fmt = "<#{destination.join('>,<')}>"
17
+ else
18
+ @destination_fmt = destination
19
+ end
20
+ end
21
+
22
+ def send
23
+ message = <<MESSAGE_END
24
+ From: #{ENV['APP_NAME']} #{@sender}
25
+ To: #{@destination_fmt}
26
+ Subject: #{ENV['APP_NAME']} Alert
27
+
28
+ #{@body}
29
+ .
30
+ MESSAGE_END
31
+
32
+ Net::SMTP.start(@smtp_address,@smtp_port) do |smtp|
33
+ smtp.send_message message, @sender, @destination
34
+ end
35
+
36
+ rescue Errno::ECONNREFUSED
37
+ puts "*** Conection refused while attempting to connect to SMTP server\n" \
38
+ "*** Recipient, #{@destination}. Body,\n" \
39
+ "*** #{@body}\n"
40
+ end
41
+ end
data/lib/alert.rb ADDED
@@ -0,0 +1,6 @@
1
+ # Base class / Interface for implementing alert types
2
+ class Alert
3
+ def send(_destination, _body)
4
+ fail 'Method needs to be overridden'
5
+ end
6
+ end
@@ -1,11 +1,9 @@
1
- def log( string, verbose=false )
2
- return if ENV["TESTING"]=="true"
3
-
4
- type = verbose ? "VERB" : "INFO"
5
- if !ENV["VERBOSE"].nil? || verbose==false then
6
- timestamp = Time.new.strftime( "%Y-%m-%d %H:%M:%S" )
7
- puts "[#{type}] #{timestamp} :: #{string}"
8
- end
9
- end
10
-
1
+ def log(string, verbose = false)
2
+ return if ENV['TESTING'] == 'true'
11
3
 
4
+ if !ENV['VERBOSE'].nil? || verbose == false
5
+ type = verbose ? 'VERB' : 'INFO'
6
+ timestamp = Time.new.strftime('%Y-%m-%d %H:%M:%S')
7
+ puts "[#{type}] #{timestamp} :: #{string}"
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ # Monitor Manager
2
+ class MonitorManager
3
+ def initialize
4
+ @list = []
5
+ end
6
+
7
+ def add(monitor)
8
+ @list.push monitor
9
+ end
10
+
11
+ # The main run loop
12
+ def run
13
+ Kernel.loop do
14
+ @list.each do |m|
15
+ begin
16
+ m.run
17
+ rescue MonitorTypeExceptionHandled => e
18
+ m.alert(e.message)
19
+ end
20
+ end
21
+ sleep 0.2
22
+ end
23
+
24
+ rescue Interrupt
25
+ string = "Exiting on request ...\n"
26
+ puts string
27
+
28
+ rescue StandardError
29
+ string = "#{e.class.name}\n" \
30
+ "*** This is really unexpected.\n" \
31
+ "Message: #{e.message}\n" \
32
+ "#{e.backtrace}\n"
33
+ puts string
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ require 'beanstalk-client'
2
+ require 'monitor_type/threshold'
3
+
4
+ # A Beanstalk class for checking how many msgs are in a Queue
5
+ class MonitorTypeBeanstalk < MonitorTypeThreshold
6
+ # Extract parameters
7
+ #
8
+ # @param [String] beanstalk Optional connection string. Default to local
9
+ # @param [String] queue Name of queue to monitor
10
+ def extract_params
11
+ @connection_string = @params[:beanstalk] || 'localhost:11300'
12
+
13
+ if @params[:queue].nil?
14
+ string = "*** Beanstalk parameter missing, queue\n" \
15
+ '*** :queue => <queue name>'
16
+ fail MonitorTypeParameterMissingError, string
17
+ end
18
+ @queue = @params[:queue]
19
+
20
+ @context_sentence = "Checking number of jobs in queue, #{@queue}"
21
+ end
22
+
23
+ def setup
24
+ @beanstalk = Beanstalk::Pool.new([@connection_string])
25
+ end
26
+
27
+ def derived_value
28
+ tube_stats = @beanstalk.stats_tube(@queue)
29
+ tube_stats['current-jobs-ready']
30
+ end
31
+ end
32
+
33
+ def beanstalk(params)
34
+ $a.add(MonitorTypeBeanstalk.new(params))
35
+ end
@@ -0,0 +1,45 @@
1
+ require 'monitor_type/threshold'
2
+
3
+ # A directory class for checking how many files are in a directory
4
+ class MonitorTypeDir < MonitorTypeThreshold
5
+ # Extract parameters
6
+ #
7
+ # @param [String] path Path to directory to check
8
+ def extract_params
9
+ if @params[:path].nil?
10
+ string = "*** Dir parameter missing, path\n" \
11
+ '*** :path => <path to directory to be monitored>'
12
+ fail MonitorTypeParameterMissingError, string
13
+ end
14
+ @path = @params[:path]
15
+
16
+ @context_sentence = "Checking number of files in, #{@path}"
17
+ end
18
+
19
+ def setup
20
+ input_dir = Dir.new(@path)
21
+ @path = input_dir.path
22
+ @params[:dir] = input_dir
23
+
24
+ rescue Errno::ENOENT
25
+ str = "***** Directory does not exist, #{@path}.\n" \
26
+ "***** Create the directory, #{@path}, and try again.\n" \
27
+ "***** eg, mkdir #{@path}"
28
+ raise MonitorTypeExceptionHandled, str
29
+ rescue Errno::ENOTDIR
30
+ str = '***** The specified path does not point to a ' \
31
+ "directory, #{@path}.\n" \
32
+ '***** Either repoint path to a directory, ' \
33
+ "or remove, #{@path}, and create it as a directory.\n" \
34
+ "***** eg, rm #{@path} && mkdir #{@path}"
35
+ raise MonitorTypeExceptionHandled, str
36
+ end
37
+
38
+ def derived_value
39
+ Dir.glob("#{@path}/*").length
40
+ end
41
+ end
42
+
43
+ def dir(params)
44
+ $a.add(MonitorTypeDir.new(params))
45
+ end
@@ -0,0 +1,49 @@
1
+ require 'monitor_type/threshold'
2
+ require 'sys/filesystem'
3
+ include Sys
4
+
5
+ # MonitorType Drive
6
+ class MonitorTypeDrive < MonitorTypeThreshold
7
+ def extract_params
8
+ if @params[:path].nil?
9
+ string = "*** Drive parameter missing, drive\n" \
10
+ '*** :drive => <name of the drive to be monitored>'
11
+ fail MonitorTypeParameterMissingError, string
12
+ end
13
+ @path = @params[:path]
14
+
15
+ log "#{@process_name}", "result: #{(@process_name =~ /^(.*\[{1}.+\]{1}.*)$|^(\w+)$/) == 0}"
16
+
17
+ if @params[:min].nil?
18
+ string = "*** Min parameter missing, min\n" \
19
+ '*** :min => <the minimum amount of free space on ' \
20
+ 'the drive to be monitored>'
21
+ fail MonitorTypeParameterMissingError, string
22
+ end
23
+
24
+ log '*** Max value will be ignored, setting to nil' unless @params[:max].nil?
25
+ @max = nil
26
+
27
+ @context_sentence = 'Checking that available drive space is greater ' \
28
+ "than min, #{@process_name}"
29
+ end
30
+
31
+ def setup
32
+ # Check that the path exists
33
+ Filesystem.stat(@path)
34
+
35
+ rescue
36
+ string = "*** Unable to mount the specifed path\n" \
37
+ "*** path: #{@path}\n" \
38
+ "*** Please fix the error and run again\n"
39
+ raise MonitorTypeExceptionHandled, string
40
+ end
41
+
42
+ def derived_value
43
+ ((Filesystem.stat(@path).blocks_available.to_f / Filesystem.stat(@path).blocks.to_f) * 100).round(2)
44
+ end
45
+ end
46
+
47
+ def process(params)
48
+ $a.add(MonitorTypeDrive.new(params))
49
+ end
@@ -0,0 +1,71 @@
1
+ require 'FluidDb'
2
+ require 'monitor_type/threshold'
3
+
4
+ # A database class for checking a single number against a threshold.
5
+ # For example,
6
+ # get the max timestamp from a table as a date.
7
+ # subtract this from now
8
+ # => check that the number is not greater than 2
9
+ class MonitorTypeFluidDb < MonitorTypeThreshold
10
+ # Extract parameters
11
+ #
12
+ # @param [String] uri Connection string to db
13
+ # @param [String] sql SQL statement to gather a single value
14
+ def extract_params
15
+ if @params[:uri].nil?
16
+ string = "*** FluidDb parameter missing, uri\n" \
17
+ "*** :uri => <uri pointing to db to be monitored>"
18
+ fail MonitorTypeParameterMissingError, string
19
+ end
20
+ begin
21
+ @uri = URI.parse(@params[:uri])
22
+ rescue URI::InvalidURIError
23
+ string = '*** FluidDb encountered an error while parsing the uri' \
24
+ "*** uri: #{@params[:uri]}" \
25
+ "*** Please fix the uri and run again"
26
+ raise MonitorTypeParameterMissingError, string
27
+ end
28
+
29
+ if @params[:sql].nil?
30
+ string = '*** FluidDb parameter missing, sql' \
31
+ "*** :sql => <sql statement, producing a single " \
32
+ 'column, single row which yeidls a number>'
33
+ fail MonitorTypeParameterMissingError, string
34
+ end
35
+ @sql = @params[:sql]
36
+ @context_sentence = "Checking result of sql query, #{@sql}"
37
+ end
38
+
39
+ # Create the connection to the db, and get the value
40
+ # This ensures that all params are correct.
41
+ def setup
42
+ begin
43
+ @fluid_db = FluidDb.Db(@uri)
44
+ rescue StandardError => e
45
+ string = "*** FluidDb encountered an error while connecting to the db\n" \
46
+ "*** Error: #{e.message}\n" \
47
+ "*** uri: #{@uri}\n" \
48
+ "*** Please fix the error and run again\n"
49
+ raise MonitorTypeExceptionHandled, string
50
+ end
51
+
52
+ @params[:fluidDb] = @fluid_db
53
+ end
54
+
55
+ def derived_value
56
+ @fluid_db.queryForValue(@sql, [])
57
+ rescue StandardError
58
+ string = "*** FluidDb encountered an error while running the sql\n" \
59
+ "*** sql: #{@sql}\n" \
60
+ "*** Please fix the query and run again\n"
61
+ raise MonitorTypeExceptionHandled, string
62
+ end
63
+
64
+ def teardown
65
+ @fluid_db.close
66
+ end
67
+ end
68
+
69
+ def fluiddb(params)
70
+ $a.add(MonitorTypeFluidDb.new(params))
71
+ end
@@ -0,0 +1,53 @@
1
+ require 'restclient'
2
+ require 'monitor_type/threshold'
3
+
4
+ # An http class for checking the length of a json list.
5
+ # For example,
6
+ # Get the list of outstandinig errors
7
+ # => check that the number is not greater than 2
8
+ class MonitorTypeHttpGetJsonList < MonitorTypeThreshold
9
+ # Extract parameters
10
+ #
11
+ # @param [String] uri Connection string to db
12
+ # @param [String] sql SQL statement to gather a single value
13
+ def extract_params
14
+ if @params[:uri].nil?
15
+ string = "*** HttpGetJsonList parameter missing, uri\n" \
16
+ '*** :uri => <uri pointing to url to be monitored>'
17
+ fail MonitorTypeParameterMissingError, string
18
+ end
19
+
20
+ begin
21
+ @uri = URI.parse(@params[:uri])
22
+ rescue URI::InvalidURIError
23
+ str = '*** HttpGetJsonList encountered an error while parsing the uri' \
24
+ "*** uri: #{@params[:uri]}" \
25
+ '*** Please fix the uri and run again'
26
+ raise MonitorTypeParameterMissingError, str
27
+ end
28
+
29
+ url = "#{@uri.scheme}://#{@uri.host}#{@uri.path}"
30
+ @context_sentence = "Checking size of json list returned from, #{url}"
31
+ end
32
+
33
+ def derived_value
34
+ content = RestClient.get(@uri.to_s)
35
+ list = JSON.parse(content)
36
+ str = "Expected type, Array - Actual type, #{list.class.name}"
37
+ fail MonitorTypeExceptionHandled, str unless list.class.name == 'Array'
38
+ list.length
39
+ rescue MonitorTypeExceptionHandled
40
+ raise e
41
+
42
+ rescue StandardError
43
+ string = '*** HttpGetJsonList encountered an error while running the ' \
44
+ 'HTTP Get\n' \
45
+ "*** uri: #{@uri}\n" \
46
+ "*** Please fix the query and run again\n"
47
+ raise MonitorTypeExceptionHandled, string
48
+ end
49
+ end
50
+
51
+ def httpgetjsonlist(params)
52
+ $a.add(MonitorTypeHttpGetJsonList.new(params))
53
+ end