ubc-monitor 1.1.0
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/History.txt +16 -0
- data/Manifest.txt +16 -0
- data/PostInstall.txt +2 -0
- data/README.txt +56 -0
- data/Rakefile +28 -0
- data/bin/ubc_monitor +9 -0
- data/lib/ubc_monitor.rb +18 -0
- data/lib/ubc_monitor/cli.rb +46 -0
- data/lib/ubc_monitor/monitor.rb +77 -0
- data/lib/ubc_monitor/report.rb +128 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_helper.rb +2 -0
- data/test/test_ubc_monitor.rb +117 -0
- data/test/test_ubc_report.rb +67 -0
- metadata +94 -0
data/History.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
1.1.0 - 2008-11-07 Christian Johansen <christian@cjohansen.no>w
|
2
|
+
* Packaged project as gem
|
3
|
+
* Switched from Subversion to Git
|
4
|
+
|
5
|
+
1.0.2 - 2008-04-25 Christian Johansen <christian@cjohansen.no>
|
6
|
+
|
7
|
+
* Added Changelog to project :)
|
8
|
+
* Added a boolean updated flag to Ubc::Report
|
9
|
+
* Changed check on failcounts to make sure failcounts higher than 0, but no higher than previous
|
10
|
+
failcount still gets written back to the log file
|
11
|
+
|
12
|
+
1.0.1 - 2008-04-21 Christian Johansen <christian@cjohansen.no>
|
13
|
+
|
14
|
+
* Changed shebang to /usr/bin/env ruby
|
15
|
+
* Changed cat /proc/user_beancounters command (removed grep part which rendered it useless)
|
16
|
+
* Removed -t option for mail which didn't work under Debian
|
data/Manifest.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
PostInstall.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/ubc_monitor
|
7
|
+
lib/ubc_monitor.rb
|
8
|
+
lib/ubc_monitor/cli.rb
|
9
|
+
lib/ubc_monitor/monitor.rb
|
10
|
+
lib/ubc_monitor/report.rb
|
11
|
+
script/console
|
12
|
+
script/destroy
|
13
|
+
script/generate
|
14
|
+
test/test_helper.rb
|
15
|
+
test/test_ubc_monitor.rb
|
16
|
+
test/test_ubc_report.rb
|
data/PostInstall.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= ubc_monitor
|
2
|
+
|
3
|
+
* http://www.cjohansen.no/projects/ubc_monitor
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
ubc_monitor monitors resource usage in virtual servers run by
|
8
|
+
OpenVz.
|
9
|
+
|
10
|
+
Monitor /proc/user_beancounters and send an email to the systems
|
11
|
+
administrator if failcnt has increased since last time ubc_monitor
|
12
|
+
was run.
|
13
|
+
|
14
|
+
ubc_monitor uses a file (by default ~/.ubc_monitor) to keep track of
|
15
|
+
user_beancounter fail counts. When running without this file (such
|
16
|
+
as the first run) any fail count except 0 will be reported.
|
17
|
+
|
18
|
+
== SYNOPSIS:
|
19
|
+
|
20
|
+
ubc_monitor [options]
|
21
|
+
|
22
|
+
Options:
|
23
|
+
|
24
|
+
-f --file Log failcounts to this file, default is ~/.ubc_monitor
|
25
|
+
-n --no-log Don't log fail counts (only print results to STDOUT)
|
26
|
+
-t --email-recipient [EMAIL] The recipient of report emails. If this is not set, no email is sent
|
27
|
+
-s --email-subject [SUBJECT] Email subject. Default value is 'VPS has increased failcounts'
|
28
|
+
|
29
|
+
== INSTALL:
|
30
|
+
|
31
|
+
sudo gem install ubc_monitor
|
32
|
+
|
33
|
+
== LICENSE:
|
34
|
+
|
35
|
+
(The MIT License)
|
36
|
+
|
37
|
+
Copyright (c) 2008 Christian Johansen
|
38
|
+
|
39
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
40
|
+
a copy of this software and associated documentation files (the
|
41
|
+
'Software'), to deal in the Software without restriction, including
|
42
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
43
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
44
|
+
permit persons to whom the Software is furnished to do so, subject to
|
45
|
+
the following conditions:
|
46
|
+
|
47
|
+
The above copyright notice and this permission notice shall be
|
48
|
+
included in all copies or substantial portions of the Software.
|
49
|
+
|
50
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
51
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
52
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
53
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
54
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
55
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
56
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/ubc_monitor'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('ubc-monitor', UbcMonitor::VERSION) do |p|
|
7
|
+
p.developer('Christian Johansen', 'christian@cjohansen.no')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
10
|
+
p.rubyforge_name = p.name # TODO this is default value
|
11
|
+
# p.extra_deps = [
|
12
|
+
# ['activesupport','>= 2.0.2'],
|
13
|
+
# ]
|
14
|
+
p.extra_dev_deps = [
|
15
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
16
|
+
]
|
17
|
+
|
18
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
19
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
20
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
21
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
25
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
26
|
+
|
27
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
28
|
+
# task :default => [:spec, :features]
|
data/bin/ubc_monitor
ADDED
data/lib/ubc_monitor.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'ubc_monitor/report'
|
5
|
+
require 'ubc_monitor/monitor'
|
6
|
+
|
7
|
+
#
|
8
|
+
# Monitor /proc/user_beancounters and send an email to the systems
|
9
|
+
# administrator if failcnt has increased since last time ubc_monitor
|
10
|
+
# was run.
|
11
|
+
#
|
12
|
+
# ubc_monitor uses a file (by default ~/.ubc_monitor) to keep track of
|
13
|
+
# user_beancounter fail counts. When running without this file (such
|
14
|
+
# as the first run) any fail count except 0 will be reported.
|
15
|
+
#
|
16
|
+
module UbcMonitor
|
17
|
+
VERSION = '1.1.0'
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module UbcMonitor
|
4
|
+
#
|
5
|
+
# Run the monitor
|
6
|
+
#
|
7
|
+
class CLI
|
8
|
+
def self.execute(arguments=[])
|
9
|
+
options = { :file => File.expand_path('~/.ubc_monitor'),
|
10
|
+
:email_recipient => nil,
|
11
|
+
:email_subject => 'User beancounters has new errors' }
|
12
|
+
|
13
|
+
OptionParser.new do |opts|
|
14
|
+
opts.banner = <<-BANNER.gsub(/^ /,'')
|
15
|
+
Monitor /proc/user_beancounters and send an email to the systems
|
16
|
+
administrator if failcnt has increased since last time ubc_monitor
|
17
|
+
was run.
|
18
|
+
|
19
|
+
ubc_monitor uses a file (by default ~/.ubc_monitor) to keep track of
|
20
|
+
user_beancounter fail counts. When running without this file (such
|
21
|
+
as the first run) any fail count except 0 will be reported.
|
22
|
+
|
23
|
+
Usage: #{File.basename(__FILE__)} [options]
|
24
|
+
BANNER
|
25
|
+
opts.on("-f", "--file [FILE]", "Log failcounts to this file, default\n" +
|
26
|
+
" is #{options[:file]}") { |f| options[:file] = File.expand_path f }
|
27
|
+
opts.on("-n", "--no-log", "Don't log fail counts") { |r| options[:file] = nil }
|
28
|
+
opts.on("-t", "--email-recipient [EMAIL]", "The recipient of report emails.\n" +
|
29
|
+
" If this is not set, no email is sent") { |r| options[:email_recipient] = r }
|
30
|
+
opts.on("-s", "--email-subject [SUBJECT]", "Email subject. Default\n" +
|
31
|
+
" 'value is #{options[:email_subject]}'") { |s| options[:email_subject] = s }
|
32
|
+
end.parse!
|
33
|
+
|
34
|
+
monitor = UbcMonitor::Monitor.new(options)
|
35
|
+
report = monitor.run
|
36
|
+
|
37
|
+
if report.updated && !options[:email_recipient].nil?
|
38
|
+
`echo '"#{report.to_s}"' | mail -s "#{options[:email_subject]}" "#{options[:email_recipient]}"`
|
39
|
+
elsif report.updated
|
40
|
+
puts report.to_s
|
41
|
+
else
|
42
|
+
puts "All's swell!"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
# Namespace for the UbcMonitor script
|
5
|
+
module UbcMonitor
|
6
|
+
|
7
|
+
# The Monitor provides an interface for inspecting /proc/user_beancounters as well
|
8
|
+
# as a number of ways to report numbers that exceed given limits
|
9
|
+
class Monitor
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@options = ({ :file => nil }).merge(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Run the monitor. Uses a UbcMonitor::Report object to track runs so as to not
|
16
|
+
# report back errors that have already been reported
|
17
|
+
def run
|
18
|
+
filename = @options[:file]
|
19
|
+
|
20
|
+
# Fetch data from the previous run, this will be the baseline
|
21
|
+
report = filename.nil? ? Report.new : Report.load(filename)
|
22
|
+
|
23
|
+
# Update the report by scanning /proc/user_beancounters
|
24
|
+
report = scan(report)
|
25
|
+
|
26
|
+
# Log report back to file and return report
|
27
|
+
report.dump!(filename) unless filename.nil? || report.length == 0
|
28
|
+
|
29
|
+
report
|
30
|
+
end
|
31
|
+
|
32
|
+
# Generate the /proc/user_beancounters report by running cat on it.
|
33
|
+
# The method takes a UbcMonitor::Report object and returns a fresh report containing
|
34
|
+
# only VPS's that have increased failcounts
|
35
|
+
def scan(report = Report.new)
|
36
|
+
vps = nil
|
37
|
+
nrep = Report.new
|
38
|
+
|
39
|
+
proc_user_beancounters.split("\n").each do |line|
|
40
|
+
if line =~ /^\s+(\d+):/
|
41
|
+
vps = $1.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
# If the VPS is set, and the line (that is, the failcount) does not end with
|
45
|
+
# a 0, set the resource/failcount pair
|
46
|
+
unless vps.nil? || line =~ /\s0$/
|
47
|
+
pieces = line.gsub(/^\s*(\d+:)?\s*/, '').split(/\s+/)
|
48
|
+
resource = pieces[0].to_sym
|
49
|
+
|
50
|
+
if report[vps, resource].nil? || report[vps, resource][:failcnt].nil? ||
|
51
|
+
pieces[5].to_i > report[vps, resource][:failcnt]
|
52
|
+
nrep[vps, resource] = { :held => pieces[1].to_i, :maxheld => pieces[2].to_i,
|
53
|
+
:barrier => pieces[3].to_i, :limit => pieces[4].to_i,
|
54
|
+
:failcnt => pieces[5].to_i }
|
55
|
+
|
56
|
+
# Mark report as updated if failcount has increased
|
57
|
+
nrep.updated = true if report[vps, resource].nil? || pieces[5].to_i > report[vps, resource][:failcnt]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
nrep
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Reading /proc/user_beancounters itself is separated to allow for better testability
|
68
|
+
def proc_user_beancounters
|
69
|
+
unless File.readable? '/proc/user_beancounters'
|
70
|
+
puts "Unable to \'cat /proc/user_beancounters\'. Are you root?"
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
|
74
|
+
`cat /proc/user_beancounters`
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Namespace for the UbcMonitor script
|
2
|
+
module UbcMonitor
|
3
|
+
|
4
|
+
# The UbcMonitor::Report object holds information on the current state of failcounts in the
|
5
|
+
# /proc/user_beancounts table
|
6
|
+
#
|
7
|
+
# The Report is able to generate different views of the data it represents. It can use a
|
8
|
+
# file to log reports between uses in order to only report on failcounts that have increased
|
9
|
+
# since its last run.
|
10
|
+
#
|
11
|
+
# The log file contains sections for each VPS currently having failcounts. The VPS id introduces
|
12
|
+
# the section, followed by a newline and then resource: <failcount> pairs, one on each line.
|
13
|
+
# The VPS block is terminated by a double newline.
|
14
|
+
#
|
15
|
+
# Example file:
|
16
|
+
#
|
17
|
+
# 101
|
18
|
+
# privvmpages: 2
|
19
|
+
# kmemsize: 4
|
20
|
+
#
|
21
|
+
# 102
|
22
|
+
# privvmpages: 3
|
23
|
+
#
|
24
|
+
class Report
|
25
|
+
attr_accessor :updated
|
26
|
+
|
27
|
+
# Setup a new Report
|
28
|
+
def initialize
|
29
|
+
@resource_counts = {}
|
30
|
+
@updated = false
|
31
|
+
end
|
32
|
+
|
33
|
+
# Parse the ubc_monitor logfile and return a UbcMonitor::Report object
|
34
|
+
def self.load(file)
|
35
|
+
report = Report.new
|
36
|
+
vps = nil
|
37
|
+
|
38
|
+
return report if file.nil? || !File.exist?(file)
|
39
|
+
|
40
|
+
IO.read(file).each do |line|
|
41
|
+
if line =~ /^\s*$/
|
42
|
+
# This is a blank line separating VPS instances. Reset vps
|
43
|
+
vps = nil
|
44
|
+
elsif vps.nil?
|
45
|
+
# If the VPS has been reset, this line is expected to contain a new VPS id
|
46
|
+
vps = line.strip.to_sym
|
47
|
+
else
|
48
|
+
# Otherwise, this is a resource: <value> line belonging to the current VPS
|
49
|
+
resource, failcnt = line.split(':')
|
50
|
+
report[vps, resource.to_sym] = { :failcnt => failcnt.to_i }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return report
|
55
|
+
end
|
56
|
+
|
57
|
+
# Dump the report back to file
|
58
|
+
def dump!(file)
|
59
|
+
File.open(file, 'w+') do |f|
|
60
|
+
@resource_counts.each_pair do |vps, content|
|
61
|
+
# Each VPS in its own section, starting with the VPS id and followed by all the
|
62
|
+
# resources currently keeping a failcount, then terminated by a blank line.
|
63
|
+
# Resources whose failcounts are 0 are not dumped
|
64
|
+
str = ''
|
65
|
+
content.each_pair { |resource, numbers| str += "#{resource}: #{numbers[:failcnt]}\n" unless numbers[:failcnt] == 0 }
|
66
|
+
f.puts vps, str, '' unless str == ''
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add a resource failcount. If resource and failcnt are nil, only allocate room for
|
72
|
+
# the VPS. Returns the VPS symbol
|
73
|
+
#
|
74
|
+
# +vps+ and +resource+ are both symbols while +limits+ should be a hash (unless
|
75
|
+
# +resource+ and +limits+ are both +nil+ in which case no resource/limits pair
|
76
|
+
# is actually appended). The hash can contain the following values:
|
77
|
+
# :held, :maxheld, :barrier, :limit, :failcnt
|
78
|
+
def []=(vps, resource, limits)
|
79
|
+
@resource_counts[vps] = {} if @resource_counts[vps].nil?
|
80
|
+
@resource_counts[vps][resource] = limits
|
81
|
+
vps
|
82
|
+
end
|
83
|
+
|
84
|
+
# Fetch the ubc numbers array for a given VPS
|
85
|
+
def [](vps, resource = nil)
|
86
|
+
has_vps = @resource_counts.key? vps
|
87
|
+
has_resource = has_vps && @resource_counts[vps].key?(resource)
|
88
|
+
|
89
|
+
return resource.nil? ?
|
90
|
+
(has_vps ? @resource_counts[vps] : nil) :
|
91
|
+
(has_resource ? @resource_counts[vps][resource] : nil)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns true if no VPS's has any reported failcounts
|
95
|
+
def empty?
|
96
|
+
return length == 0
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the number of VPSs in the report
|
100
|
+
def length
|
101
|
+
return @resource_counts.length
|
102
|
+
end
|
103
|
+
|
104
|
+
# Alias of +UbcMonitor::Monitor#length+
|
105
|
+
alias size length
|
106
|
+
|
107
|
+
# Return a nicely formatted report
|
108
|
+
def to_s
|
109
|
+
str = ''
|
110
|
+
|
111
|
+
@resource_counts.dup.each do |vps, content|
|
112
|
+
str += "VPS #{vps} has increased fail counts:\n"
|
113
|
+
str += "#{'resource'.rjust(20)}#{'held'.rjust(15)}#{'maxheld'.rjust(15)}" +
|
114
|
+
"#{'barrier'.rjust(15)}#{'limit'.rjust(15)}#{'failcount'.rjust(15)}\n"
|
115
|
+
|
116
|
+
content.each_pair do |resource, report|
|
117
|
+
str += resource.to_s.rjust(20)
|
118
|
+
[:held, :maxheld, :barrier, :limit, :failcnt].each { |sym| str += report[sym].to_s.rjust(15) }
|
119
|
+
str += "\n"
|
120
|
+
end
|
121
|
+
|
122
|
+
str += "\n"
|
123
|
+
end
|
124
|
+
|
125
|
+
str
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/ubc_monitor.rb'}"
|
9
|
+
puts "Loading ubc_monitor gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
# Mock cat /proc/user_beancounters
|
4
|
+
module UbcMonitor
|
5
|
+
class Monitor
|
6
|
+
def proc_user_beancounters
|
7
|
+
<<-EOF
|
8
|
+
Version: 2.5
|
9
|
+
uid resource held maxheld barrier limit failcnt
|
10
|
+
101: kmemsize 1477444 2608200 8192000 9011200 3
|
11
|
+
lockedpages 0 0 2048 2048 4
|
12
|
+
numtcpsock 4 6 250 250 0
|
13
|
+
numflock 5 6 200 220 0
|
14
|
+
numpty 0 0 32 32 13
|
15
|
+
numsiginfo 0 2 256 256 0
|
16
|
+
tcpsndbuf 69504 90168 2682880 5242880 0
|
17
|
+
tcprcvbuf 65536 0 2682880 5242880 0
|
18
|
+
102: kmemsize 5749546 6930244 18000000 48000000 0
|
19
|
+
lockedpages 0 0 2048 2048 0
|
20
|
+
tcprcvbuf 81920 0 2682880 5242880 0
|
21
|
+
othersockbuf 4592 11200 751616 20311616 0
|
22
|
+
dgramrcvbuf 0 8440 131072 131072 345
|
23
|
+
numothersock 3 10 250 250 0
|
24
|
+
dcachesize 0 0 2097152 2158592 0
|
25
|
+
103: kmemsize 5749546 6930244 18000000 48000000 0
|
26
|
+
lockedpages 0 0 2048 2048 0
|
27
|
+
tcprcvbuf 81920 0 2682880 5242880 0
|
28
|
+
EOF
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class TestUbcMonitor < Test::Unit::TestCase
|
34
|
+
|
35
|
+
def test_init_monitor
|
36
|
+
monitor = UbcMonitor::Monitor.new
|
37
|
+
assert_not_nil monitor
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_monitor_scan
|
41
|
+
monitor = UbcMonitor::Monitor.new
|
42
|
+
report = monitor.scan
|
43
|
+
|
44
|
+
assert_equal 2, report.length
|
45
|
+
assert_equal 3, report[:'101'].length
|
46
|
+
assert_equal 1, report[:'102'].length
|
47
|
+
|
48
|
+
report[:'101', :kmemsize] = { :failcnt => 0 }
|
49
|
+
report[:'101', :numpty] = { :failcnt => 4 }
|
50
|
+
nrep = monitor.scan report
|
51
|
+
|
52
|
+
assert_equal 1, nrep.length
|
53
|
+
assert_equal 2, nrep[:'101'].length
|
54
|
+
assert_equal 13, nrep[:'101', :numpty][:failcnt]
|
55
|
+
assert_equal 3, nrep[:'101', :kmemsize][:failcnt]
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_run
|
59
|
+
monitor = UbcMonitor::Monitor.new
|
60
|
+
report = monitor.run
|
61
|
+
|
62
|
+
assert_equal 2, report.length
|
63
|
+
assert_equal 3, report[:'101'].length
|
64
|
+
assert_equal 1, report[:'102'].length
|
65
|
+
|
66
|
+
filename = '.ubc_test_file'
|
67
|
+
monitor = UbcMonitor::Monitor.new :file => filename
|
68
|
+
report = monitor.run
|
69
|
+
|
70
|
+
assert_equal 2, report.length
|
71
|
+
assert_equal 3, report[:'101'].length
|
72
|
+
assert_equal 1, report[:'102'].length
|
73
|
+
|
74
|
+
contents = <<-EOF
|
75
|
+
101
|
76
|
+
kmemsize: 3
|
77
|
+
lockedpages: 4
|
78
|
+
numpty: 13
|
79
|
+
|
80
|
+
102
|
81
|
+
dgramrcvbuf: 345
|
82
|
+
|
83
|
+
EOF
|
84
|
+
|
85
|
+
assert_equal contents.split("\n").sort, IO.read(filename).split("\n").sort
|
86
|
+
|
87
|
+
# Again, this time the report should be empty, and the file unchanged
|
88
|
+
atime = File.new(filename).atime
|
89
|
+
monitor = UbcMonitor::Monitor.new :file => filename
|
90
|
+
report = monitor.run
|
91
|
+
|
92
|
+
assert_equal 0, report.length
|
93
|
+
assert_equal atime, File.new(filename).atime
|
94
|
+
|
95
|
+
File.delete filename
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_to_s
|
99
|
+
monitor = UbcMonitor::Monitor.new
|
100
|
+
report = monitor.run
|
101
|
+
|
102
|
+
content = <<-EOF
|
103
|
+
VPS 101 has increased fail counts:
|
104
|
+
resource held maxheld barrier limit failcount
|
105
|
+
kmemsize 1477444 2608200 8192000 9011200 3
|
106
|
+
lockedpages 0 0 2048 2048 4
|
107
|
+
numpty 0 0 32 32 13
|
108
|
+
|
109
|
+
VPS 102 has increased fail counts:
|
110
|
+
resource held maxheld barrier limit failcount
|
111
|
+
dgramrcvbuf 0 8440 131072 131072 345
|
112
|
+
|
113
|
+
EOF
|
114
|
+
|
115
|
+
assert_equal content.split("\n").sort, report.to_s.split("\n").sort
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestUbcReport < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_init_report
|
6
|
+
report = UbcMonitor::Report.new
|
7
|
+
assert_not_nil report
|
8
|
+
assert report.empty?
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_append
|
12
|
+
report = UbcMonitor::Report.new
|
13
|
+
assert report.empty?
|
14
|
+
|
15
|
+
assert :'196', report[:'196', :privvmpages] = { :failcnt => 4 }
|
16
|
+
assert !report.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_getter
|
20
|
+
report = UbcMonitor::Report.new
|
21
|
+
numbers = { :failcnt => 4 }
|
22
|
+
vps = :'196'
|
23
|
+
report[vps, :privvmpages] = numbers
|
24
|
+
assert_equal numbers, report[:'196', :privvmpages]
|
25
|
+
|
26
|
+
# More complex hash
|
27
|
+
numbers = { :held => 1000, :maxheld => 1012, :barrier => 4000, :limit => 4050, :failcnt => 4 }
|
28
|
+
report[vps, :privvmpages] = numbers
|
29
|
+
assert_equal numbers, report[vps, :privvmpages]
|
30
|
+
|
31
|
+
assert !report.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_load_dump
|
35
|
+
filename = '.ubc_test_file'
|
36
|
+
contents = <<-EOF
|
37
|
+
196
|
38
|
+
privvmpages: 4
|
39
|
+
|
40
|
+
197
|
41
|
+
kmemsize: 6
|
42
|
+
privvmpages: 5
|
43
|
+
|
44
|
+
EOF
|
45
|
+
|
46
|
+
File.open(filename, 'w') { |f| f.puts contents }
|
47
|
+
|
48
|
+
report = UbcMonitor::Report.load filename
|
49
|
+
assert_equal 1, report[:'196'].length, report[:'196'].inspect
|
50
|
+
assert_equal 1, report[:'196'][:privvmpages].length
|
51
|
+
assert_equal 2, report[:'197'].length
|
52
|
+
|
53
|
+
assert_equal 4, report[:'196'][:privvmpages][:failcnt]
|
54
|
+
assert_equal 5, report[:'197'][:privvmpages][:failcnt]
|
55
|
+
assert_equal 6, report[:'197'][:kmemsize][:failcnt]
|
56
|
+
|
57
|
+
assert_equal 2, report.length
|
58
|
+
assert_equal 2, report.size
|
59
|
+
|
60
|
+
report[:'197', :kmemsize] = { :held => 1000, :maxheld => 1050, :barrier => 4000, :limit => 4000, :failcnt => 8 }
|
61
|
+
assert_equal 8, report[:'197'][:kmemsize][:failcnt]
|
62
|
+
|
63
|
+
report.dump! filename
|
64
|
+
assert_equal "197\nprivvmpages: 5\nkmemsize: 8\n\n196\nprivvmpages: 4\n\n", IO.read(filename)
|
65
|
+
File.delete filename
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ubc-monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christian Johansen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-09 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: newgem
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.6
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
35
|
+
description: ubc_monitor monitors resource usage in virtual servers run by OpenVz. Monitor /proc/user_beancounters and send an email to the systems administrator if failcnt has increased since last time ubc_monitor was run. ubc_monitor uses a file (by default ~/.ubc_monitor) to keep track of user_beancounter fail counts. When running without this file (such as the first run) any fail count except 0 will be reported.
|
36
|
+
email:
|
37
|
+
- christian@cjohansen.no
|
38
|
+
executables:
|
39
|
+
- ubc_monitor
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- PostInstall.txt
|
46
|
+
- README.txt
|
47
|
+
files:
|
48
|
+
- History.txt
|
49
|
+
- Manifest.txt
|
50
|
+
- PostInstall.txt
|
51
|
+
- README.txt
|
52
|
+
- Rakefile
|
53
|
+
- bin/ubc_monitor
|
54
|
+
- lib/ubc_monitor.rb
|
55
|
+
- lib/ubc_monitor/cli.rb
|
56
|
+
- lib/ubc_monitor/monitor.rb
|
57
|
+
- lib/ubc_monitor/report.rb
|
58
|
+
- script/console
|
59
|
+
- script/destroy
|
60
|
+
- script/generate
|
61
|
+
- test/test_helper.rb
|
62
|
+
- test/test_ubc_monitor.rb
|
63
|
+
- test/test_ubc_report.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://www.cjohansen.no/projects/ubc_monitor
|
66
|
+
post_install_message: PostInstall.txt
|
67
|
+
rdoc_options:
|
68
|
+
- --main
|
69
|
+
- README.txt
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project: ubc-monitor
|
87
|
+
rubygems_version: 1.2.0
|
88
|
+
signing_key:
|
89
|
+
specification_version: 2
|
90
|
+
summary: ubc_monitor monitors resource usage in virtual servers run by OpenVz
|
91
|
+
test_files:
|
92
|
+
- test/test_helper.rb
|
93
|
+
- test/test_ubc_monitor.rb
|
94
|
+
- test/test_ubc_report.rb
|