checkup 0.0.2

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.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *~
2
+ .DS_Store
3
+ .rvmrc
4
+ models/
5
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ checkup (0.0.1)
5
+ httparty
6
+ thor (~> 0.14.6)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ httparty (0.9.0)
12
+ multi_json (~> 1.0)
13
+ multi_xml
14
+ multi_json (1.3.6)
15
+ multi_xml (0.5.1)
16
+ thor (0.14.6)
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ checkup!
data/bin/checkup ADDED
@@ -0,0 +1,9 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # whole library
4
+ require File.expand_path("../../lib/checkup", __FILE__)
5
+ # cli interface for the binary
6
+ require File.expand_path("../../lib/checkup/cli/utility", __FILE__)
7
+
8
+
9
+ Checkup::CLI::Utility.start
data/checkup.gemspec ADDED
@@ -0,0 +1,24 @@
1
+
2
+
3
+ require File.expand_path('lib/checkup/version')
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'checkup'
7
+ gem.version = Checkup::Version.current
8
+ gem.platform = Gem::Platform::RUBY
9
+ gem.authors = 'Heiko Moeller'
10
+ gem.email = 'femaref@googlemail.com'
11
+ gem.homepage = 'http://rubygems.org/gems/checkup'
12
+ gem.summary = ''
13
+
14
+
15
+ gem.files = %x[git ls-files].split("\n")
16
+ gem.test_files = %x[git ls-files -- {spec}/*].split("\n")
17
+ gem.require_path = 'lib'
18
+
19
+ gem.executables = ['checkup']
20
+
21
+ gem.add_dependency 'thor', ['~> 0.14.6']
22
+ gem.add_dependency 'httparty'
23
+
24
+ end
data/lib/checkup.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'thor'
5
+ rescue LoadError
6
+ puts 'Checkup requires the Thor library'
7
+ exit 1
8
+ end
9
+
10
+ module Checkup
11
+ LIBRARY_PATH = File.join(File.dirname(__FILE__), 'checkup')
12
+ TEMPLATE_PATH = File.join(File.dirname(__FILE__), '..', 'templates')
13
+ CLI_PATH = File.join(LIBRARY_PATH, 'cli')
14
+ CONFIGURATION_PATH = File.join(LIBRARY_PATH, 'configuration')
15
+
16
+ autoload :Binder, File.join(LIBRARY_PATH, 'binder')
17
+ autoload :Config, File.join(LIBRARY_PATH, 'config')
18
+ autoload :Dependency, File.join(LIBRARY_PATH, 'dependency')
19
+ autoload :Errors, File.join(LIBRARY_PATH, 'errors')
20
+ autoload :Logger, File.join(LIBRARY_PATH, 'logger')
21
+ autoload :Model, File.join(LIBRARY_PATH, 'model')
22
+ autoload :Template, File.join(LIBRARY_PATH, 'template')
23
+ autoload :Version, File.join(LIBRARY_PATH, 'version')
24
+
25
+ module CLI
26
+ autoload :Utility, File.join(CLI_PATH, 'utility')
27
+ end
28
+
29
+ module Configuration
30
+ autoload :Base, File.join(CONFIGURATION_PATH, 'base')
31
+ autoload :Helpers, File.join(CONFIGURATION_PATH, 'helpers')
32
+
33
+ module Notifier
34
+ autoload :Base, File.join(CONFIGURATION_PATH, 'notifier', 'base')
35
+ autoload :Mail, File.join(CONFIGURATION_PATH, 'notifier', 'mail')
36
+ end
37
+
38
+ module Service
39
+ autoload :Base, File.join(CONFIGURATION_PATH, 'service', 'base')
40
+ autoload :Http, File.join(CONFIGURATION_PATH, 'service', 'http')
41
+ end
42
+ end
43
+
44
+ module Notifier
45
+ autoload :Base, File.join(LIBRARY_PATH, 'notifier', 'base')
46
+ autoload :Mail, File.join(LIBRARY_PATH, 'notifier', 'mail')
47
+ end
48
+
49
+ module Service
50
+ autoload :Base, File.join(LIBRARY_PATH, 'service', 'base')
51
+ autoload :Http, File.join(LIBRARY_PATH, 'service', 'http')
52
+ end
53
+ end
@@ -0,0 +1,14 @@
1
+ module Checkup
2
+ class Binder
3
+ def initialize(key_and_values)
4
+ key_and_values.each do |key, value|
5
+ instance_variable_set("@#{key}", value)
6
+ end
7
+ end
8
+
9
+ def get_binding
10
+ binding
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,62 @@
1
+ module Checkup
2
+ module CLI
3
+ class Utility < Thor
4
+ include Thor::Actions
5
+
6
+ method_option :trigger, :type => :string, :required => true, :aliases => ['-t', '--triggers']
7
+ method_option :root_path, :type => :string, :default => '', :aliases => '-r'
8
+ desc 'perform', 'executes a named model'
9
+ def perform
10
+ root_path = options[:root_path]
11
+
12
+ if root_path == ""
13
+ root_path = Checkup::Config::DEFAULT_ROOT_PATH
14
+ end
15
+
16
+ load root_path
17
+
18
+ triggers = options[:trigger].split(",")
19
+ triggers.map!(&:strip).map! {|t|
20
+ t.include?('*') ? Model.find_matching(t) : t
21
+ }.flatten!
22
+
23
+ triggers.each do |trigger|
24
+ model = Model.find(trigger)
25
+ model.perform!
26
+ Logger.clear!
27
+ end
28
+ end
29
+
30
+ method_option :root_path, :type => :string, :default => '', :aliases => '-r'
31
+ desc 'list', 'lists all models'
32
+ def list
33
+ root_path = options[:root_path]
34
+
35
+ if root_path == ""
36
+ root_path = Checkup::Config::DEFAULT_ROOT_PATH
37
+ end
38
+
39
+ load root_path
40
+
41
+ Model.all.each do |model|
42
+ puts model.trigger
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def load (path)
49
+ path = File.expand_path path
50
+
51
+ if !Dir.exists? path
52
+ FileUtils.mkdir_p path
53
+ end
54
+
55
+ Dir[File.join(path, "*.rb")].each do |file|
56
+ Checkup::Config.class_eval File.read(File.expand_path(File.basename(file), path))
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,41 @@
1
+ module Checkup
2
+ module Config
3
+ DEFAULT_ROOT_PATH = '~/.checkup'
4
+
5
+ class << self
6
+ def add_dsl_constants!
7
+ create_modules(
8
+ self,
9
+ [
10
+ # Services
11
+ ['Http'],
12
+ # Notifiers
13
+ ['Mail']
14
+ ]
15
+ )
16
+ end
17
+
18
+ def create_modules(scope, names)
19
+ names.flatten.each do |name|
20
+ if name.is_a?(Hash)
21
+ name.each do |key, val|
22
+ create_modules(get_or_create_empty_module(scope, key), [val])
23
+ end
24
+ else
25
+ get_or_create_empty_module(scope, name)
26
+ end
27
+ end
28
+ end
29
+
30
+ def get_or_create_empty_module(scope, const)
31
+ if scope.const_defined?(const)
32
+ scope.const_get(const)
33
+ else
34
+ scope.const_set(const, Module.new)
35
+ end
36
+ end
37
+ end
38
+
39
+ add_dsl_constants!
40
+ end
41
+ end
@@ -0,0 +1,6 @@
1
+ module Checkup
2
+ module Configuration
3
+ class Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ module Checkup
4
+ module Configuration
5
+ module Helpers
6
+
7
+ ##
8
+ # Finds all the object's getter methods and checks the global
9
+ # configuration for these methods, if they respond then they will
10
+ # assign the object's attribute(s) to that particular global configuration's attribute
11
+ def load_defaults!
12
+ module_names = self.class.name.split('::')[1..-1]
13
+ configuration = Checkup::Configuration
14
+ module_names.each do |module_name|
15
+ configuration = configuration.const_get(module_name)
16
+ end
17
+
18
+ getter_methods.each do |attribute|
19
+ if configuration.respond_to?(attribute)
20
+ self.send("#{attribute}=", configuration.send(attribute))
21
+ end
22
+ end
23
+ end
24
+
25
+ ##
26
+ # Clears all the defaults that may have been set by the user
27
+ def clear_defaults!
28
+ setter_methods.each do |method|
29
+ self.send(method, nil)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ ##
36
+ # Returns an Array of the setter methods (as String)
37
+ def setter_methods
38
+ methods.map do |method|
39
+ method = method.to_s
40
+ method if method =~ /^\w(\w|\d|\_)+\=$/ and method != 'taguri='
41
+ end.compact
42
+ end
43
+
44
+ ##
45
+ # Returns an Array of getter methods (as String)
46
+ def getter_methods
47
+ setter_methods.map {|method| method.sub('=','') }
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ module Checkup
2
+ module Configuration
3
+ module Notifier
4
+ class Base < Configuration::Base
5
+ class << self
6
+ attr_accessor :on_success
7
+ attr_accessor :on_warning
8
+ attr_accessor :on_failure
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+
3
+ module Checkup
4
+ module Configuration
5
+ module Notifier
6
+ class Mail < Base
7
+ class << self
8
+
9
+ ##
10
+ # Mail delivery method to be used by the Mail gem.
11
+ # Supported methods:
12
+ #
13
+ # `:smtp` [::Mail::SMTP] (default)
14
+ # : Settings used only by this method:
15
+ # : `address`, `port`, `domain`, `user_name`, `password`
16
+ # : `authentication`, `enable_starttls_auto`, `openssl_verify_mode`
17
+ #
18
+ # `:sendmail` [::Mail::Sendmail]
19
+ # : Settings used only by this method:
20
+ # : `sendmail`, `sendmail_args`
21
+ #
22
+ # `:exim` [::Mail::Exim]
23
+ # : Settings used only by this method:
24
+ # : `exim`, `exim_args`
25
+ #
26
+ # `:file` [::Mail::FileDelivery]
27
+ # : Settings used only by this method:
28
+ # : `mail_folder`
29
+ #
30
+ attr_accessor :delivery_method
31
+
32
+ ##
33
+ # Sender and Receiver email addresses
34
+ # Examples:
35
+ # sender - my.email.address@gmail.com
36
+ # receiver - your.email.address@gmail.com
37
+ attr_accessor :from, :to
38
+
39
+ ##
40
+ # The address to use
41
+ # Example: smtp.gmail.com
42
+ attr_accessor :address
43
+
44
+ ##
45
+ # The port to connect to
46
+ # Example: 587
47
+ attr_accessor :port
48
+
49
+ ##
50
+ # Your domain (if applicable)
51
+ # Example: mydomain.com
52
+ attr_accessor :domain
53
+
54
+ ##
55
+ # Username and Password (sender email's credentials)
56
+ # Examples:
57
+ # user_name - meskyanichi
58
+ # password - my_secret_password
59
+ attr_accessor :user_name, :password
60
+
61
+ ##
62
+ # Authentication type
63
+ # Example: plain
64
+ attr_accessor :authentication
65
+
66
+ ##
67
+ # Automatically set TLS
68
+ # Example: true
69
+ attr_accessor :enable_starttls_auto
70
+
71
+ ##
72
+ # OpenSSL Verify Mode
73
+ # Example: none - Only use this option for a self-signed and/or wildcard certificate
74
+ attr_accessor :openssl_verify_mode
75
+
76
+ ##
77
+ # When using the `:sendmail` `delivery_method` option,
78
+ # this may be used to specify the absolute path to `sendmail` (if needed)
79
+ # Example: '/usr/sbin/sendmail'
80
+ attr_accessor :sendmail
81
+
82
+ ##
83
+ # Optional arguments to pass to `sendmail`
84
+ # Note that this will override the defaults set by the Mail gem (currently: '-i -t')
85
+ # So, if set here, be sure to set all the arguments you require.
86
+ # Example: '-i -t -X/tmp/traffic.log'
87
+ attr_accessor :sendmail_args
88
+
89
+ ##
90
+ # When using the `:exim` `delivery_method` option,
91
+ # this may be used to specify the absolute path to `exim` (if needed)
92
+ # Example: '/usr/sbin/exim'
93
+ attr_accessor :exim
94
+
95
+ ##
96
+ # Optional arguments to pass to `exim`
97
+ # Note that this will override the defaults set by the Mail gem (currently: '-i -t')
98
+ # So, if set here, be sure to set all the arguments you require.
99
+ # Example: '-i -t -X/tmp/traffic.log'
100
+ attr_accessor :exim_args
101
+
102
+ ##
103
+ # Folder where mail will be kept when using the `:file` `delivery_method` option.
104
+ # Default location is '$HOME/backup-mails'
105
+ # Example: '/tmp/test-mails'
106
+ attr_accessor :mail_folder
107
+
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,10 @@
1
+ module Checkup
2
+ module Configuration
3
+ module Service
4
+ class Base < Configuration::Base
5
+ class << self
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Checkup
2
+ module Configuration
3
+ module Service
4
+ class Http < Base
5
+ class << self
6
+ attr_accessor :url
7
+ attr_accessor :method
8
+ attr_accessor :expected_code
9
+ attr_accessor :expected_response
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ module Checkup
4
+ # Small dependency loader, so we don't have to require all possible gems in the Gemfile
5
+ class Dependency
6
+ def self.all
7
+ @all ||= {
8
+ 'mail' => {
9
+ :require => 'mail',
10
+ :version => '>= 2.4.0',
11
+ :for => 'Sending Emails (Mail Notifier)'
12
+ },
13
+ 'httparty' => {
14
+ :require => 'httparty',
15
+ :version => '>= 0',
16
+ :for => 'Http up check'
17
+ }
18
+ }
19
+ end
20
+
21
+ def self.load (name)
22
+ begin
23
+ gem(name, all[name][:version])
24
+ require(all[name][:require])
25
+ rescue LoadError
26
+ Logger.error Errors::Dependency::LoadError.new(<<-EOS)
27
+ Dependency missing
28
+ Dependency required for:
29
+ #{all[name][:for]}
30
+ To install the gem, issue the following command:
31
+ > gem install #{name} -v '#{all[name][:version]}'
32
+ Please try again after installing the missing dependency.
33
+ EOS
34
+ exit 1
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,80 @@
1
+ module Checkup
2
+ # when included, automatically creates new Exceptions depending on the Const passed in
3
+ module ErrorsHelper
4
+ def const_missing(const)
5
+ if const.to_s.end_with?('Error')
6
+ module_eval("class #{const} < Checkup::Errors::Error; end")
7
+ else
8
+ module_eval("module #{const}; extend Checkup::ErrorsHelper; end")
9
+ end
10
+ const_get(const)
11
+ end
12
+ end
13
+
14
+ module Errors
15
+ extend ErrorsHelper
16
+
17
+ class Error < StandardError
18
+
19
+ def self.wrap(orig_err, msg = nil)
20
+ new(msg, orig_err)
21
+ end
22
+
23
+ def initialize(msg = nil, orig_err = nil)
24
+ super(msg)
25
+ set_backtrace(orig_err.backtrace) if @orig_err = orig_err
26
+ end
27
+
28
+ def to_s
29
+ return @to_s if @to_s
30
+ orig_to_s = super()
31
+
32
+ if orig_to_s == self.class.to_s
33
+ msg = orig_err_msg ?
34
+ "#{orig_err_class}: #{orig_err_msg}" : orig_err_class
35
+ else
36
+ msg = format_msg(orig_to_s)
37
+ msg << "\n Reason: #{orig_err_class}" + (orig_err_msg ?
38
+ "\n #{orig_err_msg}" : ' (no message given)') if @orig_err
39
+ end
40
+
41
+ @to_s = msg ? msg_prefix + msg : class_name
42
+ end
43
+
44
+ private
45
+
46
+ def msg_prefix
47
+ @msg_prefix ||= class_name + ': '
48
+ end
49
+
50
+ def orig_msg
51
+ @orig_msg ||= to_s.sub(msg_prefix, '')
52
+ end
53
+
54
+ def class_name
55
+ @class_name ||= self.class.to_s.sub('Checkup::Errors::', '')
56
+ end
57
+
58
+ def orig_err_class
59
+ return unless @orig_err
60
+
61
+ @orig_err_class ||= @orig_err.is_a?(Errors::Error) ?
62
+ @orig_err.send(:class_name) : @orig_err.class.to_s
63
+ end
64
+
65
+ def orig_err_msg
66
+ return unless @orig_err
67
+ return @orig_err_msg unless @orig_err_msg.nil?
68
+
69
+ msg = @orig_err.is_a?(Errors::Error) ?
70
+ @orig_err.send(:orig_msg) : @orig_err.to_s
71
+ @orig_err_msg = (msg == orig_err_class) ?
72
+ false : format_msg(msg)
73
+ end
74
+
75
+ def format_msg(msg)
76
+ msg.gsub(/^ */, ' ').strip
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,157 @@
1
+ # encoding: utf-8
2
+
3
+ module Checkup
4
+ module Logger
5
+ class << self
6
+
7
+ attr_accessor :quiet
8
+
9
+ ##
10
+ # Outputs a messages to the console and writes it to the backup.log
11
+ def message(string)
12
+ to_console loggify(string, :message, :green)
13
+ to_file loggify(string, :message)
14
+ end
15
+
16
+ ##
17
+ # Outputs an error to the console and writes it to the backup.log
18
+ # Called when an Exception has caused the backup process to abort.
19
+ def error(string)
20
+ @has_errors = true
21
+ to_console loggify(string, :error, :red), true
22
+ to_file loggify(string, :error)
23
+ end
24
+
25
+ ##
26
+ # Outputs a notice to the console and writes it to the backup.log
27
+ # Sets #has_warnings? true so :on_warning notifications will be sent
28
+ def warn(string)
29
+ @has_warnings = true
30
+ to_console loggify(string, :warning, :yellow), true
31
+ to_file loggify(string, :warning)
32
+ end
33
+
34
+ # Outputs the data as if it were a regular 'puts' command,
35
+ # but also logs it to the backup.log
36
+ def normal(string)
37
+ to_console loggify(string)
38
+ to_file loggify(string)
39
+ end
40
+
41
+ ##
42
+ # Silently logs data to the log file
43
+ def silent(string)
44
+ to_file loggify(string, :silent)
45
+ end
46
+
47
+ ##
48
+ # Returns an Array of all messages written to the log file for this session
49
+ def messages
50
+ @messages ||= []
51
+ end
52
+
53
+ def has_errors?
54
+ @has_errors ||= false
55
+ end
56
+
57
+ ##
58
+ # Returns true if any warnings have been issued
59
+ def has_warnings?
60
+ @has_warnings ||= false
61
+ end
62
+
63
+ def clear!
64
+ messages.clear
65
+ @has_warnings = false
66
+ end
67
+
68
+ def truncate!(max_bytes = 500_000)
69
+ log_file = File.join(Config.log_path, 'checkup.log')
70
+ return unless File.exist?(log_file)
71
+
72
+ if File.stat(log_file).size > max_bytes
73
+ FileUtils.mv(log_file, log_file + '~')
74
+ File.open(log_file + '~', 'r') do |io_in|
75
+ File.open(log_file, 'w') do |io_out|
76
+ io_in.seek(-max_bytes, IO::SEEK_END) && io_in.gets
77
+ while line = io_in.gets
78
+ io_out.puts line
79
+ end
80
+ end
81
+ end
82
+ FileUtils.rm_f(log_file + '~')
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ ##
89
+ # Returns the time in [YYYY/MM/DD HH:MM:SS] format
90
+ def time
91
+ Time.now.strftime("%Y/%m/%d %H:%M:%S")
92
+ end
93
+
94
+ ##
95
+ # Receives a String, or an Object that responds to #to_s (e.g. an
96
+ # Exception), from one of the messaging methods and converts it into an
97
+ # Array of Strings, split on newline separators. Each line is then
98
+ # formatted into a log format based on the given options, and the Array
99
+ # returned to be passed to to_console() and/or to_file().
100
+ def loggify(string, type = false, color = false)
101
+ lines = string.to_s.split("\n")
102
+ if type
103
+ type = send(color, type) if color
104
+ time_now = time
105
+ lines.map {|line| "[#{time_now}][#{type}] #{line}" }
106
+ else
107
+ lines
108
+ end
109
+ end
110
+
111
+ ##
112
+ # Receives an Array of Strings to be written to the console.
113
+ def to_console(lines, stderr = false)
114
+ return if quiet
115
+ lines.each {|line| stderr ? Kernel.warn(line) : puts(line) }
116
+ end
117
+
118
+ ##
119
+ # Receives an Array of Strings to be written to the log file.
120
+ def to_file(lines)
121
+ # File.open(File.join(Config.log_path, 'checkup.log'), 'a') do |file|
122
+ # lines.each {|line| file.puts line }
123
+ # end
124
+ # messages.push(*lines)
125
+ end
126
+
127
+ ##
128
+ # Invokes the #colorize method with the provided string
129
+ # and the color code "32" (for green)
130
+ def green(string)
131
+ colorize(string, 32)
132
+ end
133
+
134
+ ##
135
+ # Invokes the #colorize method with the provided string
136
+ # and the color code "33" (for yellow)
137
+ def yellow(string)
138
+ colorize(string, 33)
139
+ end
140
+
141
+ ##
142
+ # Invokes the #colorize method the with provided string
143
+ # and the color code "31" (for red)
144
+ def red(string)
145
+ colorize(string, 31)
146
+ end
147
+
148
+ ##
149
+ # Wraps the provided string in colorizing tags to provide
150
+ # easier to view output to the client
151
+ def colorize(string, code)
152
+ "\e[#{code}m#{string}\e[0m"
153
+ end
154
+
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,119 @@
1
+ module Checkup
2
+ class Model
3
+ class << self
4
+ def all
5
+ @all ||= []
6
+ end
7
+
8
+ def find(trigger)
9
+ trigger = trigger.to_s
10
+ all.each do |model|
11
+ return model if model.trigger == trigger
12
+ end
13
+ raise Errors::Model::MissingTriggerError,
14
+ "Could not find trigger '#{trigger}'."
15
+ end
16
+
17
+ def find_matching(trigger)
18
+ regex = /^#{ trigger.to_s.gsub('*', '(.*)') }$/
19
+ all.select {|model| regex =~ model.trigger }
20
+ end
21
+ end
22
+
23
+ attr_reader :trigger
24
+ attr_reader :description
25
+
26
+
27
+ def initialize(trigger, description, &block)
28
+ @trigger = trigger.to_s
29
+ @description = description.to_s
30
+ @started_at = Time.now
31
+
32
+ @services = []
33
+ @notifiers = []
34
+
35
+ instance_eval(&block) if block_given?
36
+ Model.all << self
37
+ end
38
+
39
+ def service(name, &block)
40
+ @services << get_class_from_scope(Service, name).new(self, &block)
41
+ end
42
+
43
+ def notify_with(name, &block)
44
+ @notifiers << get_class_from_scope(Notifier, name).new(self, &block)
45
+ end
46
+
47
+ def perform!
48
+ log!(:started)
49
+
50
+
51
+ @services.each do |service|
52
+ service_result = true
53
+ begin
54
+ Logger.message "Starting service #{service.identifier}"
55
+ service_result &&= service.perform!
56
+ rescue StandardError => e
57
+ service_result = false
58
+ self.notify! :error, service, "#{service.identifier}: #{e.message}"
59
+ Logger.error e.message
60
+ end
61
+
62
+ message = "Finished service #{service.identifier}"
63
+
64
+ if !service_result
65
+ message += " (with errors)"
66
+ Logger.error message
67
+ else
68
+ Logger.message message
69
+ end
70
+
71
+ end
72
+
73
+ log!(:finished)
74
+ end
75
+
76
+ def get_class_from_scope(scope, name)
77
+ klass = scope
78
+ name = name.to_s.sub(/^Checkup::Config::/, '')
79
+ name.split('::').each do |chunk|
80
+ klass = klass.const_get(chunk)
81
+ end
82
+ klass
83
+ end
84
+
85
+ def log!(action)
86
+ case action
87
+ when :started
88
+ Logger.message "Started model '(#{trigger})'!\n" +
89
+ "[ checkup #{ Version.current } : #{ RUBY_DESCRIPTION } ]"
90
+
91
+ when :finished
92
+ msg = "Finished '(#{ trigger })' " +
93
+ "Completed %s in #{ elapsed_time }"
94
+ if Logger.has_warnings?
95
+ Logger.warn msg % 'Successfully (with Warnings)'
96
+ elsif Logger.has_errors?
97
+ Logger.error msg % 'with errors'
98
+ else
99
+ Logger.message msg % 'Successfully'
100
+ end
101
+ end
102
+ end
103
+
104
+ def notify! (status, origin, message)
105
+ @notifiers.each do |notifier|
106
+ notifier.notify! status, origin, message
107
+ end
108
+ end
109
+
110
+ def elapsed_time
111
+ duration = Time.now.to_i - @started_at.to_i
112
+ hours = duration / 3600
113
+ remainder = duration - (hours * 3600)
114
+ minutes = remainder / 60
115
+ seconds = remainder - (minutes * 60)
116
+ '%02d:%02d:%02d' % [hours, minutes, seconds]
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,26 @@
1
+ module Checkup
2
+ module Notifier
3
+ class Base
4
+ include Checkup::Configuration::Helpers
5
+
6
+ attr_accessor :on_success
7
+ alias :notify_on_success? :on_success
8
+
9
+ attr_accessor :on_warning
10
+ alias :notify_on_warning? :on_warning
11
+
12
+ attr_accessor :on_failure
13
+ alias :notify_on_failure? :on_failure
14
+
15
+ def initialize(model)
16
+ @model = model
17
+ load_defaults!
18
+
19
+ yield self
20
+ end
21
+
22
+ def perform!
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,170 @@
1
+ # encoding: utf-8
2
+
3
+ Checkup::Dependency.load('mail')
4
+
5
+ module Checkup
6
+ module Notifier
7
+ class Mail < Base
8
+
9
+ ##
10
+ # Mail delivery method to be used by the Mail gem.
11
+ # Supported methods:
12
+ #
13
+ # `:smtp` [::Mail::SMTP] (default)
14
+ # : Settings used only by this method:
15
+ # : `address`, `port`, `domain`, `user_name`, `password`
16
+ # : `authentication`, `enable_starttls_auto`, `openssl_verify_mode`
17
+ #
18
+ # `:sendmail` [::Mail::Sendmail]
19
+ # : Settings used only by this method:
20
+ # : `sendmail`, `sendmail_args`
21
+ #
22
+ # `:exim` [::Mail::Exim]
23
+ # : Settings used only by this method:
24
+ # : `exim`, `exim_args`
25
+ #
26
+ # `:file` [::Mail::FileDelivery]
27
+ # : Settings used only by this method:
28
+ # : `mail_folder`
29
+ #
30
+ attr_accessor :delivery_method
31
+
32
+ ##
33
+ # Sender and Receiver email addresses
34
+ # Examples:
35
+ # sender - my.email.address@gmail.com
36
+ # receiver - your.email.address@gmail.com
37
+ attr_accessor :from, :to
38
+
39
+ ##
40
+ # The address to use
41
+ # Example: smtp.gmail.com
42
+ attr_accessor :address
43
+
44
+ ##
45
+ # The port to connect to
46
+ # Example: 587
47
+ attr_accessor :port
48
+
49
+ ##
50
+ # Your domain (if applicable)
51
+ # Example: mydomain.com
52
+ attr_accessor :domain
53
+
54
+ ##
55
+ # Username and Password (sender email's credentials)
56
+ # Examples:
57
+ # user_name - meskyanichi
58
+ # password - my_secret_password
59
+ attr_accessor :user_name, :password
60
+
61
+ ##
62
+ # Authentication type
63
+ # Example: plain
64
+ attr_accessor :authentication
65
+
66
+ ##
67
+ # Automatically set TLS
68
+ # Example: true
69
+ attr_accessor :enable_starttls_auto
70
+
71
+ ##
72
+ # OpenSSL Verify Mode
73
+ # Example: none - Only use this option for a self-signed and/or wildcard certificate
74
+ attr_accessor :openssl_verify_mode
75
+
76
+ ##
77
+ # When using the `:sendmail` `delivery_method` option,
78
+ # this may be used to specify the absolute path to `sendmail` (if needed)
79
+ # Example: '/usr/sbin/sendmail'
80
+ attr_accessor :sendmail
81
+
82
+ ##
83
+ # Optional arguments to pass to `sendmail`
84
+ # Note that this will override the defaults set by the Mail gem (currently: '-i -t')
85
+ # So, if set here, be sure to set all the arguments you require.
86
+ # Example: '-i -t -X/tmp/traffic.log'
87
+ attr_accessor :sendmail_args
88
+
89
+ ##
90
+ # When using the `:exim` `delivery_method` option,
91
+ # this may be used to specify the absolute path to `exim` (if needed)
92
+ # Example: '/usr/sbin/exim'
93
+ attr_accessor :exim
94
+
95
+ ##
96
+ # Optional arguments to pass to `exim`
97
+ # Note that this will override the defaults set by the Mail gem (currently: '-i -t')
98
+ # So, if set here, be sure to set all the arguments you require.
99
+ # Example: '-i -t -X/tmp/traffic.log'
100
+ attr_accessor :exim_args
101
+
102
+ ##
103
+ # Folder where mail will be kept when using the `:file` `delivery_method` option.
104
+ # Default location is '$HOME/Backup/emails'
105
+ # Example: '/tmp/test-mails'
106
+ attr_accessor :mail_folder
107
+
108
+ def initialize(model, &block)
109
+ super(model)
110
+
111
+ instance_eval(&block) if block_given?
112
+ end
113
+
114
+ def notify!(status, origin, message)
115
+ email = new_email
116
+ email.subject = "[Checkup::#{status}] #{@model.trigger}"
117
+ template = Checkup::Template.new ({ :origin => origin, :message => message })
118
+ email.body = template.result('notifier/mail/%s.erb' % status.to_s)
119
+
120
+ email.deliver!
121
+ end
122
+
123
+ private
124
+
125
+ ##
126
+ # Configures the Mail gem by setting the defaults.
127
+ # Creates and returns a new email, based on the @delivery_method used.
128
+ def new_email
129
+ method = %w{ smtp sendmail exim file test }.
130
+ index(@delivery_method.to_s) ? @delivery_method.to_s : 'smtp'
131
+
132
+ options =
133
+ case method
134
+ when 'smtp'
135
+ { :address => @address,
136
+ :port => @port,
137
+ :domain => @domain,
138
+ :user_name => @user_name,
139
+ :password => @password,
140
+ :authentication => @authentication,
141
+ :enable_starttls_auto => @enable_starttls_auto,
142
+ :openssl_verify_mode => @openssl_verify_mode }
143
+ when 'sendmail'
144
+ opts = {}
145
+ opts.merge!(:location => File.expand_path(@sendmail)) if @sendmail
146
+ opts.merge!(:arguments => @sendmail_args) if @sendmail_args
147
+ opts
148
+ when 'exim'
149
+ opts = {}
150
+ opts.merge!(:location => File.expand_path(@exim)) if @exim
151
+ opts.merge!(:arguments => @exim_args) if @exim_args
152
+ opts
153
+ when 'file'
154
+ @mail_folder ||= File.join(Config.root_path, 'emails')
155
+ { :location => File.expand_path(@mail_folder) }
156
+ when 'test' then {}
157
+ end
158
+
159
+ ::Mail.defaults do
160
+ delivery_method method.to_sym, options
161
+ end
162
+
163
+ email = ::Mail.new
164
+ email.to = @to
165
+ email.from = @from
166
+ email
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ module Checkup
4
+ module Service
5
+ class Base
6
+ include Checkup::Configuration::Helpers
7
+
8
+ def initialize(model)
9
+ @model = model
10
+ load_defaults!
11
+
12
+ yield self
13
+ end
14
+
15
+ def perform!
16
+ end
17
+
18
+ def identifier
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ Checkup::Dependency.load('httparty')
4
+
5
+ module Checkup
6
+ module Service
7
+ class Http < Base
8
+ attr_accessor :url
9
+ attr_accessor :method
10
+ attr_accessor :expected_code
11
+ attr_accessor :expected_response
12
+
13
+ def perform!
14
+ super
15
+
16
+ response = ::HTTParty.send(self.method.to_sym, self.url)
17
+
18
+ Logger.message "Got #{response.code} from #{self.url}"
19
+
20
+ result = response.code == self.expected_code
21
+
22
+ if !result
23
+ raise Checkup::Errors::Service::Http::AssertError,
24
+ "Expected code #{self.expected_code}, got #{response.code}"
25
+ end
26
+
27
+ if self.expected_response.is_a? Regexp
28
+ result &&= !!self.expected_response.match(response.body)
29
+ if !result
30
+ raise Checkup::Errors::Service::Http::RegexpError,
31
+ "Expected match for #{self.expected_response.to_s}"
32
+ end
33
+ else
34
+ result &&= self.expected_response == response.body
35
+ raise Checkup::Errors::Service::Http::AssertError,
36
+ "Expected response #{self.expected_response}"
37
+ end
38
+
39
+ return result
40
+ end
41
+
42
+ def identifier
43
+ return "#{self.method} #{self.url}"
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,33 @@
1
+ require 'erb'
2
+
3
+ module Checkup
4
+ class Template
5
+
6
+ attr_accessor :binding
7
+
8
+ def initialize(object = nil)
9
+ if object.is_a?(Binding)
10
+ @binding = object
11
+ elsif object.is_a?(Hash)
12
+ @binding = Checkup::Binder.new(object).get_binding
13
+ else
14
+ @binding = nil
15
+ end
16
+ end
17
+
18
+ def render(file)
19
+ puts result(file)
20
+ end
21
+
22
+ def result(file)
23
+ ERB.new(file_contents(file), nil, '<>').result(binding)
24
+ end
25
+
26
+ private
27
+
28
+ def file_contents(file)
29
+ File.read(File.join(Checkup::TEMPLATE_PATH, file))
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ module Checkup
4
+ class Version
5
+
6
+ ##
7
+ # Change the MAJOR, MINOR and PATCH constants below
8
+ # to adjust the version of the Backup gem
9
+ #
10
+ # MAJOR:
11
+ # Defines the major version
12
+ # MINOR:
13
+ # Defines the minor version
14
+ # PATCH:
15
+ # Defines the patch version
16
+ MAJOR, MINOR, PATCH = 0, 0, 2
17
+
18
+ ##
19
+ # Returns the major version ( big release based off of multiple minor releases )
20
+ def self.major
21
+ MAJOR
22
+ end
23
+
24
+ ##
25
+ # Returns the minor version ( small release based off of multiple patches )
26
+ def self.minor
27
+ MINOR
28
+ end
29
+
30
+ ##
31
+ # Returns the patch version ( updates, features and (crucial) bug fixes )
32
+ def self.patch
33
+ PATCH
34
+ end
35
+
36
+ ##
37
+ # Returns the current version of the Backup gem ( qualified for the gemspec )
38
+ def self.current
39
+ "#{major}.#{minor}.#{patch}"
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ Service "<%= @origin.identifier %>" failed with
2
+
3
+ <%= @message %>
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: checkup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Heiko Moeller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.14.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.14.6
30
+ - !ruby/object:Gem::Dependency
31
+ name: httparty
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description:
47
+ email: femaref@googlemail.com
48
+ executables:
49
+ - checkup
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - bin/checkup
57
+ - checkup.gemspec
58
+ - lib/checkup.rb
59
+ - lib/checkup/binder.rb
60
+ - lib/checkup/cli/utility.rb
61
+ - lib/checkup/config.rb
62
+ - lib/checkup/configuration/base.rb
63
+ - lib/checkup/configuration/helpers.rb
64
+ - lib/checkup/configuration/notifier/base.rb
65
+ - lib/checkup/configuration/notifier/mail.rb
66
+ - lib/checkup/configuration/service/base.rb
67
+ - lib/checkup/configuration/service/http.rb
68
+ - lib/checkup/dependency.rb
69
+ - lib/checkup/errors.rb
70
+ - lib/checkup/logger.rb
71
+ - lib/checkup/model.rb
72
+ - lib/checkup/notifier/base.rb
73
+ - lib/checkup/notifier/mail.rb
74
+ - lib/checkup/service/base.rb
75
+ - lib/checkup/service/http.rb
76
+ - lib/checkup/template.rb
77
+ - lib/checkup/version.rb
78
+ - templates/notifier/mail/error.erb
79
+ homepage: http://rubygems.org/gems/checkup
80
+ licenses: []
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 1.8.23
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: ''
103
+ test_files: []