instrumental_tools 1.0.0.rc2 → 1.0.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.
- checksums.yaml +4 -4
- data/BUILD.md +50 -0
- data/CHANGELOG.md +5 -1
- data/CUSTOM_METRICS.md +9 -1
- data/INSTALL.md +89 -0
- data/LICENSE +1 -1
- data/README.md +23 -3
- data/Rakefile +257 -0
- data/TEST.md +9 -0
- data/bin/instrument_server +48 -7
- data/chef/.kitchen.yml +16 -0
- data/chef/Berksfile +4 -0
- data/chef/Berksfile.lock +9 -0
- data/chef/instrumental_tools/attributes/default.rb +2 -0
- data/chef/instrumental_tools/metadata.rb +3 -0
- data/chef/instrumental_tools/recipes/default.rb +21 -0
- data/chef/instrumental_tools/templates/instrumental.yml.erb +6 -0
- data/conf/instrumental.yml +6 -0
- data/debian/after-install.sh +6 -0
- data/debian/after-remove.sh +4 -0
- data/debian/before-remove.sh +4 -0
- data/debian/instrument_server +46 -0
- data/examples/mysql/mysql_status.rb +3 -3
- data/instrumental_tools.gemspec +32 -4
- data/lib/instrumental_tools/metric_script_executor.rb +38 -34
- data/lib/instrumental_tools/server_controller.rb +122 -35
- data/lib/instrumental_tools/system_inspector/linux.rb +80 -42
- data/lib/instrumental_tools/version.rb +1 -1
- data/puppet/.kitchen.yml +26 -0
- data/puppet/.librarian/puppet/config +2 -0
- data/puppet/Puppetfile +4 -0
- data/puppet/Puppetfile.lock +17 -0
- data/puppet/instrumental_tools/manifests/init.pp +29 -0
- data/puppet/instrumental_tools/metadata.json +11 -0
- data/puppet/instrumental_tools/templates/instrumental.yml.erb +6 -0
- data/puppet/manifests/site.pp +3 -0
- data/rpm/after-install.sh +7 -0
- data/rpm/after-remove.sh +4 -0
- data/rpm/before-remove.sh +5 -0
- data/rpm/instrument_server +46 -0
- data/systemd/instrument_server.service +13 -0
- data/test/integration/default/serverspec/instrumental_tools_spec.rb +29 -0
- metadata +164 -11
- data/.gitignore +0 -3
@@ -0,0 +1,21 @@
|
|
1
|
+
packagecloud_repo "expectedbehavior/instrumental" do
|
2
|
+
case node["platform_family"]
|
3
|
+
when "debian"
|
4
|
+
type "deb"
|
5
|
+
when "rhel"
|
6
|
+
type "rpm"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
package "instrumental-tools" do
|
11
|
+
action :upgrade
|
12
|
+
end
|
13
|
+
|
14
|
+
template "/etc/instrumental.yml" do
|
15
|
+
source "instrumental.yml.erb"
|
16
|
+
mode "0440"
|
17
|
+
owner "nobody"
|
18
|
+
variables(
|
19
|
+
:api_key => node[:instrumental][:api_key]
|
20
|
+
)
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
### BEGIN INIT INFO
|
3
|
+
# Provides: instrument_server
|
4
|
+
# Required-Start: $all
|
5
|
+
# Required-Stop: $all
|
6
|
+
# Default-Start: 2 3 4 5
|
7
|
+
# Default-Stop: 0 1 6
|
8
|
+
# Short-Description: Start instrument_server at boot to provide system metrics
|
9
|
+
# Description: Report system level metrics to the Instrumental service (https://instrumentalapp.com/)
|
10
|
+
### END INIT INFO
|
11
|
+
|
12
|
+
set -e
|
13
|
+
|
14
|
+
DIRECTORY="/opt/instrumental-tools/"
|
15
|
+
CONFIG_FILE="/etc/instrumental.yml"
|
16
|
+
TMPDIR=$DIRECTORY
|
17
|
+
PID="${DIRECTORY}instrument_server.pid"
|
18
|
+
LOG="${DIRECTORY}instrument_server.log"
|
19
|
+
SCRIPT_LOCATION="${DIRECTORY}.instrumental_scripts"
|
20
|
+
USER_TO_RUN_AS="nobody"
|
21
|
+
ARGS="-f ${CONFIG_FILE} -p ${PID} -l ${LOG} -s ${SCRIPT_LOCATION} -u ${USER_TO_RUN_AS} -t ${TMPDIR}"
|
22
|
+
PROCESS="${DIRECTORY}instrument_server ${ARGS}"
|
23
|
+
|
24
|
+
case "$1" in
|
25
|
+
start)
|
26
|
+
$PROCESS start
|
27
|
+
;;
|
28
|
+
stop)
|
29
|
+
$PROCESS stop
|
30
|
+
;;
|
31
|
+
restart)
|
32
|
+
$PROCESS restart
|
33
|
+
;;
|
34
|
+
status)
|
35
|
+
$PROCESS status
|
36
|
+
;;
|
37
|
+
force-reload)
|
38
|
+
$PROCESS stop && $PROCESS clean && $PROCESS start
|
39
|
+
;;
|
40
|
+
*)
|
41
|
+
echo "Usage: /etc/init.d/instrumental-tools {start|stop|restart|status}"
|
42
|
+
exit 1
|
43
|
+
;;
|
44
|
+
esac
|
45
|
+
|
46
|
+
exit 0
|
@@ -9,8 +9,8 @@ MYSQL_USER = ENV["MYSQL_USER"]
|
|
9
9
|
MYSQL_DEFAULTS_FILE = ENV["MYSQL_DEFAULTS_FILE"]
|
10
10
|
MYSQL_PASSWORD = ENV["MYSQL_PASSWORD"]
|
11
11
|
|
12
|
-
RATE_METRICS_TO_INSPECT = %w{
|
13
|
-
CANARY_METRIC = "
|
12
|
+
RATE_METRICS_TO_INSPECT = %w{queries bytes_sent bytes_received connections slow_queries}
|
13
|
+
CANARY_METRIC = "queries"
|
14
14
|
|
15
15
|
env = {}
|
16
16
|
args = []
|
@@ -61,7 +61,7 @@ if !exit_status.success?
|
|
61
61
|
else
|
62
62
|
output = stdout_r.read.lines # each line
|
63
63
|
.map { |line| line.chomp.split } # split by space characters
|
64
|
-
.map { |(name, value, _)| [name, value.to_f] } # with values coerced to floats
|
64
|
+
.map { |(name, value, _)| [name.downcase, value.to_f] } # with values coerced to floats
|
65
65
|
stats = Hash[output]
|
66
66
|
if (stats[CANARY_METRIC] < previous_values[CANARY_METRIC].to_i) || previous_values[CANARY_METRIC].nil?
|
67
67
|
# The server has restarted, don't trust previous values for calculating difference
|
data/instrumental_tools.gemspec
CHANGED
@@ -1,18 +1,37 @@
|
|
1
1
|
$: << "./lib"
|
2
|
+
require 'find'
|
2
3
|
require 'instrumental_tools/version'
|
3
4
|
|
5
|
+
gitignore = Array(File.exists?(".gitignore") ? File.read(".gitignore").split("\n") : []) + [".git", ".gitignore"]
|
6
|
+
all_files = []
|
7
|
+
|
8
|
+
Find.find(".") do |path|
|
9
|
+
scrubbed_path = path.gsub(/\A\.\//, "")
|
10
|
+
if gitignore.any? { |glob| File.fnmatch(glob, scrubbed_path) }
|
11
|
+
Find.prune
|
12
|
+
else
|
13
|
+
if !File.directory?(scrubbed_path)
|
14
|
+
all_files << scrubbed_path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test_files = all_files.select { |path| path =~ /\A(test|spec|features)\//i }
|
20
|
+
bin_files = all_files.select { |path| path.index("bin") == 0 }.map { |path| File.basename(path) }
|
21
|
+
|
4
22
|
Gem::Specification.new do |s|
|
5
23
|
s.name = "instrumental_tools"
|
6
24
|
s.version = Instrumental::Tools::VERSION
|
7
|
-
s.authors = ["
|
25
|
+
s.authors = ["Expected Behavior"]
|
8
26
|
s.email = ["support@instrumentalapp.com"]
|
9
27
|
s.homepage = "http://github.com/expectedbehavior/instrumental_tools"
|
10
28
|
s.summary = %q{Command line tools for Instrumental}
|
11
29
|
s.description = %q{A collection of scripts useful for monitoring servers and services with Instrumental (instrumentalapp.com)}
|
30
|
+
s.licenses = ["MIT"]
|
12
31
|
|
13
|
-
s.files =
|
14
|
-
s.test_files =
|
15
|
-
s.executables =
|
32
|
+
s.files = all_files
|
33
|
+
s.test_files = test_files
|
34
|
+
s.executables = bin_files
|
16
35
|
s.require_paths = ["lib"]
|
17
36
|
|
18
37
|
s.required_ruby_version = '>= 1.9'
|
@@ -20,4 +39,13 @@ Gem::Specification.new do |s|
|
|
20
39
|
s.add_runtime_dependency(%q<instrumental_agent>, [">=0.12.6"])
|
21
40
|
s.add_runtime_dependency(%q<pidly>, [">=0.1.3"])
|
22
41
|
s.add_development_dependency(%q<rake>, [">=0"])
|
42
|
+
s.add_development_dependency(%q<fpm>, [">=1.3.3"])
|
43
|
+
s.add_development_dependency(%q<package_cloud>, [">=0"])
|
44
|
+
s.add_development_dependency(%q<test-kitchen>, [">=0"])
|
45
|
+
s.add_development_dependency(%q<kitchen-vagrant>, [">=0"])
|
46
|
+
s.add_development_dependency(%q<kitchen-puppet>, [">=0"])
|
47
|
+
s.add_development_dependency(%q<berkshelf>, [">=0"])
|
48
|
+
s.add_development_dependency(%q<librarian-puppet>, [">=0"])
|
49
|
+
s.add_development_dependency(%q<puppet>, [">=0"])
|
50
|
+
s.add_development_dependency(%q<serverspec>, [">=0"])
|
23
51
|
end
|
@@ -23,51 +23,55 @@ class MetricScriptExecutor
|
|
23
23
|
file_stat.owned? && ((file_stat.mode & 0xFFF) ^ 0O700) == 0
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
full_path = File.expand_path(path)
|
31
|
-
if can_execute_file?(path)
|
32
|
-
stdin_r, stdin_w = IO.pipe
|
33
|
-
stdout_r, stdout_w = IO.pipe
|
34
|
-
stderr_r, stderr_w = IO.pipe
|
26
|
+
def execute_custom_script(full_path)
|
27
|
+
stdin_r, stdin_w = IO.pipe
|
28
|
+
stdout_r, stdout_w = IO.pipe
|
29
|
+
stderr_r, stderr_w = IO.pipe
|
35
30
|
|
36
|
-
|
31
|
+
previous_status, previous_time, previous_output = previous[full_path]
|
37
32
|
|
38
|
-
|
39
|
-
|
33
|
+
stdin_w.write(previous_output || "")
|
34
|
+
stdin_w.close
|
40
35
|
|
41
36
|
|
42
|
-
|
37
|
+
cmd = [full_path, (previous_time || 0).to_i, (previous_status && previous_status.to_i)].compact.map(&:to_s)
|
43
38
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
39
|
+
pid = Process.spawn(*cmd,
|
40
|
+
:chdir => File.dirname(full_path),
|
41
|
+
:in => stdin_r,
|
42
|
+
:out => stdout_w,
|
43
|
+
:err => stderr_w)
|
49
44
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
45
|
+
exit_status = nil
|
46
|
+
exec_time = Benchmark.realtime do
|
47
|
+
pid, exit_status = Process.wait2(pid)
|
48
|
+
end
|
54
49
|
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
if exec_time > 1.0
|
51
|
+
puts "[SLOW SCRIPT] Time to execute process #{full_path} took #{exec_time} seconds"
|
52
|
+
end
|
58
53
|
|
59
|
-
|
54
|
+
[stdin_r, stdout_w, stderr_w].each(&:close)
|
60
55
|
|
61
|
-
|
56
|
+
output = stdout_r.read.to_s.chomp
|
62
57
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
58
|
+
stderr = stderr_r.read.to_s.chomp
|
59
|
+
unless stderr.empty?
|
60
|
+
puts "[STDERR] #{full_path} (PID:#{pid}) [#{Time.now.to_s}]:: #{stderr}"
|
61
|
+
end
|
62
|
+
|
63
|
+
[stdout_r, stderr_r].each(&:close)
|
67
64
|
|
68
|
-
|
65
|
+
[full_path, [exit_status, Time.now, output]]
|
66
|
+
end
|
69
67
|
|
70
|
-
|
68
|
+
def run
|
69
|
+
process_to_output = {}
|
70
|
+
if can_execute_in_directory?(directory)
|
71
|
+
current = Dir[File.join(directory, "*")].map do |path|
|
72
|
+
full_path = File.expand_path(path)
|
73
|
+
if can_execute_file?(path)
|
74
|
+
execute_custom_script(full_path)
|
71
75
|
else
|
72
76
|
if !File.directory?(full_path)
|
73
77
|
uid = Process.uid
|
@@ -84,7 +88,7 @@ class MetricScriptExecutor
|
|
84
88
|
end
|
85
89
|
process_to_output.flat_map do |path, (status, time, output)|
|
86
90
|
if status && status.success?
|
87
|
-
prefix = File.basename(path).split(".")[0..-2].join(".").gsub(/[
|
91
|
+
prefix = File.basename(path).split(".")[0..-2].join(".").gsub(/[^\d\w\-\_\.]/i, "_")
|
88
92
|
output.lines # each line
|
89
93
|
.map { |line| line.chomp.split } # split by whitespace
|
90
94
|
.select { |data| (2..3).include?(data.size) } # and only valid name value time? pairs
|
@@ -1,11 +1,13 @@
|
|
1
|
-
require 'pidly'
|
2
1
|
require 'instrumental_tools/metric_script_executor'
|
3
2
|
require 'instrumental_tools/system_inspector'
|
3
|
+
require 'pidly'
|
4
|
+
require 'yaml'
|
4
5
|
|
5
6
|
class ServerController < Pidly::Control
|
6
7
|
COMMANDS = [:start, :stop, :status, :restart, :clean, :kill, :foreground]
|
7
8
|
|
8
9
|
attr_accessor :run_options, :pid
|
10
|
+
attr_reader :current_api_key
|
9
11
|
|
10
12
|
before_start do
|
11
13
|
extra_info = if run_options[:daemon]
|
@@ -24,49 +26,134 @@ class ServerController < Pidly::Control
|
|
24
26
|
puts 'Error encountered'
|
25
27
|
end
|
26
28
|
|
27
|
-
def
|
28
|
-
|
29
|
+
def initialize(options={})
|
30
|
+
@run_options = options.delete(:run_options) || {}
|
31
|
+
super(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def foreground
|
35
|
+
run
|
36
|
+
end
|
37
|
+
|
38
|
+
def collector_address
|
39
|
+
[run_options[:collector], run_options[:port]].compact.join(':')
|
40
|
+
end
|
41
|
+
|
42
|
+
def user_specified_api_key
|
43
|
+
run_options[:api_key]
|
44
|
+
end
|
45
|
+
|
46
|
+
def config_file_api_key
|
47
|
+
if config_file_available?
|
48
|
+
config_contents = YAML.load(File.read(run_options[:config_file]))
|
49
|
+
if config_contents.is_a?(Hash)
|
50
|
+
config_contents['api_key']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
rescue Exception => e
|
54
|
+
puts "Error loading config file %s: %s" % [run_options[:config_file], e.message]
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def configured_api_key
|
59
|
+
(user_specified_api_key || config_file_api_key).to_s.strip
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_agent(key, address, enabled)
|
63
|
+
Instrumental::Agent.new(key, collector: address, enabled: enabled)
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_new_agent(key, address)
|
67
|
+
key = key.to_s.strip
|
68
|
+
@current_api_key = key
|
69
|
+
@agent = build_agent(key, collector_address, key.size > 0)
|
70
|
+
end
|
71
|
+
|
72
|
+
def agent
|
73
|
+
if key_has_changed?
|
74
|
+
set_new_agent(configured_api_key, collector_address)
|
75
|
+
end
|
76
|
+
@agent
|
77
|
+
end
|
78
|
+
|
79
|
+
def report_interval
|
80
|
+
run_options[:report_interval]
|
81
|
+
end
|
82
|
+
|
83
|
+
def hostname
|
84
|
+
run_options[:hostname]
|
85
|
+
end
|
86
|
+
|
87
|
+
def script_location
|
88
|
+
run_options[:script_location]
|
89
|
+
end
|
90
|
+
|
91
|
+
def script_executor
|
92
|
+
@executor ||= MetricScriptExecutor.new(script_location)
|
93
|
+
end
|
94
|
+
|
95
|
+
def next_run_at(at_moment = Time.now.to_i)
|
96
|
+
(at_moment - at_moment % report_interval) + report_interval
|
97
|
+
end
|
98
|
+
|
99
|
+
def time_to_sleep
|
100
|
+
t = Time.now.to_i
|
101
|
+
[next_run_at(t) - t, 0].max
|
102
|
+
end
|
103
|
+
|
104
|
+
def config_file_available?
|
105
|
+
File.exists?(run_options[:config_file])
|
106
|
+
end
|
107
|
+
|
108
|
+
def enabled?
|
109
|
+
agent.enabled
|
110
|
+
end
|
111
|
+
|
112
|
+
def debug?
|
113
|
+
!!run_options[:debug]
|
114
|
+
end
|
115
|
+
|
116
|
+
def enable_scripts?
|
117
|
+
!!run_options[:enable_scripts]
|
118
|
+
end
|
119
|
+
|
120
|
+
def key_has_changed?
|
121
|
+
current_api_key != configured_api_key
|
122
|
+
end
|
123
|
+
|
124
|
+
def run
|
29
125
|
puts "instrument_server version #{Instrumental::Tools::VERSION} started at #{Time.now.utc}"
|
30
|
-
puts "Collecting stats under the hostname: #{
|
31
|
-
report_interval = options[:report_interval]
|
32
|
-
custom_metrics = MetricScriptExecutor.new(options[:script_location])
|
126
|
+
puts "Collecting stats under the hostname: #{hostname}"
|
33
127
|
loop do
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
if options[:debug]
|
44
|
-
puts [metric, value].join(":")
|
45
|
-
end
|
46
|
-
count += 1
|
47
|
-
end
|
48
|
-
if options[:enable_scripts]
|
49
|
-
custom_metrics.run.each do |(stat, value, time)|
|
50
|
-
metric = "#{options[:hostname]}.#{stat}"
|
51
|
-
agent.gauge(metric, value, time)
|
52
|
-
if options[:debug]
|
128
|
+
sleep time_to_sleep
|
129
|
+
if enabled?
|
130
|
+
inspector = SystemInspector.new
|
131
|
+
inspector.load_all
|
132
|
+
count = 0
|
133
|
+
inspector.gauges.each do |stat, value|
|
134
|
+
metric = [hostname, stat].join(".")
|
135
|
+
agent.gauge(metric, value)
|
136
|
+
if debug?
|
53
137
|
puts [metric, value].join(":")
|
54
138
|
end
|
55
139
|
count += 1
|
56
140
|
end
|
141
|
+
if enable_scripts?
|
142
|
+
script_executor.run.each do |(stat, value, time)|
|
143
|
+
metric = [hostname, stat].join(".")
|
144
|
+
agent.gauge(metric, value, time)
|
145
|
+
if debug?
|
146
|
+
puts [metric, value].join(":")
|
147
|
+
end
|
148
|
+
count += 1
|
149
|
+
end
|
150
|
+
end
|
151
|
+
if debug?
|
152
|
+
puts "Sent #{count} metrics"
|
153
|
+
end
|
57
154
|
end
|
58
|
-
puts "Sent #{count} metrics"
|
59
155
|
end
|
60
156
|
end
|
61
157
|
|
62
|
-
def initialize(options={})
|
63
|
-
@run_options = options.delete(:run_options) || {}
|
64
|
-
super(options)
|
65
|
-
end
|
66
|
-
|
67
|
-
def foreground
|
68
|
-
self.class.run(run_options)
|
69
|
-
end
|
70
|
-
|
71
158
|
alias_method :clean, :clean!
|
72
159
|
end
|
@@ -7,29 +7,60 @@ class SystemInspector
|
|
7
7
|
output
|
8
8
|
end
|
9
9
|
|
10
|
+
def self.cpu_file
|
11
|
+
"/proc/stat"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load_file
|
15
|
+
"/proc/loadavg"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.disk_file
|
19
|
+
"/proc/diskstats"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.mount_file
|
23
|
+
"/proc/mounts"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.open_files_file
|
27
|
+
"/proc/sys/fs/file-nr"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.memory_file
|
31
|
+
"/proc/meminfo"
|
32
|
+
end
|
33
|
+
|
10
34
|
def self.cpu
|
11
|
-
|
12
|
-
|
13
|
-
SystemInspector.memory.store(:cpu_values, values.dup)
|
14
|
-
if previous_values = SystemInspector.memory.retrieve(:cpu_values)
|
15
|
-
index = -1
|
16
|
-
values.collect! { |value| (previous_values[index += 1] - value).abs }
|
17
|
-
end
|
18
|
-
data = Hash[*categories.zip(values).flatten]
|
19
|
-
total = values.inject { |memo, value| memo + value }
|
35
|
+
agg_cpu_stat = File.read(cpu_file).lines.map { |line| line.split }.detect { |values| values.first == "cpu" }
|
36
|
+
output = {}
|
20
37
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
38
|
+
if agg_cpu_stat
|
39
|
+
categories = [:user, :nice, :system, :idle, :iowait]
|
40
|
+
values = agg_cpu_stat.slice(1, 5).map { |v| v.to_f }
|
41
|
+
SystemInspector.memory.store(:cpu_values, values.dup)
|
42
|
+
if previous_values = SystemInspector.memory.retrieve(:cpu_values)
|
43
|
+
index = -1
|
44
|
+
values.collect! { |value| (previous_values[index += 1] - value).abs }
|
25
45
|
end
|
46
|
+
|
47
|
+
data = Hash[*categories.zip(values).flatten]
|
48
|
+
total = values.inject { |memo, value| memo + value }
|
49
|
+
|
50
|
+
if previous_values
|
51
|
+
data.each do |category, value|
|
52
|
+
output["cpu.#{category}"] = value / total * 100
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
output["cpu.in_use"] = 100 - data[:idle] / total * 100
|
26
57
|
end
|
27
|
-
|
58
|
+
|
28
59
|
output
|
29
60
|
end
|
30
61
|
|
31
62
|
def self.loadavg
|
32
|
-
min_1, min_5, min_15 =
|
63
|
+
min_1, min_5, min_15 = File.read(load_file).split
|
33
64
|
{
|
34
65
|
'load.1min' => min_1.to_f,
|
35
66
|
'load.5min' => min_5.to_f,
|
@@ -39,34 +70,41 @@ class SystemInspector
|
|
39
70
|
|
40
71
|
def self.load_memory
|
41
72
|
output = { :gauges => {} }
|
42
|
-
if
|
73
|
+
if File.exists?(memory_file)
|
43
74
|
output[:gauges].merge!(memory)
|
44
75
|
end
|
45
|
-
if SystemInspector.command_present?('free', 'swap')
|
46
|
-
output[:gauges].merge!(swap)
|
47
|
-
end
|
48
76
|
output
|
49
77
|
end
|
50
78
|
|
51
79
|
def self.memory
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
80
|
+
memory_stats = Hash[File.read(memory_file).lines.map { |line| line.chomp.strip.split(/:\s+/) }.reject { |l| l.size != 2 } ]
|
81
|
+
total = memory_stats["MemTotal"].to_f
|
82
|
+
free = memory_stats["MemFree"].to_f
|
83
|
+
used = total - free
|
84
|
+
buffers = memory_stats["Buffers"].to_f
|
85
|
+
cached = memory_stats["Cached"].to_f
|
86
|
+
swaptotal = memory_stats["SwapTotal"].to_f
|
87
|
+
swapfree = memory_stats["SwapFree"].to_f
|
88
|
+
swapused = swaptotal - swapfree
|
89
|
+
|
90
|
+
stats_to_record = {
|
91
|
+
'memory.used_mb' => used / 1024,
|
92
|
+
'memory.free_mb' => free / 1024,
|
93
|
+
'memory.buffers_mb' => buffers / 1024,
|
94
|
+
'memory.cached_mb' => cached / 1024,
|
95
|
+
'memory.free_percent' => (free / total) * 100,
|
61
96
|
|
62
|
-
def self.swap
|
63
|
-
_, total, used, free = `free -k -o | grep Swap`.chomp.split
|
64
|
-
return {} if total.to_i == 0
|
65
|
-
{
|
66
|
-
'swap.used_mb' => used.to_f / 1024,
|
67
|
-
'swap.free_mb' => free.to_f / 1024,
|
68
|
-
'swap.free_percent' => (free.to_f / total.to_f) * 100
|
69
97
|
}
|
98
|
+
|
99
|
+
if swaptotal > 0
|
100
|
+
stats_to_record.merge!({
|
101
|
+
'swap.used_mb' => swapused / 1024,
|
102
|
+
'swap.free_mb' => swapfree / 1024,
|
103
|
+
'swap.free_percent' => (swapfree / swaptotal) * 100
|
104
|
+
})
|
105
|
+
end
|
106
|
+
|
107
|
+
stats_to_record
|
70
108
|
end
|
71
109
|
|
72
110
|
def self.load_disks
|
@@ -74,7 +112,7 @@ class SystemInspector
|
|
74
112
|
if SystemInspector.command_present?('df', 'disk storage')
|
75
113
|
output[:gauges].merge!(disk_storage)
|
76
114
|
end
|
77
|
-
if
|
115
|
+
if File.exists?(mount_file) && File.exists?(disk_file)
|
78
116
|
output[:gauges].merge!(disk_io)
|
79
117
|
end
|
80
118
|
output
|
@@ -104,10 +142,10 @@ class SystemInspector
|
|
104
142
|
|
105
143
|
def self.disk_io
|
106
144
|
output = {}
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
145
|
+
device_root = "/dev/"
|
146
|
+
mounted_devices = File.read(mount_file).lines.map { |l| l.split.first }.select { |device| device.index(device_root) }.map { |device| File.realpath(device) }
|
147
|
+
diskstats_lines = File.read(disk_file).lines.map(&:split).select { |values| mounted_devices.include?(File.join(device_root, values[2])) }
|
148
|
+
entries = diskstats_lines.map do |values|
|
111
149
|
entry = {}
|
112
150
|
entry[:time] = Time.now
|
113
151
|
entry[:device] = values[2]
|
@@ -127,14 +165,14 @@ class SystemInspector
|
|
127
165
|
|
128
166
|
def self.load_filesystem
|
129
167
|
output = { :gauges => {} }
|
130
|
-
if
|
168
|
+
if File.exists?(open_files_file)
|
131
169
|
output[:gauges].merge!(filesystem)
|
132
170
|
end
|
133
171
|
output
|
134
172
|
end
|
135
173
|
|
136
174
|
def self.filesystem
|
137
|
-
allocated, unused, max =
|
175
|
+
allocated, unused, max = File.read(open_files_file).split.map(&:to_i)
|
138
176
|
open_files = allocated - unused
|
139
177
|
{
|
140
178
|
'filesystem.open_files' => open_files,
|
data/puppet/.kitchen.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
driver:
|
3
|
+
name: vagrant
|
4
|
+
provider: vmware_fusion
|
5
|
+
|
6
|
+
provisioner:
|
7
|
+
name: puppet_apply
|
8
|
+
manifests_path: manifests
|
9
|
+
modules_path: modules
|
10
|
+
hiera_data_path: hieradata
|
11
|
+
|
12
|
+
platforms:
|
13
|
+
- name: nocm_ubuntu-12.04
|
14
|
+
driver_plugin: vagrant
|
15
|
+
driver_config:
|
16
|
+
box: nocm_ubuntu-12.04
|
17
|
+
box_url: https://atlas.hashicorp.com/puppetlabs/boxes/ubuntu-12.04-64-nocm/versions/1.0.1/providers/vmware_fusion.box
|
18
|
+
- name: nocm_centos-6.6
|
19
|
+
driver_plugin: vagrant
|
20
|
+
driver_config:
|
21
|
+
box: nocm_centos-6.6
|
22
|
+
box_url: https://atlas.hashicorp.com/puppetlabs/boxes/centos-6.6-64-nocm/versions/1.0.1/providers/vmware_fusion.box
|
23
|
+
|
24
|
+
suites:
|
25
|
+
- name: default
|
26
|
+
manifest: site.pp
|