newrelic_zfs 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|