newrelic_zfs 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 +7 -0
- data/bin/newrelic_zfs +60 -0
- data/lib/newrelic_zfs.rb +116 -0
- data/lib/newrelic_zfs/config.rb +70 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9fdd5091dd94e9ea8d6b2b9ac4a6f856b6a8f8b9
|
4
|
+
data.tar.gz: 4be49358deb4349c9ce20f31cecda0bf79d1e6bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4726fd516e06b68227dbcce1af4cd46c9afa61a3a6dd3f910dd5aadc5673291d587ac221d011481792230ddd7a53b5642236f2acb19b8c573b3eb01d70925b00
|
7
|
+
data.tar.gz: cd7ba440866b75b6fb57ac14a0188b6eb8b94826b9c385baa5f2be0da4b5f9d7cbf3edaea4bdb0ba79825a7c101ed7127e68779d0916ddf7aa5b9778fdc604d5
|
data/bin/newrelic_zfs
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
require 'newrelic_plugin'
|
7
|
+
require 'trollop'
|
8
|
+
|
9
|
+
require 'newrelic_zfs'
|
10
|
+
require 'newrelic_zfs/config'
|
11
|
+
|
12
|
+
module ZfsAgent
|
13
|
+
|
14
|
+
class Agent < NewRelic::Plugin::Agent::Base
|
15
|
+
|
16
|
+
agent_guid 'com.tomreay.newrelic-zfs'
|
17
|
+
agent_version '1.0.0'
|
18
|
+
agent_config_options :instance_name, :print_metrics
|
19
|
+
agent_human_labels("ZFS Agent") { instance_name }
|
20
|
+
|
21
|
+
def poll_cycle
|
22
|
+
collector = ZFSTools::Collector.new
|
23
|
+
stats = collector.collect_stats
|
24
|
+
health_total = 0
|
25
|
+
stats.each do |stat|
|
26
|
+
if stat.name == 'UnhealthyCount'
|
27
|
+
health_total = health_total + stat.value
|
28
|
+
end
|
29
|
+
|
30
|
+
stat_name = 'ZPools/' + stat.name + '/' + stat.pool_name
|
31
|
+
if print_metrics
|
32
|
+
puts 'Reporting metric named ' + stat_name + ' with value ' + stat.value.to_s + ' and unit ' + stat.unit
|
33
|
+
end
|
34
|
+
report_metric stat_name, stat.unit, stat.value
|
35
|
+
end
|
36
|
+
|
37
|
+
stat_name = 'ZPools/UnhealthyCount'
|
38
|
+
if print_metrics
|
39
|
+
puts 'Reporting metric named ' + stat_name + ' with value ' + health_total.to_s + ' and unit Value'
|
40
|
+
end
|
41
|
+
report_metric stat_name, 'Value', health_total
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
opts = Trollop::options do
|
47
|
+
opt :config_file, "Config file", :type => :string
|
48
|
+
end
|
49
|
+
|
50
|
+
config_file_path = ZfsConfig::get_config_location(ARGV[0])
|
51
|
+
if config_file_path.nil?
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
|
55
|
+
NewRelic::Plugin::Config::config_file = config_file_path
|
56
|
+
NewRelic::Plugin::Setup.install_agent :zfs, ZfsAgent
|
57
|
+
NewRelic::Plugin::Run.setup_and_run
|
58
|
+
|
59
|
+
puts 'Newrelic ZFS Agent started'
|
60
|
+
end
|
data/lib/newrelic_zfs.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module ZFSTools
|
2
|
+
class Stat
|
3
|
+
attr_reader :pool_name
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :unit
|
6
|
+
attr_reader :value
|
7
|
+
|
8
|
+
def initialize(pool_name, name, unit, value)
|
9
|
+
@pool_name = pool_name
|
10
|
+
@name = name
|
11
|
+
@unit = unit
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Pool
|
17
|
+
BLACK_LIST = ['Altroot']
|
18
|
+
|
19
|
+
attr_accessor :name
|
20
|
+
attr_reader :values
|
21
|
+
|
22
|
+
def initialize()
|
23
|
+
@values = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_value(heading, value)
|
27
|
+
if !BLACK_LIST.include?(heading)
|
28
|
+
@values.merge!({ heading => value })
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Converter
|
34
|
+
UNITS = { 'B' => 'bytes', 'K' => 'kilobytes', 'M' => 'megabytes', 'G' => 'gigabytes', 'T' => 'terabytes', 'P' => 'petabytes'}
|
35
|
+
HEADINGS = { 'Health' => 'UnhealthyCount' }
|
36
|
+
|
37
|
+
def convert(heading, value)
|
38
|
+
values = _split(value)
|
39
|
+
return [ _convert(heading, HEADINGS), _convert_d(values[1], UNITS, 'Value'), values[0] ]
|
40
|
+
end
|
41
|
+
|
42
|
+
def _split(value)
|
43
|
+
match = /\d+\.?\d*/.match(value)
|
44
|
+
#If numeric value
|
45
|
+
if match
|
46
|
+
numeric_part = match[0]
|
47
|
+
unit = value.slice(numeric_part.length, value.length)
|
48
|
+
return [numeric_part, unit]
|
49
|
+
elsif value == 'ONLINE'
|
50
|
+
return [0, '']
|
51
|
+
else
|
52
|
+
return [1, '']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def _convert_d(value, hash, default)
|
57
|
+
converted = _convert(value, hash)
|
58
|
+
|
59
|
+
if converted.nil?
|
60
|
+
converted = default
|
61
|
+
end
|
62
|
+
|
63
|
+
return converted
|
64
|
+
end
|
65
|
+
|
66
|
+
def _convert(value, hash)
|
67
|
+
converted = hash[value]
|
68
|
+
|
69
|
+
#If the converted value is null, use the original unit
|
70
|
+
if converted.nil?
|
71
|
+
converted = value
|
72
|
+
end
|
73
|
+
|
74
|
+
return converted
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Collector
|
79
|
+
CONVERTER = Converter.new
|
80
|
+
|
81
|
+
def collect_stats()
|
82
|
+
first = true
|
83
|
+
headings = {}
|
84
|
+
pools = []
|
85
|
+
|
86
|
+
`zpool list`.each_line do |line|
|
87
|
+
#File.open('/Users/tomreay/Documents/workspaceWebApps/newrelic-zfs/list.txt').each_line do |line|
|
88
|
+
pool = Pool.new
|
89
|
+
line.split(' ').each_with_index do |token, index|
|
90
|
+
if first
|
91
|
+
headings.merge!({ index => token.capitalize})
|
92
|
+
else
|
93
|
+
if headings[index] == 'Name'
|
94
|
+
pool.name = token
|
95
|
+
else
|
96
|
+
pool.add_value(headings[index], token)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
first = false
|
101
|
+
pools << pool
|
102
|
+
end
|
103
|
+
|
104
|
+
stats = []
|
105
|
+
pools.each do |pool|
|
106
|
+
pool.values.each do |heading, value|
|
107
|
+
converted = CONVERTER.convert(heading, value)
|
108
|
+
stat = Stat.new(pool.name, converted[0], converted[1], converted[2])
|
109
|
+
stats << stat
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
return stats
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ZfsConfig
|
2
|
+
def self.get_config_location(config_file_location)
|
3
|
+
if config_file_location.nil?
|
4
|
+
print "No config file argument given, if you have already generated a config file please rerun using:\n" +
|
5
|
+
"\n" +
|
6
|
+
"newrelic_zfs full/path/to/file \n"+
|
7
|
+
"\n" +
|
8
|
+
'Or, create a config file now? [y/n]: '
|
9
|
+
if user_says_yes?
|
10
|
+
print 'Where should the file be created? '
|
11
|
+
file_path = get_user_input
|
12
|
+
create_config(File.join(file_path, 'config.yml'))
|
13
|
+
|
14
|
+
config_file_location = get_file_path(file_path)
|
15
|
+
end
|
16
|
+
elsif !File.exist?(config_file_location)
|
17
|
+
print 'The specified config file does not exist, do you want to create it now? [y/n]: '
|
18
|
+
if user_says_yes?
|
19
|
+
create_config(config_file_location)
|
20
|
+
else
|
21
|
+
config_file_location = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
return config_file_location
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.create_config(config_file_name)
|
29
|
+
puts "Writing file #{config_file_name}"
|
30
|
+
print 'Please enter your API key: '
|
31
|
+
api_key = get_user_input
|
32
|
+
raise 'API Key must be non-empty' unless !api_key.nil? && !api_key.empty?
|
33
|
+
|
34
|
+
print 'Please enter a name for this server: '
|
35
|
+
server_name = get_user_input
|
36
|
+
raise 'Server name must be non-empty' unless !server_name.nil? && !server_name.empty?
|
37
|
+
|
38
|
+
File.open(config_file_name, 'w') do |f|
|
39
|
+
f.write ERB.new(
|
40
|
+
"newrelic: \n" +
|
41
|
+
" license_key: '<%= api_key %>' \n" +
|
42
|
+
"agents:\n" +
|
43
|
+
" zfs:\n" +
|
44
|
+
" instance_name: '<%= server_name %>'\n" +
|
45
|
+
" print_metrics: false").result(binding)
|
46
|
+
end
|
47
|
+
puts 'Config file written, starting newrelic_zfs agent'
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.get_file_path(file_path)
|
51
|
+
if File.directory?(file_path)
|
52
|
+
file_path = File.join(file_path, 'config.yml')
|
53
|
+
end
|
54
|
+
|
55
|
+
if File.extname(file_path).empty?
|
56
|
+
file_path = file_path + '.yml'
|
57
|
+
end
|
58
|
+
|
59
|
+
return file_path
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.user_says_yes?()
|
63
|
+
return get_user_input == 'y'
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.get_user_input()
|
67
|
+
return $stdin.gets.chomp
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: newrelic_zfs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Reay
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: newrelic_plugin
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: trollop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
description: Newrelic plugin to monitor ZFS pools
|
56
|
+
email: dev@tomreay.co.uk
|
57
|
+
executables:
|
58
|
+
- newrelic_zfs
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- bin/newrelic_zfs
|
63
|
+
- lib/newrelic_zfs.rb
|
64
|
+
- lib/newrelic_zfs/config.rb
|
65
|
+
homepage: http://rubygems.org/gems/newrelic-zfs
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.2.1
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: Newrelic ZFS
|
89
|
+
test_files: []
|