qnotifier 0.6.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/Manifest ADDED
@@ -0,0 +1,21 @@
1
+ Manifest
2
+ Rakefile
3
+ bin/qnotifier
4
+ config/qnotifier_config.yml
5
+ gem-public_cert.pem
6
+ lib/command.rb
7
+ lib/plugin.rb
8
+ lib/qnotifier.rb
9
+ lib/storage.rb
10
+ lib/web_service.rb
11
+ plugins/apache.rb
12
+ plugins/iostat.rb
13
+ plugins/mysql.rb
14
+ plugins/network.rb
15
+ plugins/nginx.rb
16
+ plugins/passenger.rb
17
+ plugins/processes.rb
18
+ plugins/rails.rb
19
+ plugins/ruby.rb
20
+ plugins/system.rb
21
+ plugins/urls.rb
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('qnotifier', '0.6.0') do |p|
6
+ p.description = "The server side agent for the QNotifier monitoring system"
7
+ p.url = "http://qnotifier.com/qnotifier_gem"
8
+ p.author = "Gersham Meharg"
9
+ p.email = "gersham@qnotifier.com"
10
+ p.ignore_pattern = ["var/*"]
11
+ p.runtime_dependencies = ["rest-client >=1.4.2", "json >=1.2.3", "elif >=0.1.0"]
12
+ p.development_dependencies = ["rest-client >=1.4.2", "json >=1.2.3", "elif >=0.1.0"]
13
+ p.executable_pattern = ["bin/*"]
14
+ p.install_message = "Qnotifier installed, please register by running 'qnotifier -r CODE' in order to register this server."
15
+ end
data/bin/qnotifier ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift( File.join( File.dirname(__FILE__), '../lib' ) )
3
+ require "command"
4
+
5
+ Qnotifier::Command.run(ARGV)
6
+
@@ -0,0 +1,112 @@
1
+ # qnotifier_config.yml file
2
+ ---
3
+ #
4
+ # This is the configuration file for the Qnotifier Agent
5
+ # It should live in /etc/qnotifier.config
6
+ #
7
+ # Note that this file is YML formatted, please respect the indents
8
+ #
9
+
10
+ #
11
+ # General Settings
12
+ #
13
+
14
+ # Whether to resend alerts
15
+ resend_alerts: true
16
+ # resend_alert_time: Resend alerts every X seconds
17
+ resend_alert_time: 1 #14400 # Four hours
18
+
19
+ # alert_email_address: if this is defined any alerts will be copied to this email address
20
+ # Note that is in addition to the Qnotifier notifications
21
+ #alert_email_address: user@domain.com
22
+
23
+ #
24
+ # PLUGINS
25
+ #
26
+
27
+ # Where to look for user generated plugins
28
+ # To add your own plugin subclass the Qnotifier::Plugin class and put this in to this directory
29
+ # You may add configuration parameters here based on the name of your plugin class
30
+ plugin_directory: "/var/qnotifier"
31
+
32
+ # The System Plugin must be enabled, this gives basic stats like load average, disk use, memory, etc
33
+ System:
34
+ # use_load: either one_minute, five_minute or fifteen_minutes
35
+ use_load: five_minute
36
+ # normalize_load: whether to divide the reported load by the number of CPUs in the system
37
+ normalize_load: true
38
+ # Alert if the CPU is above this percent usage, 0 disables
39
+ alert_cpu_threshold: 10
40
+ # Alert if the memory is above this percent usage, 0 disables
41
+ alert_memory_threshold: 10
42
+ # Alert if the memory is above this percent usage, 0 disables
43
+ alert_load_threshold: 1.0
44
+ # Alert if the memory is above this percent usage, 0 disables
45
+ alert_disk_threshold: 90
46
+ # Partitions which to monitor for free disk space
47
+ partitions:
48
+ - "/"
49
+
50
+ # The Apache built-in plugin
51
+ Apache:
52
+ # Enabled, set to either true or false
53
+ enabled: false
54
+ monitor_url: "http://localhost/foo"
55
+ username: "username"
56
+ password: "password"
57
+
58
+ # The IOStat built-in plugin
59
+ Iostat:
60
+ # Enabled, set to either true or false
61
+ enabled: false
62
+
63
+ # The MySQL built-in plugin
64
+ Mysql:
65
+ # Enabled, set to either true or false
66
+ enabled: false
67
+ username: "username"
68
+ password: "password"
69
+
70
+ # The Network Interface built-in plugin
71
+ Network:
72
+ # Enabled, set to either true or false
73
+ enabled: false
74
+ interfaces:
75
+ - eth0
76
+
77
+ # The Nginx built-in plugin
78
+ Nginx:
79
+ # Enabled, set to either true or false
80
+ enabled: false
81
+ username: "username"
82
+ password: "password"
83
+
84
+ # The Passenger Phusion built-in plugin
85
+ Passenger:
86
+ # Enabled, set to either true or false
87
+ enabled: false
88
+
89
+ # The Process List built-in plugin
90
+ Processes:
91
+ # Enabled, set to either true or false
92
+ enabled: false
93
+
94
+ # The Rails built-in plugin
95
+ Rails:
96
+ # Enabled, set to either true or false
97
+ enabled: false
98
+ log_file: "/var/www/rails/log/production.log"
99
+
100
+ # The Ruby built-in plugin
101
+ Ruby:
102
+ enabled: true
103
+ list_gems: true
104
+
105
+ #
106
+ # Other settings that you generally will not need to modify
107
+ #
108
+
109
+ # The API End Point in which to send our pings
110
+ #api_endpoint: "http://ping.qnotifier.com"
111
+ api_endpoint: "http://localhost:4567"
112
+
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAdnZXJz
3
+ aGFtMRkwFwYKCZImiZPyLGQBGRYJcW5vdGlmaWVyMRMwEQYKCZImiZPyLGQBGRYD
4
+ Y29tMB4XDTEwMDMxNzE4MjAwOFoXDTExMDMxNzE4MjAwOFowQjEQMA4GA1UEAwwH
5
+ Z2Vyc2hhbTEZMBcGCgmSJomT8ixkARkWCXFub3RpZmllcjETMBEGCgmSJomT8ixk
6
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMS8vIaSE0eA
7
+ DfL3OqRwmY+b3ueQ+cfm2nxU1J+TE7yFFGiv+bk4z4YMtHtbqsGxlmL4HZKW7Ur/
8
+ RrS7+d+fVTskoRC7t9g6mRoww/4+fTgmX25g7YLe4vuiSBkBeBMXBt5Vd3ombU9F
9
+ b0CrguX2a2ffYxnF/RlrXnhsU2VywZry+qz1NJglaCa+qb0S0W3BnvoB8T+MxNOM
10
+ 7feKF/HvWRCM7DdHyqXqHFqMBIWJlCC7MFV4kQVW/a8b49VC5Dgmz6QVWcPqQ8cl
11
+ GK35UW+1WZXRB5Mhv5HBAQQqzLut46pxbUJ3qIpibtp1ltgyu81ZIRAwKIWx0YNv
12
+ lP5V85hTZ1ECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUn3O2jt+12CmU
13
+ t1GEK8NZRNRbzqwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQBb5gk8
14
+ OyfuloScbz/oHOopNmSc+o/s/5MvyrslPYDZA0WGR/63Q4Wl6l/tFFPwuAZH1KAI
15
+ MtLf7mVDdijHQf3Q6e+DicNRRQrl1w3s2m4PHyPiFUmXULzWHbMc3OK4LdM+1f5q
16
+ oZvsRrAAz6esBChxfdpuNCsP9Eu3j9MIWHy4KPTNuqOFyI+p3YVW2+SHeN4gBCyV
17
+ b7VZHIY+1kKjmMYXPeG9xlXaxLABhS1iN66tAyg66l6u6vuLt5Rdh1RUIY534Edq
18
+ ciUZJrPp/am/m0FtGWggbAohDKjiKRL0E6OCFQ7wSCTUPKoB9MbIJkKSGFo6ExWe
19
+ wu7A8rLN6CU0SfWf
20
+ -----END CERTIFICATE-----
data/lib/command.rb ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+ require "optparse"
3
+ require "qnotifier"
4
+
5
+ module Qnotifier
6
+ class Command
7
+
8
+ def self.parse_options(argv)
9
+ options = {}
10
+
11
+ op = OptionParser.new do |opts|
12
+
13
+ opts.banner = "\nQnotifier is an agent for the Qnotifer server reporting and alerting system"
14
+ opts.separator "See http://qnotifier.com for details."
15
+ opts.separator "\nUsage:"
16
+
17
+ opts.on("-r", "--register CODE", String, "Register agent with code.") do |register_code|
18
+ qnotifier = Qnotifier::Process.new
19
+ qnotifier.debug = true if @debug
20
+ qnotifier.register(register_code)
21
+ exit
22
+ end
23
+ opts.on("-v", "--version", "Displays the agent version") do |version|
24
+ puts "Qnotifier Agent Version: #{Qnotifier::VERSION}"
25
+ exit
26
+ end
27
+ opts.on("-d", "--debug", "Run in debug mode") do |debug|
28
+ @debug = true
29
+ end
30
+ opts.on("-h", "--help", "Shows this help") do
31
+ puts opts
32
+ exit
33
+ end
34
+ opts.separator "\n"
35
+ end
36
+
37
+ begin
38
+ op.parse!(argv)
39
+ @usage = op.to_s
40
+ rescue OptionParser::InvalidOption
41
+ puts op
42
+ exit
43
+ rescue OptionParser::MissingArgument
44
+ puts op
45
+ exit
46
+ end
47
+ options
48
+ end
49
+
50
+ def self.run(argv)
51
+ argv.push("--help") if argv.first == 'help'
52
+ options = parse_options(argv)
53
+ qnotifier = Qnotifier::Process.new
54
+ qnotifier.debug = true if @debug
55
+ qnotifier.run
56
+ end
57
+ end
58
+ end
59
+
data/lib/plugin.rb ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ require "storage"
3
+
4
+ # Subclass this to create a new plugin
5
+ # Note that plugins only get 30 seconds to run and do their thing
6
+ module Qnotifier
7
+ class Plugin
8
+
9
+ attr_accessor :reports
10
+ attr_accessor :alerts
11
+ attr_accessor :stats
12
+ attr_accessor :config
13
+ attr_accessor :alert_count
14
+
15
+ # The run method, do not override
16
+ def run
17
+ @class_name = self.class.to_s.split("::").last
18
+ @alert_count = 0
19
+
20
+ # Read the options from the global config and mix them in to the defaults for this plugin
21
+ if @config[@class_name]
22
+ @options = @defaults.update(@config[@class_name])
23
+ else
24
+ @options = @defaults
25
+ end
26
+
27
+ # Only run this plugin if it's enabled
28
+ return unless @options["enabled"]
29
+
30
+ Qnotifier.log.debug("Plugin #{@class_name} running")
31
+ main
32
+ end
33
+
34
+ # You'll need to override this in your subclass
35
+ def main
36
+ Qnotifier.log.error("You must implement the main method in the plugin: #{self.class.name}")
37
+ end
38
+
39
+ # Log something to console
40
+ # Log levels: log.info, log.warn, log.error, log.fatal, log.unknown
41
+ def log
42
+ return Qnotifier.log
43
+ end
44
+
45
+ # Alert is an alert to the adminstrators that something requires looking at
46
+ # Severity should usually be 3
47
+ def alert(name, message, severity = 3)
48
+ @alerts = {@class_name => []} unless @alerts
49
+ @alert_count += 1
50
+ # Only send the alert if we haven't already
51
+ if Qnotifier::Storage.get("AlertTime_#{@class_name}-#{name}")
52
+ # Check to see if we need to resend the alert
53
+ if @config["resend_alerts"] and Qnotifier::Storage.get("AlertTime_#{@class_name}-#{name}") < Time.now - @config["resend_alert_time"]
54
+ add_alert(name, message, severity)
55
+ else
56
+ Qnotifier.log.debug("Already sent alert: #{message}")
57
+ end
58
+ else
59
+ add_alert(name, message, severity)
60
+ end
61
+ end
62
+
63
+ # Add the alert to the outbound queue
64
+ def add_alert(name, message, severity)
65
+
66
+ if severity == 1 # emergency
67
+ log.fatal message
68
+ elsif severity == 2 # critical
69
+ log.error message
70
+ elsif severity == 3 # alert
71
+ log.error message
72
+ elsif severity == 4 # error
73
+ log.error message
74
+ elsif severity == 5 # warn
75
+ log.warn message
76
+ elsif severity == 6 # clear
77
+ log.info message
78
+ end
79
+ data = [name, message, severity]
80
+ @alerts[@class_name].push(data)
81
+ Qnotifier::Storage.put("AlertTime_#{@class_name}-#{name}", Time.now)
82
+ end
83
+
84
+ # Alert is no longer needed as the value has crossed back over the threshold value
85
+ def reset_alert(name, message)
86
+ @alerts = {@class_name => []} unless @alerts
87
+ if Qnotifier::Storage.get("AlertTime_#{@class_name}-#{name}")
88
+ log.warn message
89
+ Qnotifier::Storage.delete("AlertTime_#{@class_name}-#{name}")
90
+ data = [name, message, 6] # Clear
91
+ @alerts[@class_name].push(data)
92
+ end
93
+ end
94
+
95
+ # Report is an ongoing data point for graphing and realtime reporting for this server
96
+ def report(key, value)
97
+ @reports = {@class_name => []} unless @reports
98
+ @reports[@class_name].push([key, value])
99
+ end
100
+
101
+ # Stat is a one time statistic about this server, it doesn't get tracked and graphed
102
+ def stat(key, value)
103
+ @stats = {@class_name => {}} unless @stats
104
+ @stats[@class_name].merge!(key => value.to_s)
105
+ end
106
+
107
+ # Store this value for later retrieval
108
+ def put(key, value)
109
+ Qnotifier::Storage.put(key, value)
110
+ end
111
+
112
+ # Retrieve this value
113
+ def get(key)
114
+ Qnotifier::Storage.get(key)
115
+ end
116
+
117
+ # Delete the value
118
+ def delete(key)
119
+ Qnotifier::Storage.delete(key)
120
+ end
121
+ end
122
+ end
data/lib/qnotifier.rb ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env ruby
2
+ require "yaml"
3
+ require "timeout"
4
+ require "logger"
5
+ require "plugin"
6
+ require "web_service"
7
+ require "storage"
8
+
9
+ module Qnotifier
10
+ VERSION = "0.7.0".freeze
11
+
12
+ def self.log
13
+ unless @logger
14
+ begin
15
+ @logger = Logger.new("/var/log/qnotifier.log","monthly")
16
+ rescue Exception => e
17
+ puts "Error starting logging - using stdout (#{e.message})"
18
+ @logger = Logger.new($stdout)
19
+ end
20
+ end
21
+ return @logger
22
+ end
23
+
24
+ class Process
25
+
26
+ attr_accessor :debug
27
+
28
+ def initialize
29
+ Qnotifier::Storage.restore
30
+
31
+ @alerts = {}
32
+ @reports = {}
33
+ @stats = {}
34
+ @alert_count = 0
35
+ end
36
+
37
+ def start_logging
38
+ # Logging
39
+ if @debug
40
+ puts "Starting in debug mode"
41
+ Qnotifier.log.level = Logger::DEBUG
42
+ else
43
+ Qnotifier.log.level = Logger::INFO
44
+ end
45
+ end
46
+
47
+ def run
48
+ start_logging
49
+ load_config
50
+
51
+ last_run = Qnotifier::Storage.get("last_run")
52
+
53
+ if Qnotifier::Storage.get("server_disabled_pings")
54
+ Qnotifier.log.fatal "Disabled by the Qnotifer API, please re-register (qnotifier --register key) this agent to enable. Exiting."
55
+ exit
56
+ end
57
+
58
+ # Start up
59
+ Qnotifier.log.info "Running#{", last run: #{last_run}" if last_run}"
60
+ Qnotifier::Storage.put("last_run", Time.now) unless @debug
61
+ unless @debug
62
+ if last_run and (Time.now - last_run) < 120
63
+ message = "Starting too frequently, please run every 5 minutes (use debug mode to override)\nLast start up: #{last_run}"
64
+ puts message
65
+ Qnotifier.log.fatal message
66
+ exit
67
+ end
68
+ end
69
+
70
+ unless @config["api_key"]
71
+ error_message = "Missing API Key, please register this agent first."
72
+ puts error_message
73
+ Qnotifier.log.fatal error_message
74
+ exit
75
+ end
76
+
77
+ # Load the built in plugins
78
+ Dir[File.dirname(__FILE__) + '/../plugins/*.rb'].each do |file|
79
+ process_plugin_file(file)
80
+ end
81
+
82
+ # Load the user plugins
83
+ Dir[@config["plugin_directory"] + '/*.rb'].each do |file|
84
+ process_plugin_file(file)
85
+ end
86
+
87
+ # Send the alerts, reports and stats to the API
88
+ webservice = Qnotifier::WebService.new
89
+ webservice.config = @config
90
+ webservice.send_alerts(@alerts)
91
+ webservice.send_reports_stats(@reports, @stats, @alert_count)
92
+
93
+ Qnotifier::Storage.save
94
+
95
+ # Done, clean up and save
96
+ Qnotifier::Storage.save
97
+ end
98
+
99
+ def process_plugin_file(file)
100
+ return unless file =~ /\.rb/
101
+ require file
102
+ class_name = "Qnotifier::#{File.basename(file, ".rb").split(/[^a-z0-9]/i).map{|w| w.capitalize}.join}"
103
+ begin
104
+ plugin = eval(class_name).new
105
+ rescue
106
+ Qnotifier.log.error "Couldn't process the plugin file #{file}"
107
+ return
108
+ end
109
+ plugin.config = @config
110
+ unless plugin.class.superclass.name == "Qnotifier::Plugin"
111
+ Qnotifier.log.fatal "Attempted to load a non Qnotifier::Plugin plugin subclass at #{file} - make sure this directory only includes Qnotifier::Plugin subclasses"
112
+ return
113
+ end
114
+ begin
115
+ Timeout.timeout 30 do
116
+ plugin.run
117
+ end
118
+ rescue RuntimeError => e
119
+ Qnotifier.log.error "#{class_name} Plugin Error: #{e.message}"
120
+ rescue Errno::ENOENT => e
121
+ Qnotifier.log.error "#{class_name} Plugin Error: #{e.message}"
122
+ end
123
+ @alerts.merge!(plugin.alerts) if plugin.alerts
124
+ @reports.merge!(plugin.reports) if plugin.reports
125
+ @stats.merge!(plugin.stats) if plugin.stats
126
+ @alert_count += plugin.alert_count
127
+ end
128
+
129
+ def register(code)
130
+
131
+ start_logging
132
+ load_config
133
+
134
+ if @config["api_key"]
135
+ Qnotifier.log.error "Server already registered. You should not keep registering the server, you only need to do this once."
136
+ end
137
+
138
+ webservice = Qnotifier::WebService.new
139
+ webservice.config = @config
140
+ api_key = webservice.register_server(code)
141
+
142
+ save_api_key(api_key)
143
+
144
+ end
145
+
146
+ def save_api_key(api_key)
147
+ return unless api_key
148
+ @config["api_key"] = api_key
149
+ begin
150
+ File.open(File.dirname(__FILE__) + "/../var/api_key", 'w') {|f| f.write(api_key) }
151
+ rescue Exception => e
152
+ Qnotifier.log.fatal "Can't save API Key #{e.message}"
153
+ end
154
+ end
155
+
156
+ def load_config
157
+
158
+ # Make the var dir if it doesn't exist
159
+ var_dir = File.dirname(__FILE__) + "/../var"
160
+ FileUtils.mkdir_p var_dir
161
+
162
+ # Load from /etc/qnotifier_config.yml if the file is there
163
+ begin
164
+ @config = YAML::load(File.open('/etc/qnotifier_config.yml'))
165
+ rescue Exception => e
166
+ Qnotifier.log.error "Can't open /etc/qnotifier_config.yml (loading default config and copying it to /etc/qnotifier_config.yml)"
167
+ begin
168
+ default_config_file = File.dirname(__FILE__) + "/../config/qnotifier_config.yml"
169
+ @config = YAML::load(File.open(default_config_file))
170
+ `cp #{default_config_file} /etc/qnotifier_config.yml`
171
+ rescue Exception => e
172
+ Qnotifier.log.fatal "Can't open default config #{e.message}"
173
+ exit
174
+ end
175
+ end
176
+
177
+ unless @config["api_key"]
178
+ begin
179
+ api_key_file = File.open(File.dirname(__FILE__) + "/../var/api_key")
180
+ while (line = api_key_file.readline)
181
+ @config["api_key"] = line
182
+ end
183
+ rescue EOFError
184
+ rescue Exception => e
185
+ Qnotifier.log.debug "Can't get API key, have you registered?"
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
data/lib/storage.rb ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env
2
+ require "yaml"
3
+
4
+ module Qnotifier
5
+ class Storage
6
+
7
+ @@stored_variables = {}
8
+ @@restored = false
9
+
10
+ def self.restore
11
+ begin
12
+ saved_variables = File.dirname(__FILE__) + "/../var/saved_variables.yml"
13
+ @@stored_variables = YAML::load(File.open(saved_variables))
14
+ rescue Exception => e
15
+ Qnotifier.log.debug "Error loading stored variables file. #{e.message}"
16
+ end
17
+ @@restored = true
18
+ end
19
+
20
+ def self.get(key)
21
+ restore unless @@restored
22
+ if @@stored_variables[key]
23
+ return @@stored_variables[key]
24
+ else
25
+ return nil
26
+ end
27
+ end
28
+
29
+ def self.put(key, value)
30
+ restore unless @@restored
31
+ @@stored_variables[key] = value
32
+ end
33
+
34
+ def self.delete(key)
35
+ restore unless @@restored
36
+ @@stored_variables.delete(key)
37
+ end
38
+
39
+ def self.save
40
+ begin
41
+ saved_variables = File.dirname(__FILE__) + "/../var/saved_variables.yml"
42
+ File.open(saved_variables, "w") do |f|
43
+ f.write(YAML::dump(@@stored_variables))
44
+ end
45
+ rescue Exception => e
46
+ Qnotifier.log.error "Error saving stored variables file. #{e.message}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rest_client'
3
+ require 'json'
4
+ require "storage"
5
+
6
+ module Qnotifier
7
+ class WebService
8
+
9
+ attr_accessor :config
10
+
11
+ def initialize
12
+
13
+ RestClient.proxy = ENV['http_proxy']
14
+ end
15
+
16
+ def send_alerts(alerts)
17
+
18
+ return if alerts.empty?
19
+ Qnotifier.log.debug "Sending #{alerts.count} alerts"
20
+
21
+ # Hostname
22
+ unless @config["hostname"]
23
+ @hostname = `hostname`.strip
24
+ else
25
+ @hostname = @config["hostname"]
26
+ end
27
+
28
+ message = {"api_key" => @config["api_key"],
29
+ "api_version" => "1.0",
30
+ "agent_version" => Qnotifier::VERSION,
31
+ "hostname" => @hostname,
32
+ "alerts" => alerts}.to_json
33
+
34
+ begin
35
+ resource = RestClient::Resource.new(@config["api_endpoint"],
36
+ :timeout => 30,
37
+ :headers => { :user_agent => "Qnotifier-#{Qnotifier::VERSION}" })
38
+ response = resource["/send_alert"].post(message, :content_type => 'application/json')
39
+
40
+ if response.code == 200
41
+ Qnotifier.log.debug "Server Response: HTTP #{response.code} #{response.body}"
42
+ else
43
+ Qnotifier.log.warn "Server Response: HTTP #{response.code} #{response.body}"
44
+ end
45
+
46
+ rescue Exception => e
47
+ Qnotifier.log.error "Sending Alerts: Can't connect to #{@config["api_endpoint"]} - #{e.message}"
48
+ if e.message == "HTTP status code 402"
49
+ # The server doesn't want to hear from us any more, disable pinging
50
+ Qnotifier::Storage.put("server_disabled_pings", Time.now)
51
+ Qnotifier.log.error "Server has asked us to disable pings"
52
+ end
53
+ end
54
+ end
55
+
56
+ def send_reports_stats(reports, stats, alert_count)
57
+
58
+ return if reports.empty? and stats.empty?
59
+ Qnotifier.log.debug "Sending Reports and Stats"
60
+
61
+ # Hostname
62
+ unless @config["hostname"]
63
+ @hostname = `hostname`.strip
64
+ else
65
+ @hostname = @config["hostname"]
66
+ end
67
+
68
+ message = {"api_key" => @config["api_key"],
69
+ "api_version" => "1.0",
70
+ "agent_version" => Qnotifier::VERSION,
71
+ "hostname" => @hostname,
72
+ "stats" => stats,
73
+ "alert_count" => alert_count,
74
+ "reports" => reports}.to_json
75
+
76
+ begin
77
+ resource = RestClient::Resource.new(@config["api_endpoint"],
78
+ :timeout => 30,
79
+ :headers => { :user_agent => "Qnotifier-#{Qnotifier::VERSION}" })
80
+ response = resource["/update_server"].post(message, :content_type => 'application/json')
81
+
82
+ if response.code == 200
83
+ Qnotifier.log.debug "Server Response: HTTP #{response.code} #{response.body}"
84
+ else
85
+ Qnotifier.log.warn "Server Response: HTTP #{response.code} #{response.body}"
86
+ end
87
+
88
+ rescue Exception => e
89
+ Qnotifier.log.error "Sending Reports/Stats: Can't connect to #{@config["api_endpoint"]} - #{e.message}"
90
+ if e.message == "HTTP status code 402"
91
+ # The server doesn't want to hear from us any more, disable pinging
92
+ Qnotifier::Storage.put("server_disabled_pings", Time.now)
93
+ Qnotifier.log.error "Server has asked us to disable pings"
94
+ end
95
+ end
96
+ end
97
+
98
+ def register_server(temp_key)
99
+ return if temp_key.empty?
100
+ Qnotifier.log.info "Registering Server"
101
+
102
+ message = {"temp_key" => temp_key, "hostname" => `hostname`.strip}.to_json
103
+
104
+ begin
105
+ resource = RestClient::Resource.new(@config["api_endpoint"],
106
+ :timeout => 30,
107
+ :headers => { :user_agent => "Qnotifier-#{Qnotifier::VERSION}" })
108
+ response = resource["/register_server"].post(message, :content_type => 'application/json')
109
+
110
+ if response.code == 200 and response.body
111
+ Qnotifier.log.debug "Registration Request Response: HTTP #{response.code} #{response.body}"
112
+ puts "OK, the server has been successfully registered."
113
+ puts "You now need to call this script from cron every 5 minutes, add to root's crontab (sudo crontab -e):"
114
+ puts "*/5 * * * * qnotifier"
115
+ return response.body
116
+ else
117
+ Qnotifier.log.warn "Registration Request Response: HTTP #{response.code} #{response.body}"
118
+ end
119
+
120
+ rescue Exception => e
121
+ if e.message == "Bad Request"
122
+ puts "Can\'t find that key to register the server, please check it and try again. The key may have expired."
123
+ Qnotifier.log.error "Can\'t find that key to register the server, please check it and try again. The key may have expired."
124
+ else
125
+ Qnotifier.log.error "Registering Server: Can't connect to #{@config["api_endpoint"]} - #{e.message}"
126
+ end
127
+ end
128
+
129
+ return nil
130
+ end
131
+ end
132
+ end
data/plugins/apache.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Apache < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/iostat.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Iostat < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/mysql.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Mysql < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Network < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/nginx.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Nginx < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Passenger < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Processes < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/plugins/rails.rb ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ require "elif"
3
+
4
+ module Qnotifier
5
+ class Rails < Qnotifier::Plugin
6
+
7
+ def initialize
8
+ @defaults = {
9
+ :rails_log_file => "/var/www/rails/log/production.log"
10
+ }
11
+ patch_elif
12
+ end
13
+
14
+ def main
15
+ puts "here"
16
+ #log_file = read_backwards_to_timestamp(@options[:rails_log_file], last_summary)
17
+ end
18
+
19
+ def patch_elif
20
+ if Elif::VERSION < "0.2.0"
21
+ Elif.send(:define_method, :pos) do
22
+ @current_pos +
23
+ @line_buffer.inject(0) { |bytes, line| bytes + line.size }
24
+ end
25
+ end
26
+ end
27
+
28
+ def read_backwards_to_timestamp(path, timestamp)
29
+ start = nil
30
+ Elif.open(path) do |elif|
31
+ elif.each do |line|
32
+ if line =~ /\AProcessing .+ at (\d+-\d+-\d+ \d+:\d+:\d+)\)/
33
+ time_of_request = Time.parse($1)
34
+ if time_of_request < timestamp
35
+ break
36
+ else
37
+ start = elif.pos
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ file = open(path)
44
+ file.seek(start) if start
45
+ file
46
+ end
47
+ end
48
+ end
data/plugins/ruby.rb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Ruby < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ # Ruby Info
12
+ ruby_info = [RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PATCHLEVEL, RUBY_PLATFORM]
13
+ stat("Ruby", "ruby %s (%s patchlevel %s) [%s]" % ruby_info)
14
+
15
+ # Gems
16
+ gem_list = `gem list`.split("\n")
17
+ gems = []
18
+ if gem_list
19
+ for line in gem_list
20
+ next if line.match(/^[\*\n]/)
21
+ gems << line.strip
22
+ end
23
+ stat("Gems", gems.join(", "))
24
+ end
25
+ end
26
+ end
27
+ end
data/plugins/system.rb ADDED
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class System < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ "enabled" => true,
8
+ "use_load" => "five_minute",
9
+ "normalize_load" => true,
10
+ "alert_cpu_threshold" => 0,
11
+ "alert_memory_threshold" => 0,
12
+ "alert_load_threshold" => 2.0,
13
+ "alert_disk_threshold" => 0,
14
+ "partitions" => ["/"]
15
+ }
16
+ count_cpus
17
+ end
18
+
19
+ def main
20
+
21
+ # Uptime, Users and Load Average
22
+ uptime = `uptime`.strip
23
+ if uptime
24
+ if uptime =~ /load average(s*): ([\d.]+)(,*) ([\d.]+)(,*) ([\d.]+)\Z/
25
+ load_one_minute = $2.to_f
26
+ load_five_minute = $4.to_f
27
+ load_fifteen_minute = $6.to_f
28
+
29
+ if @options["normalize_load"]
30
+ load_one_minute = load_one_minute / @cpu_count
31
+ load_five_minute = load_five_minute / @cpu_count
32
+ load_fifteen_minute = load_fifteen_minute / @cpu_count
33
+ end
34
+
35
+ case @options["use_load"]
36
+ when "one_minute"
37
+ load_average = load_one_minute
38
+ when "five_minute"
39
+ load_average = load_one_minute
40
+ else
41
+ load_average = load_one_minute
42
+ end
43
+
44
+ report("Load", load_average)
45
+ stat("Load", load_average)
46
+
47
+ if @options["alert_load_threshold"] != 0 and load_average >= @options["alert_load_threshold"]
48
+ alert("load", "Load is at #{load_average} #{"(normalized)" if @options[:normalize_load]}")
49
+ else
50
+ reset_alert("load", "Load is now #{load_average}")
51
+ end
52
+
53
+ else
54
+ raise "Unable to parse load averages"
55
+ end
56
+
57
+ stat("Uptime", uptime)
58
+ end
59
+
60
+ # CPU
61
+ vmstat = `vmstat | tail -1`
62
+ if vmstat
63
+ vmstat = vmstat.split
64
+ if vmstat.size == 16
65
+
66
+ cpu = "User: #{vmstat[12].to_i}%, System: #{vmstat[13].to_i}%, Idle: #{vmstat[14].to_i}%, Wait: #{vmstat[15].to_i}%"
67
+ cpu_percent = (100 - vmstat[14].to_i)
68
+
69
+ stat("CPU", cpu)
70
+ report("CPU %", cpu_percent)
71
+
72
+ if @options["alert_cpu_threshold"] != 0 and cpu_percent >= @options["alert_cpu_threshold"]
73
+ alert("cpu", "CPU is at #{cpu_percent}%")
74
+ else
75
+ reset_alert("cpu", "CPU is now #{cpu_percent}%")
76
+ end
77
+
78
+ else
79
+ raise "Can't parse vmstat"
80
+ end
81
+ else
82
+ raise "Can't run vmstat, is it installed/supported?"
83
+ end
84
+
85
+ # Disk
86
+ df = `df -Phl`
87
+ if df
88
+ df = df.split("\n")
89
+ for partition in @options["partitions"]
90
+ for line in df
91
+ if line =~ /#{partition}$/
92
+ items = line.split
93
+
94
+ disk = "Used: #{items[-2]} (#{items[-4]}), #{items[-3]} free"
95
+ stat("Disk #{partition}", disk) if partition == "/"
96
+ report("Disk #{partition} %", items[-2].delete("%").to_i)
97
+
98
+ if @options["alert_disk_threshold"] != 0 and items[-2].delete("%").to_i >= @options["alert_disk_threshold"]
99
+ alert("partition-#{partition}", "Partition #{partition} is at #{items[-2]}")
100
+ else
101
+ reset_alert("partition-#{partition}", "Partition #{partition} is now #{items[-2]}")
102
+ end
103
+ end
104
+ end
105
+ end
106
+ else
107
+ raise "Can't run df -Phl"
108
+ end
109
+
110
+
111
+ # Uname
112
+ stat("Uname", `uname -srm`.strip)
113
+
114
+ # Memory
115
+ meminfo = {}
116
+ `cat /proc/meminfo`.each_line do |line|
117
+ _, key, value = *line.match(/^(\w+):\s+(\d+)\s/)
118
+ meminfo[key] = value.to_i
119
+ end
120
+
121
+ memory = {}
122
+ unless meminfo.empty?
123
+ memory["Free"] = meminfo['MemFree'] / 1024
124
+ memory["Total"] = meminfo['MemTotal'] / 1024
125
+ memory_percent = ((memory["Total"] - memory["Free"]) / memory["Total"] * 100).to_i
126
+ memory["Percent"] = memory_percent
127
+
128
+ stat("Memory", "Free: #{memory["Free"]}M, Total: #{memory["Total"]}M")
129
+ report("Memory %", memory_percent)
130
+
131
+ if @options["alert_memory_threshold"] != 0 and memory_percent >= @options["alert_memory_threshold"]
132
+ alert("memory", "Memory is at #{memory_percent}%")
133
+ else
134
+ reset_alert("memory", "Memory is now #{memory_percent}%")
135
+ end
136
+ else
137
+ raise "Can't get memory information from /proc/meminfo (is it supported by this OS?)"
138
+ end
139
+
140
+
141
+ end
142
+
143
+
144
+ def count_cpus
145
+ if get("cpu_count")
146
+ @cpu_count = get("cpu_count")
147
+ else
148
+ cpu_count = `cat /proc/cpuinfo | grep "model name" | wc -l`.to_i
149
+ if cpu_count != 0
150
+ @cpu_count = cpu_count
151
+ else
152
+ @cpu_count = 1
153
+ end
154
+ put("cpu_count", @cpu_count)
155
+ end
156
+ end
157
+ end
158
+ end
data/plugins/urls.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ module Qnotifier
3
+ class Urls < Qnotifier::Plugin
4
+
5
+ def initialize
6
+ @defaults = {
7
+ }
8
+ end
9
+
10
+ def main
11
+ end
12
+ end
13
+ end
data/qnotifier.gemspec ADDED
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{qnotifier}
5
+ s.version = "0.6.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Gersham Meharg"]
9
+ s.date = %q{2010-03-17}
10
+ s.default_executable = %q{qnotifier}
11
+ s.description = %q{The server side agent for the QNotifier monitoring system. This software will monitor local Linux system parameters and upload them to the Qnotifier servers where users can use iPhone/iPad applications to view those stats and recevie alerts.}
12
+ s.email = %q{gersham@qnotifier.com}
13
+ s.executables = ["qnotifier"]
14
+ s.extra_rdoc_files = ["bin/qnotifier", "lib/command.rb", "lib/plugin.rb", "lib/qnotifier.rb", "lib/storage.rb", "lib/web_service.rb"]
15
+ s.files = ["Manifest", "Rakefile", "bin/qnotifier", "config/qnotifier_config.yml", "gem-public_cert.pem", "lib/command.rb", "lib/plugin.rb", "lib/qnotifier.rb", "lib/storage.rb", "lib/web_service.rb", "plugins/apache.rb", "plugins/iostat.rb", "plugins/mysql.rb", "plugins/network.rb", "plugins/nginx.rb", "plugins/passenger.rb", "plugins/processes.rb", "plugins/rails.rb", "plugins/ruby.rb", "plugins/system.rb", "plugins/urls.rb", "qnotifier.gemspec"]
16
+ s.homepage = %q{http://qnotifier.com/qnotifier_gem}
17
+ s.post_install_message = %q{Qnotifier installed, please register by running 'qnotifier -r CODE' in order to register this server.}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Qnotifier"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{qnotifier}
21
+ s.rubygems_version = %q{1.3.5}
22
+ s.summary = %q{The server side agent for the QNotifier monitoring system}
23
+ s.signing_key = "/Users/gersham/Sources/qanix-documents/qnotifier-gem-private_key.pem"
24
+ s.cert_chain = ['gem-public_cert.pem']
25
+
26
+ if s.respond_to? :specification_version then
27
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
28
+ s.specification_version = 3
29
+
30
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
31
+ s.add_runtime_dependency(%q<rest-client>, [">= 1.4.2"])
32
+ s.add_runtime_dependency(%q<json>, [">= 1.2.3"])
33
+ s.add_runtime_dependency(%q<elif>, [">= 0.1.0"])
34
+ s.add_development_dependency(%q<rest-client>, [">= 1.4.2"])
35
+ s.add_development_dependency(%q<json>, [">= 1.2.3"])
36
+ s.add_development_dependency(%q<elif>, [">= 0.1.0"])
37
+ else
38
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
39
+ s.add_dependency(%q<json>, [">= 1.2.3"])
40
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
41
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
42
+ s.add_dependency(%q<json>, [">= 1.2.3"])
43
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
44
+ end
45
+ else
46
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
47
+ s.add_dependency(%q<json>, [">= 1.2.3"])
48
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
49
+ s.add_dependency(%q<rest-client>, [">= 1.4.2"])
50
+ s.add_dependency(%q<json>, [">= 1.2.3"])
51
+ s.add_dependency(%q<elif>, [">= 0.1.0"])
52
+ end
53
+ end
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qnotifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.2
5
+ platform: ruby
6
+ authors:
7
+ - Gersham Meharg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAdnZXJz
14
+ aGFtMRkwFwYKCZImiZPyLGQBGRYJcW5vdGlmaWVyMRMwEQYKCZImiZPyLGQBGRYD
15
+ Y29tMB4XDTEwMDMxNzE4MjAwOFoXDTExMDMxNzE4MjAwOFowQjEQMA4GA1UEAwwH
16
+ Z2Vyc2hhbTEZMBcGCgmSJomT8ixkARkWCXFub3RpZmllcjETMBEGCgmSJomT8ixk
17
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMS8vIaSE0eA
18
+ DfL3OqRwmY+b3ueQ+cfm2nxU1J+TE7yFFGiv+bk4z4YMtHtbqsGxlmL4HZKW7Ur/
19
+ RrS7+d+fVTskoRC7t9g6mRoww/4+fTgmX25g7YLe4vuiSBkBeBMXBt5Vd3ombU9F
20
+ b0CrguX2a2ffYxnF/RlrXnhsU2VywZry+qz1NJglaCa+qb0S0W3BnvoB8T+MxNOM
21
+ 7feKF/HvWRCM7DdHyqXqHFqMBIWJlCC7MFV4kQVW/a8b49VC5Dgmz6QVWcPqQ8cl
22
+ GK35UW+1WZXRB5Mhv5HBAQQqzLut46pxbUJ3qIpibtp1ltgyu81ZIRAwKIWx0YNv
23
+ lP5V85hTZ1ECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUn3O2jt+12CmU
24
+ t1GEK8NZRNRbzqwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQBb5gk8
25
+ OyfuloScbz/oHOopNmSc+o/s/5MvyrslPYDZA0WGR/63Q4Wl6l/tFFPwuAZH1KAI
26
+ MtLf7mVDdijHQf3Q6e+DicNRRQrl1w3s2m4PHyPiFUmXULzWHbMc3OK4LdM+1f5q
27
+ oZvsRrAAz6esBChxfdpuNCsP9Eu3j9MIWHy4KPTNuqOFyI+p3YVW2+SHeN4gBCyV
28
+ b7VZHIY+1kKjmMYXPeG9xlXaxLABhS1iN66tAyg66l6u6vuLt5Rdh1RUIY534Edq
29
+ ciUZJrPp/am/m0FtGWggbAohDKjiKRL0E6OCFQ7wSCTUPKoB9MbIJkKSGFo6ExWe
30
+ wu7A8rLN6CU0SfWf
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2010-03-17 00:00:00 -07:00
34
+ default_executable: qnotifier
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: rest-client
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 1.4.2
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: json
48
+ type: :runtime
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.3
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: elif
58
+ type: :runtime
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 0.1.0
65
+ version:
66
+ - !ruby/object:Gem::Dependency
67
+ name: rest-client
68
+ type: :development
69
+ version_requirement:
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.4.2
75
+ version:
76
+ - !ruby/object:Gem::Dependency
77
+ name: json
78
+ type: :development
79
+ version_requirement:
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.2.3
85
+ version:
86
+ - !ruby/object:Gem::Dependency
87
+ name: elif
88
+ type: :development
89
+ version_requirement:
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 0.1.0
95
+ version:
96
+ description: The server side agent for the QNotifier monitoring system. This software will monitor local Linux system parameters and upload them to the Qnotifier servers where users can use iPhone/iPad applications to view those stats and recevie alerts.
97
+ email: gersham@qnotifier.com
98
+ executables:
99
+ - qnotifier
100
+ extensions: []
101
+
102
+ extra_rdoc_files:
103
+ - bin/qnotifier
104
+ - lib/command.rb
105
+ - lib/plugin.rb
106
+ - lib/qnotifier.rb
107
+ - lib/storage.rb
108
+ - lib/web_service.rb
109
+ files:
110
+ - Manifest
111
+ - Rakefile
112
+ - bin/qnotifier
113
+ - config/qnotifier_config.yml
114
+ - gem-public_cert.pem
115
+ - lib/command.rb
116
+ - lib/plugin.rb
117
+ - lib/qnotifier.rb
118
+ - lib/storage.rb
119
+ - lib/web_service.rb
120
+ - plugins/apache.rb
121
+ - plugins/iostat.rb
122
+ - plugins/mysql.rb
123
+ - plugins/network.rb
124
+ - plugins/nginx.rb
125
+ - plugins/passenger.rb
126
+ - plugins/processes.rb
127
+ - plugins/rails.rb
128
+ - plugins/ruby.rb
129
+ - plugins/system.rb
130
+ - plugins/urls.rb
131
+ - qnotifier.gemspec
132
+ has_rdoc: true
133
+ homepage: http://qnotifier.com/qnotifier_gem
134
+ licenses: []
135
+
136
+ post_install_message: Qnotifier installed, please register by running 'qnotifier -r CODE' in order to register this server.
137
+ rdoc_options:
138
+ - --line-numbers
139
+ - --inline-source
140
+ - --title
141
+ - Qnotifier
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: "0"
149
+ version:
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: "1.2"
155
+ version:
156
+ requirements: []
157
+
158
+ rubyforge_project: qnotifier
159
+ rubygems_version: 1.3.5
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: The server side agent for the QNotifier monitoring system
163
+ test_files: []
164
+
metadata.gz.sig ADDED
Binary file