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 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
@@ -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: []