newrelic_f5_plugin 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,35 @@
1
+ * 1.0.0
2
+ - Updated version for release!
3
+
4
+ * 0.0.8
5
+ - Updated to require newrelic_platform.gem > 0.2.10
6
+ - Added a total throughput metric
7
+
8
+ * 0.0.7
9
+ - Initial reporting of Nodes (Monitor Status)
10
+ - Include a Total throughput summary metric
11
+
12
+ * 0.0.6
13
+ - Change the GUID to match the standard naming scheme
14
+ - Added a summary metric for CPU usage
15
+ - Added summary metrics for SSL
16
+ - Added HTTP Compression metrics
17
+
18
+ * 0.0.5
19
+ - Changed bytes to bits on throughput metrics
20
+
21
+ * 0.0.4
22
+ - Added SSL metric collection
23
+ - Changed CPU to be a percentage of 100 by asking how many CPUs the device has
24
+
25
+ * 0.0.3
26
+ - Added more HTTP metrics
27
+ - Added default port so you don't have to specify it in the yaml
28
+ - Refactored much of the agent implementation to make if more modular
29
+
30
+ * 0.0.2
31
+ - Added Global CPU Metrics
32
+
33
+ * 0.0.1
34
+ - In Dev
35
+
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # This gemfile is used in the context of development on this plugin agent.
4
+
5
+ gem 'newrelic_plugin', :git => 'git@github.com:newrelic-platform/newrelic_plugin.git', :branch => 'release'
6
+ gem "snmp"
7
+ gem "rake", ">0.9.2"
8
+ gem 'test-unit'
9
+ gem "shoulda"
10
+ gem "mocha"
11
+ gem "rdoc", ">2.4.2"
12
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013 New Relic, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
data/NOTES ADDED
@@ -0,0 +1,30 @@
1
+ F5 MIB Tree Overview
2
+ -----------------------------------
3
+ 1.3.6.1.4.1 Enterprises
4
+ +-3375 F5
5
+ +-2 bigipTrafficMgmt
6
+ +-1 bigipSystem
7
+ +-1 sysGlobals
8
+ | +-2 sysGlobalStats
9
+ | | +-1 sysGlobalStat
10
+ | | | +-38 sysStatCpuCount
11
+ | | +-4 sysGlobalHttpStat
12
+ | | +-12 sysGlobalTcpStat
13
+ | | +-20 sysGlobalHost
14
+ | | | +-4 sysGlobalHostCpuCount
15
+ | | +-22 sysGlobalHttpCompressionStat
16
+ | | +-2 sysHttpCompressionStatPrecompressBytes
17
+ | 2 sysNetwork
18
+ | +-4 sysInterfaces
19
+ | 3 sysPlatform
20
+ | +-2 sysChassis
21
+ | +-6 sysSystem
22
+ | 4 sysProduct
23
+ 2 bigipLocalTM
24
+ +-1 ltmGlobals
25
+ +-4 ltmNodes
26
+ +-5 ltmPools
27
+ +-6 ltmProfiles
28
+ +-8 ltmRules
29
+ +-10 ltmVirtualServers
30
+
data/README.rdoc ADDED
@@ -0,0 +1,53 @@
1
+ = New Relic F5 Plugin
2
+
3
+ The New Relic F5 Plugin enables integrated monitoring of your F5 Local Traffic
4
+ Manager devices inside of New Relic. Currently the following metrics are recorded:
5
+
6
+ Device wide Metrics
7
+ * CPU / Memory usage
8
+ * Throughput (Total, Client side, Server side)
9
+ * HTTP Requests (Requests/second, HTTP Methods, Status Codes, Versions)
10
+ * HTTP Compression (Pre/Post broken down by content type)
11
+ * SSL Requests/second
12
+ * TCP Details (Current connections, connection rate, Server/Client side, Wait State)
13
+ * Node status
14
+
15
+
16
+ == Requirements
17
+
18
+ === Proxy host
19
+
20
+ You need a host to install the plugin on that is able to poll the desired F5s via SNMP. That
21
+ host also needs Ruby (tested with 1.8.7 and 1.9.3), and support for rubygems.
22
+
23
+
24
+ === F5
25
+
26
+ This plugin has been tested with F5 LTM versions 11.2.x and 11.3.x. Some metrics are reported on
27
+ 10.2.x, but the data is incomplete due to SNMP changes made by F5 between 10 and 11.
28
+
29
+ A *read-only* SNMP community is required for each device to be monitored. Currently, only
30
+ SNMP verison 2c is supported.
31
+
32
+
33
+ == Instructions for running the F5 plugin agent
34
+
35
+ 1. Install the +newrelic_plugin+ gem.
36
+ 2. Install this gem.
37
+ 3. Create an installation directory (like /opt/newrelic/f5 ).
38
+ 4. In the installation directory, execute
39
+
40
+ f5_monitor install -l LICENSE_KEY
41
+
42
+ using the license key from your New Relic account.
43
+ 5. Edit the +config/newrelic_plugin.yml+ file generated in step 4. Setup name/hostname/port/snmp_community for each F5 you wish to monitor.
44
+ 6. Execute
45
+
46
+ f5_monitor run
47
+
48
+ == Developer Instructions
49
+
50
+ 1. Fork/Clone the repository
51
+ 2. Install bundler and do +bundle install+
52
+ 3. Do <b><tt>rake -T</tt></b> to see rake options, including tests.
53
+
data/Rakefile ADDED
@@ -0,0 +1,155 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ # https://raw.github.com/mojombo/rakegem
6
+
7
+ #############################################################################
8
+ #
9
+ # Helper functions
10
+ #
11
+ #############################################################################
12
+
13
+ def name
14
+ @name ||= Dir['*.gemspec'].first.split('.').first
15
+ end
16
+
17
+ def version
18
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
19
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
20
+ end
21
+
22
+ def date
23
+ Date.today.to_s
24
+ end
25
+
26
+ def rubyforge_project
27
+ name
28
+ end
29
+
30
+ def gemspec_file
31
+ "#{name}.gemspec"
32
+ end
33
+
34
+ def gem_file
35
+ "#{name}-#{version}.gem"
36
+ end
37
+
38
+ def replace_header(head, header_name)
39
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
40
+ end
41
+
42
+ #############################################################################
43
+ #
44
+ # Standard tasks
45
+ #
46
+ #############################################################################
47
+
48
+ task :default => :test
49
+
50
+ require 'rake/testtask'
51
+ Rake::TestTask.new(:test) do |test|
52
+ test.libs << 'lib' << 'test'
53
+ test.pattern = 'test/**/*_test.rb'
54
+ test.verbose = true
55
+ end
56
+
57
+ desc "Generate RCov test coverage and open in your browser"
58
+ task :coverage do
59
+ require 'rcov'
60
+ sh "rm -fr coverage"
61
+ sh "rcov test/test_*.rb"
62
+ sh "open coverage/index.html"
63
+ end
64
+
65
+ require 'rdoc/task'
66
+ Rake::RDocTask.new do |rdoc|
67
+ rdoc.rdoc_dir = 'rdoc'
68
+ rdoc.title = "#{name} #{version}"
69
+ rdoc.rdoc_files.include('lib/**/*.rb')
70
+ rdoc.rdoc_files.include('README.rdoc')
71
+ rdoc.rdoc_files.include('LICENSE')
72
+ rdoc.rdoc_files.include('CHANGES')
73
+ rdoc.main = "README.rdoc"
74
+ end
75
+
76
+ desc "Open an irb session preloaded with this library"
77
+ task :console do
78
+ sh "irb -rubygems -I./lib -r ./lib/#{name}.rb"
79
+ end
80
+
81
+ #############################################################################
82
+ #
83
+ # Custom tasks (add your own tasks here)
84
+ #
85
+ #############################################################################
86
+
87
+
88
+
89
+ #############################################################################
90
+ #
91
+ # Packaging tasks
92
+ #
93
+ #############################################################################
94
+
95
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubgems"
96
+ task :release => :build do
97
+ unless `git branch` =~ /^\* master$/
98
+ puts "You must be on the master branch to release!"
99
+ exit!
100
+ end
101
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
102
+ sh "git tag v#{version}"
103
+ sh "git push origin master"
104
+ sh "git push origin v#{version}"
105
+ sh "gem push pkg/#{name}-#{version}.gem"
106
+ end
107
+
108
+ desc "Build #{gem_file} into the pkg directory"
109
+ task :build => :gemspec do
110
+ sh "mkdir -p pkg"
111
+ sh "gem build #{gemspec_file}"
112
+ sh "mv #{gem_file} pkg"
113
+ end
114
+
115
+ desc "Generate #{gemspec_file}"
116
+ task :gemspec => :validate do
117
+ # read spec file and split out manifest section
118
+ spec = File.read(gemspec_file)
119
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
120
+
121
+ # replace name version and date
122
+ replace_header(head, :name)
123
+ replace_header(head, :version)
124
+ replace_header(head, :date)
125
+ #comment this out if your rubyforge_project has a different name
126
+ replace_header(head, :rubyforge_project)
127
+
128
+ # determine file list from git ls-files
129
+ files = `git ls-files`.
130
+ split("\n").
131
+ sort.
132
+ reject { |file| file =~ /^\./ }.
133
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
134
+ map { |file| " #{file}" }.
135
+ join("\n")
136
+
137
+ # piece file back together and write
138
+ manifest = " s.files = %w[\n#{files}\n ]\n"
139
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
140
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
141
+ puts "Updated #{gemspec_file}"
142
+ end
143
+
144
+ desc "Validate #{gemspec_file}"
145
+ task :validate do
146
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
147
+ unless libfiles.empty?
148
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
149
+ exit!
150
+ end
151
+ unless Dir['VERSION*'].empty?
152
+ puts "A `VERSION` file at root level violates Gem best practices."
153
+ exit!
154
+ end
155
+ end
data/bin/f5_monitor ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path "../../lib", __FILE__
3
+ require "newrelic_f5_plugin"
4
+ require 'optparse'
5
+
6
+ options = OptionParser.new do |opts|
7
+ opts.banner = <<-EOF
8
+ Usage:
9
+ f5_monitor ( run | install ) [options]
10
+ EOF
11
+
12
+ opts.on("-v", "--verbose", "Run verbosely") do
13
+ NewRelic::Plugin::Config.config.newrelic['verbose'] = 1
14
+ end
15
+
16
+ opts.on("-l", "--license LICENSE_KEY", "Your NewRelic account License Key") do | license_key |
17
+ $license_key = license_key
18
+ end
19
+
20
+ opts.on("-c", "--config FILE", "Override the location of the newrelic_plugin.yml") do | filename |
21
+ if !File.exists? filename
22
+ puts "File not found: #{filename.inspect}"
23
+ exit 1
24
+ end
25
+ NewRelic::Plugin::Config.config_file = filename
26
+ end
27
+
28
+ opts.on("-h", "--help") do
29
+ puts opts
30
+ if File.basename($0) == File.basename(__FILE__)
31
+ exit 0
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ args = options.parse!(ARGV)
38
+
39
+ if args.first == "run"
40
+ if $license_key
41
+ NewRelic::Plugin::Config.config.options['newrelic']['license_key'] = $license_key
42
+ end
43
+ NewRelic::F5Plugin.run
44
+ elsif args.first == "install"
45
+ config_file = File.read(File.expand_path("../../config/newrelic_plugin.yml", __FILE__))
46
+ if $license_key
47
+ config_file.gsub!("YOUR_LICENSE_KEY_HERE", $license_key)
48
+ end
49
+ require 'fileutils'
50
+ FileUtils.mkdir_p "config"
51
+ File.open("config/newrelic_plugin.yml", "w") do | io |
52
+ io.write(config_file)
53
+ end
54
+ puts "Saved agent config file #{File.expand_path("config/newrelic_plugin.yml")}"
55
+ else
56
+ puts options
57
+ end
58
+
@@ -0,0 +1,38 @@
1
+ #
2
+ #
3
+ # This is a sample newrelic_plugin.yml file. Please move this file
4
+ # to the following location if it is not already there:
5
+ #
6
+ # ./config/newrelic_plugin.yml
7
+ #
8
+ # Where the current directory is the directory where your main program resides and is your current
9
+ # directory when you run the main program.
10
+ #
11
+ # Please make sure to update the license_key information with the license key for your New Relic
12
+ # account.
13
+ #
14
+ #
15
+ newrelic:
16
+ #
17
+ # Update with your New Relic account license key:
18
+ #
19
+ license_key: 'YOUR_LICENSE_KEY_HERE'
20
+ #
21
+ # Set to '1' for verbose output, remove for normal output.
22
+ # All output goes to stdout/stderr.
23
+ #
24
+ #verbose: 1
25
+
26
+
27
+ #
28
+ # Agent Configuration:
29
+ #
30
+ agents:
31
+ f5:
32
+ # Define one or more instances
33
+ -
34
+ name: 'My F5'
35
+ hostname: 'my-f5'
36
+ port: 161
37
+ snmp_community: 'public'
38
+
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'newrelic_f5_plugin/nodes'
3
+ require 'newrelic_f5_plugin/agent'
4
+
5
+ module NewRelic::F5Plugin
6
+ VERSION = '1.0.0'
7
+ end
8
+
@@ -0,0 +1,381 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'newrelic_plugin'
6
+ require 'snmp'
7
+
8
+
9
+ module NewRelic::F5Plugin
10
+
11
+ # Register and run the agent
12
+ def self.run
13
+ # Register this agent.
14
+ NewRelic::Plugin::Setup.install_agent :f5, self
15
+
16
+ # Launch the agent; this never returns.
17
+ NewRelic::Plugin::Run.setup_and_run
18
+ end
19
+
20
+
21
+ # Part of me wants to split this out into different devices using this OID:
22
+ # 1.3.6.1.4.1.3375.2.1.3.5.2.0 = STRING: "BIG-IP 3900" or
23
+ # 1.3.6.1.4.1.3375.2.1.3.5.1.0 = STRING: "C106"
24
+ # Especially since a 3900, 6900, Viprion won't respond exactly the same.
25
+ # To make it worse, versions of BIG-IP older than 11.2 might not implent all
26
+ # all of these OIDs.
27
+ # Version: 1.3.6.1.4.1.3375.2.1.4.2.0
28
+ # Build: 1.3.6.1.4.1.3375.2.1.4.3.0
29
+ class Agent < NewRelic::Plugin::Agent::Base
30
+ agent_guid 'com.newrelic.f5'
31
+ agent_version '1.0.0'
32
+ agent_config_options :hostname, :port, :snmp_community
33
+ agent_human_labels('F5') { "#{hostname}" }
34
+
35
+ #
36
+ # Required, but not used
37
+ #
38
+ def setup_metrics
39
+ end
40
+
41
+
42
+ #
43
+ # This is called on every polling cycle
44
+ #
45
+ def poll_cycle
46
+ # SNMP Stuff here
47
+ snmp = SNMP::Manager.new(:host => hostname, :port => port, :community => snmp_community)
48
+
49
+ report_global_cpu_metrics(snmp)
50
+ report_global_memory_metrics(snmp)
51
+ report_global_connection_metrics(snmp)
52
+ report_global_throughput_metrics(snmp)
53
+ report_global_http_metrics(snmp)
54
+ report_global_http_compression_metrics(snmp)
55
+ report_global_ssl_metrics(snmp)
56
+ report_global_tcp_metrics(snmp)
57
+
58
+ node_status = NewRelic::F5Plugin::Nodes.get_status(snmp)
59
+ node_status.each_key { |m|
60
+ report_metric m, node_status[m][:label], node_status[m][:count]
61
+ }
62
+
63
+ snmp.close
64
+ rescue => e
65
+ $stderr.puts "#{e}: #{e.backtrace.join("\n ")}"
66
+ end
67
+
68
+
69
+ #
70
+ # You do not have to specify the SNMP port in the yaml if you don't want to.
71
+ #
72
+ def port
73
+ @port || 161
74
+ end
75
+
76
+
77
+ #
78
+ # Helper function to create and keep track of all the counters
79
+ #
80
+ def report_counter_metric(metric, type, value)
81
+ @processors ||= {}
82
+
83
+ if @processors[metric].nil?
84
+ @processors[metric] = NewRelic::Processor::EpochCounter.new
85
+ end
86
+
87
+ report_metric metric, type, @processors[metric].process(value)
88
+ end
89
+
90
+
91
+ #
92
+ # Gather CPU Related metrics and report them
93
+ #
94
+ def report_global_cpu_metrics(snmp)
95
+ # Create the OIDs if they do not exist
96
+ @oid_sysGlobalHostCpuUser1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.22.0")
97
+ @oid_sysGlobalHostCpuNice1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.23.0")
98
+ @oid_sysGlobalHostCpuSystem1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.24.0")
99
+ #@oid_sysGlobalHostCpuIdle1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.25.0") # Ignoring the idle time
100
+ @oid_sysGlobalHostCpuIrq1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.26.0")
101
+ @oid_sysGlobalHostCpuSoftirq1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.27.0")
102
+ @oid_sysGlobalHostCpuIowait1m ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.28.0")
103
+ @oid_sysGlobalHostCpuCount ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.20.4.0")
104
+
105
+ if snmp
106
+ res = snmp.get_value([@oid_sysGlobalHostCpuCount, @oid_sysGlobalHostCpuUser1m, @oid_sysGlobalHostCpuNice1m,
107
+ @oid_sysGlobalHostCpuSystem1m, @oid_sysGlobalHostCpuIrq1m, @oid_sysGlobalHostCpuSoftirq1m,
108
+ @oid_sysGlobalHostCpuIowait1m, ])
109
+
110
+ # In order to show the CPU usage as a total percentage, we divide by the number of cpus
111
+ cpu_count = res[0].to_i
112
+ vals = res[1..6].map { |i| i.to_f / cpu_count }
113
+ report_metric "CPU/Global/User", "%", vals[0]
114
+ report_metric "CPU/Global/Nice", "%", vals[1]
115
+ report_metric "CPU/Global/System", "%", vals[2]
116
+ report_metric "CPU/Global/IRQ", "%", vals[3]
117
+ report_metric "CPU/Global/Soft IRQ", "%", vals[4]
118
+ report_metric "CPU/Global/IO Wait", "%", vals[5]
119
+
120
+ # Add it all up, and send a summary metric
121
+ report_metric "CPU/Total/Global", "%", vals.inject(0.0){ |a,b| a + b }
122
+ end
123
+ end
124
+
125
+
126
+ #
127
+ # Gather Memory related metrics and report them
128
+ #
129
+ def report_global_memory_metrics(snmp)
130
+ # Create the OIDs if they don't exist
131
+ @oid_sysStatMemoryUsed ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.45.0")
132
+ @oid_sysHostMemoryUsed ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.7.1.2.0")
133
+
134
+ if snmp
135
+ res = snmp.get_value([@oid_sysStatMemoryUsed, @oid_sysHostMemoryUsed])
136
+ report_metric "Memory/TMM", "bytes", res[0]
137
+ report_metric "Memory/Host", "bytes", res[1]
138
+ end
139
+ end
140
+
141
+
142
+ #
143
+ # Gather Global connection related metrics and report them
144
+ #
145
+ def report_global_connection_metrics(snmp)
146
+ # Create the OIDs if they don't exist
147
+ @oid_sysStatClientCurConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.8.0")
148
+ @oid_sysStatServerCurConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.15.0")
149
+ @oid_sysStatClientTotConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.7.0")
150
+ @oid_sysStatServerTotConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.14.0")
151
+ #@oid_sysStatPvaClientCurConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.22.0")
152
+ #@oid_sysStatPvaServerCurConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.29.0")
153
+ # These should be moved to an SSL metric...
154
+ @oid_sysClientsslStatCurConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.9.2.0")
155
+ @oid_sysServersslStatCurConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.10.2.0")
156
+
157
+ if snmp
158
+ res = snmp.get_value([@oid_sysStatClientCurConns, @oid_sysStatServerCurConns, @oid_sysStatClientTotConns,
159
+ @oid_sysStatServerTotConns, @oid_sysClientsslStatCurConns, @oid_sysServersslStatCurConns])
160
+ report_metric "Connections/Current/Client", "conn", res[0]
161
+ report_metric "Connections/Current/Server", "conn", res[1]
162
+ report_counter_metric "Connections/Rate/Client", "conn/sec", res[2]
163
+ report_counter_metric "Connections/Rate/Server", "conn/sec", res[3]
164
+ report_metric "Connections/Current/Client SSL", "conn", res[4]
165
+ report_metric "Connections/Current/Server SSL", "conn", res[5]
166
+ end
167
+ end
168
+
169
+
170
+ #
171
+ # Gather Global throughput related metrics and report them
172
+ #
173
+ def report_global_throughput_metrics(snmp)
174
+ # Create the OIDs if they don't exist
175
+ @oid_sysStatClientBytesIn ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.3.0")
176
+ @oid_sysStatClientBytesOut ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.5.0")
177
+ @oid_sysStatServerBytesIn ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.10.0")
178
+ @oid_sysStatServerBytesOut ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.1.12.0")
179
+
180
+ if snmp
181
+ res = snmp.get_value([@oid_sysStatClientBytesIn, @oid_sysStatClientBytesOut, @oid_sysStatServerBytesIn,
182
+ @oid_sysStatServerBytesOut])
183
+
184
+ report_counter_metric "Throughput/Client/In", "bits/sec", (res[0].to_f * 8)
185
+ report_counter_metric "Throughput/Client/Out", "bits/sec", (res[1].to_f * 8)
186
+ report_counter_metric "Throughput/Server/In", "bits/sec", (res[2].to_f * 8)
187
+ report_counter_metric "Throughput/Server/Out", "bits/sec", (res[3].to_f * 8)
188
+ tot = 0
189
+ res.each { |x| tot += x.to_f }
190
+ report_counter_metric "Throughput/Total", "bits/sec", (tot * 8)
191
+ end
192
+ end
193
+
194
+
195
+ #
196
+ # Gather Global HTTP related metrics and report them
197
+ #
198
+ def report_global_http_metrics(snmp)
199
+ # Create the OIDs if they don't exist
200
+ @oid_sysHttpStatResp2xxCnt ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.3.0")
201
+ @oid_sysHttpStatResp3xxCnt ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.4.0")
202
+ @oid_sysHttpStatResp4xxCnt ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.5.0")
203
+ @oid_sysHttpStatResp5xxCnt ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.6.0")
204
+ @oid_sysHttpStatNumberReqs ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.7.0")
205
+ @oid_sysHttpStatGetReqs ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.8.0")
206
+ @oid_sysHttpStatPostReqs ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.9.0")
207
+ @oid_sysHttpStatV9Reqs ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.10.0")
208
+ @oid_sysHttpStatV10Reqs ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.11.0")
209
+ @oid_sysHttpStatV11Reqs ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.12.0")
210
+ @oid_sysHttpStatV9Resp ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.13.0")
211
+ @oid_sysHttpStatV10Resp ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.14.0")
212
+ @oid_sysHttpStatV11Resp ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.15.0")
213
+ @oid_sysHttpStatRespBucket1k ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.17.0")
214
+ @oid_sysHttpStatRespBucket4k ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.18.0")
215
+ @oid_sysHttpStatRespBucket16k ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.19.0")
216
+ @oid_sysHttpStatRespBucket32k ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.4.20.0")
217
+
218
+ if snmp
219
+ res = snmp.get_value([@oid_sysHttpStatResp2xxCnt, @oid_sysHttpStatResp3xxCnt, @oid_sysHttpStatResp4xxCnt,
220
+ @oid_sysHttpStatResp5xxCnt, @oid_sysHttpStatNumberReqs, @oid_sysHttpStatGetReqs,
221
+ @oid_sysHttpStatPostReqs, @oid_sysHttpStatV9Reqs, @oid_sysHttpStatV10Reqs,
222
+ @oid_sysHttpStatV11Reqs, @oid_sysHttpStatV9Resp, @oid_sysHttpStatV10Resp,
223
+ @oid_sysHttpStatV11Resp, @oid_sysHttpStatRespBucket1k, @oid_sysHttpStatRespBucket4k,
224
+ @oid_sysHttpStatRespBucket16k, @oid_sysHttpStatRespBucket32k, ])
225
+
226
+ report_counter_metric "HTTP/Response Code/2xx", "resp/sec", res[0]
227
+ report_counter_metric "HTTP/Response Code/3xx", "resp/sec", res[1]
228
+ report_counter_metric "HTTP/Response Code/4xx", "resp/sec", res[2]
229
+ report_counter_metric "HTTP/Response Code/5xx", "resp/sec", res[3]
230
+
231
+ report_counter_metric "HTTP/Method/All", "req/sec", res[4]
232
+ report_counter_metric "HTTP/Method/Get", "req/sec", res[5]
233
+ report_counter_metric "HTTP/Method/Post", "req/sec", res[6]
234
+ report_counter_metric "HTTP/Version/v0.9/Request", "req/sec", res[7]
235
+ report_counter_metric "HTTP/Version/v1.0/Request", "req/sec", res[8]
236
+ report_counter_metric "HTTP/Version/v1.1/Request", "req/sec", res[9]
237
+ report_counter_metric "HTTP/Version/v0.9/Response", "resp/sec", res[10]
238
+ report_counter_metric "HTTP/Version/v1.0/Response", "resp/sec", res[11]
239
+ report_counter_metric "HTTP/Version/v1.1/Response", "resp/sec", res[12]
240
+
241
+ report_counter_metric "HTTP/Response Size/1k Bucket", "resp/sec", res[13]
242
+ report_counter_metric "HTTP/Response Size/4k Bucket", "resp/sec", res[14]
243
+ report_counter_metric "HTTP/Response Size/16k Bucket", "resp/sec", res[15]
244
+ report_counter_metric "HTTP/Response Size/32k Bucket", "resp/sec", res[16]
245
+ end
246
+ end
247
+
248
+
249
+ #
250
+ # HTTP Compression Stats
251
+ #
252
+ def report_global_http_compression_metrics(snmp)
253
+ @oid_sysHttpCompressionStatPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.2.0")
254
+ @oid_sysHttpCompressionStatPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.3.0")
255
+ @oid_sysHttpCompressionStatHtmlPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.5.0")
256
+ @oid_sysHttpCompressionStatHtmlPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.6.0")
257
+ @oid_sysHttpCompressionStatCssPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.7.0")
258
+ @oid_sysHttpCompressionStatCssPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.8.0")
259
+ @oid_sysHttpCompressionStatJsPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.9.0")
260
+ @oid_sysHttpCompressionStatJsPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.10.0")
261
+ @oid_sysHttpCompressionStatXmlPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.11.0")
262
+ @oid_sysHttpCompressionStatXmlPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.12.0")
263
+ @oid_sysHttpCompressionStatSgmlPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.13.0")
264
+ @oid_sysHttpCompressionStatSgmlPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.14.0")
265
+ @oid_sysHttpCompressionStatPlainPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.15.0")
266
+ @oid_sysHttpCompressionStatPlainPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.16.0")
267
+ @oid_sysHttpCompressionStatOctetPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.17.0")
268
+ @oid_sysHttpCompressionStatOctetPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.18.0")
269
+ @oid_sysHttpCompressionStatImagePrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.19.0")
270
+ @oid_sysHttpCompressionStatImagePostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.20.0")
271
+ @oid_sysHttpCompressionStatVideoPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.21.0")
272
+ @oid_sysHttpCompressionStatVideoPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.22.0")
273
+ @oid_sysHttpCompressionStatAudioPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.23.0")
274
+ @oid_sysHttpCompressionStatAudioPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.24.0")
275
+ @oid_sysHttpCompressionStatOtherPrecompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.25.0")
276
+ @oid_sysHttpCompressionStatOtherPostcompressBytes ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.22.26.0")
277
+
278
+ if snmp
279
+ res = snmp.get_value([@oid_sysHttpCompressionStatPrecompressBytes, @oid_sysHttpCompressionStatPostcompressBytes,
280
+ @oid_sysHttpCompressionStatHtmlPrecompressBytes, @oid_sysHttpCompressionStatHtmlPostcompressBytes,
281
+ @oid_sysHttpCompressionStatCssPrecompressBytes, @oid_sysHttpCompressionStatCssPostcompressBytes,
282
+ @oid_sysHttpCompressionStatJsPrecompressBytes, @oid_sysHttpCompressionStatJsPostcompressBytes,
283
+ @oid_sysHttpCompressionStatXmlPrecompressBytes, @oid_sysHttpCompressionStatXmlPostcompressBytes,
284
+ @oid_sysHttpCompressionStatSgmlPrecompressBytes, @oid_sysHttpCompressionStatSgmlPostcompressBytes,
285
+ @oid_sysHttpCompressionStatPlainPrecompressBytes, @oid_sysHttpCompressionStatPlainPostcompressBytes,
286
+ @oid_sysHttpCompressionStatOctetPrecompressBytes, @oid_sysHttpCompressionStatOctetPostcompressBytes,
287
+ @oid_sysHttpCompressionStatImagePrecompressBytes, @oid_sysHttpCompressionStatImagePostcompressBytes,
288
+ @oid_sysHttpCompressionStatVideoPrecompressBytes, @oid_sysHttpCompressionStatVideoPostcompressBytes,
289
+ @oid_sysHttpCompressionStatAudioPrecompressBytes, @oid_sysHttpCompressionStatAudioPostcompressBytes,
290
+ @oid_sysHttpCompressionStatOtherPrecompressBytes, @oid_sysHttpCompressionStatOtherPostcompressBytes, ])
291
+
292
+ vals = res.map { |i| i.to_f * 8 } # Convert to bits
293
+ report_counter_metric "HTTP/Compression/Total/Pre", "bits/sec", vals[0]
294
+ report_counter_metric "HTTP/Compression/Total/Post", "bits/sec", vals[1]
295
+ report_counter_metric "HTTP/Compression/HTML/Pre", "bits/sec", vals[2]
296
+ report_counter_metric "HTTP/Compression/HTML/Post", "bits/sec", vals[3]
297
+ report_counter_metric "HTTP/Compression/CSS/Pre", "bits/sec", vals[4]
298
+ report_counter_metric "HTTP/Compression/CSS/Post", "bits/sec", vals[5]
299
+ report_counter_metric "HTTP/Compression/Javascript/Pre", "bits/sec", vals[6]
300
+ report_counter_metric "HTTP/Compression/Javascript/Post", "bits/sec", vals[7]
301
+ report_counter_metric "HTTP/Compression/XML/Pre", "bits/sec", vals[8]
302
+ report_counter_metric "HTTP/Compression/XML/Post", "bits/sec", vals[9]
303
+ report_counter_metric "HTTP/Compression/SGML/Pre", "bits/sec", vals[10]
304
+ report_counter_metric "HTTP/Compression/SGML/Post", "bits/sec", vals[11]
305
+ report_counter_metric "HTTP/Compression/Plain/Pre", "bits/sec", vals[12]
306
+ report_counter_metric "HTTP/Compression/Plain/Post", "bits/sec", vals[13]
307
+ report_counter_metric "HTTP/Compression/Octet/Pre", "bits/sec", vals[14]
308
+ report_counter_metric "HTTP/Compression/Octet/Post", "bits/sec", vals[15]
309
+ report_counter_metric "HTTP/Compression/Image/Pre", "bits/sec", vals[16]
310
+ report_counter_metric "HTTP/Compression/Image/Post", "bits/sec", vals[17]
311
+ report_counter_metric "HTTP/Compression/Video/Pre", "bits/sec", vals[18]
312
+ report_counter_metric "HTTP/Compression/Video/Post", "bits/sec", vals[19]
313
+ report_counter_metric "HTTP/Compression/Audio/Pre", "bits/sec", vals[20]
314
+ report_counter_metric "HTTP/Compression/Audio/Post", "bits/sec", vals[21]
315
+ report_counter_metric "HTTP/Compression/Other/Pre", "bits/sec", vals[22]
316
+ report_counter_metric "HTTP/Compression/Other/Post", "bits/sec", vals[23]
317
+ end
318
+ end
319
+
320
+ #
321
+ # SSL Stats
322
+ #
323
+ def report_global_ssl_metrics(snmp)
324
+ @oid_sysClientsslStatTotNativeConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.9.6.0")
325
+ @oid_sysClientsslStatTotCompatConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.9.9.0")
326
+ @oid_sysServersslStatTotNativeConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.10.6.0")
327
+ @oid_sysServersslStatTotCompatConns ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.10.9.0")
328
+
329
+ if snmp
330
+ res = snmp.get_value([@oid_sysClientsslStatTotNativeConns, @oid_sysClientsslStatTotCompatConns, @oid_sysServersslStatTotNativeConns,
331
+ @oid_sysServersslStatTotCompatConns])
332
+ vals = res.map { |i| i.to_i }
333
+ report_counter_metric "SSL/Global/Client/Native", "trans/sec", vals[0]
334
+ report_counter_metric "SSL/Global/Client/Compat", "trans/sec", vals[1]
335
+ report_counter_metric "SSL/Global/Server/Native", "trans/sec", vals[2]
336
+ report_counter_metric "SSL/Global/Server/Compat", "trans/sec", vals[3]
337
+ report_counter_metric "SSL/Global/Total/Client", "trans/sec", (vals[0] + vals[1])
338
+ report_counter_metric "SSL/Global/Total/Server", "trans/sec", (vals[2] + vals[3])
339
+ report_counter_metric "SSL/Global/Total/All", "trans/sec", vals.inject(0) { |t,i| t + i }
340
+ end
341
+ end
342
+
343
+
344
+ #
345
+ # Gather TCP Statistics and report them
346
+ #
347
+ def report_global_tcp_metrics(snmp)
348
+ # Create the OIDs if they don't exist
349
+ @oid_sysTcpStatOpen ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.2.0") # "The number of current open connections."
350
+ @oid_sysTcpStatCloseWait ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.3.0") # "The number of current connections in CLOSE-WAIT/LAST-ACK."
351
+ @oid_sysTcpStatFinWait ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.4.0") # "The number of current connections in FIN-WAIT/CLOSING."
352
+ @oid_sysTcpStatTimeWait ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.5.0") # "The number of current connections in TIME-WAIT."
353
+ @oid_sysTcpStatAccepts ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.6.0") # "The number of connections accepted."
354
+ # @oid_sysTcpStatAcceptfails ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.7.0") # "The number of connections not accepted."
355
+ # @oid_sysTcpStatConnects ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.8.0") # "The number of connections established."
356
+ # @oid_sysTcpStatConnfails ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.9.0") # "The number of connection failures."
357
+ # @oid_sysTcpStatExpires ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.10.0") # "The number of connections expired due to idle timeout."
358
+ # @oid_sysTcpStatAbandons ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.11.0") # "The number of connections abandoned connections due to retries/keep-alives."
359
+ # @oid_sysTcpStatRxrst ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.12.0") # "The number of received RST."
360
+ # @oid_sysTcpStatRxbadsum ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.13.0") # "The number of bad checksum."
361
+ # @oid_sysTcpStatRxbadseg ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.14.0") # "The number of malformed segments."
362
+ # @oid_sysTcpStatRxooseg ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.15.0") # "The number of out of order segments."
363
+ # @oid_sysTcpStatRxcookie ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.16.0") # "The number of received SYN-cookies."
364
+ # @oid_sysTcpStatRxbadcookie ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.17.0") # "The number of bad SYN-cookies."
365
+ # @oid_sysTcpStatSyncacheover ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.18.0") # "The number of SYN-cache overflow."
366
+ # @oid_sysTcpStatTxrexmits ||= SNMP::ObjectId.new("1.3.6.1.4.1.3375.2.1.1.2.12.19.0") # "The number of retransmitted segments."
367
+ if snmp
368
+ res = snmp.get_value([@oid_sysTcpStatOpen, @oid_sysTcpStatCloseWait, @oid_sysTcpStatFinWait,
369
+ @oid_sysTcpStatTimeWait, @oid_sysTcpStatAccepts, ])
370
+
371
+ report_metric "TCP/Connection State/Open", "conn", res[0]
372
+ report_metric "TCP/Connection State/Wait/Close", "conn", res[1]
373
+ report_metric "TCP/Connection State/Wait/FIN", "conn", res[2]
374
+ report_metric "TCP/Connection State/Wait/TIME", "conn", res[3]
375
+ report_counter_metric "TCP/Accepts", "conn/sec", res[4]
376
+ end
377
+ end
378
+
379
+ end
380
+ end
381
+
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'newrelic_plugin'
6
+ require 'snmp'
7
+
8
+
9
+ module NewRelic
10
+ module F5Plugin
11
+
12
+ module Nodes
13
+ NODE_MONITOR_STATES = {
14
+ 0 => 'unchecked',
15
+ 1 => 'checking',
16
+ 2 => 'inband',
17
+ 3 => 'forced-up',
18
+ 4 => 'up',
19
+ 19 => 'down',
20
+ 20 => 'forced-down',
21
+ 21 => 'maint',
22
+ 22 => 'irule-down',
23
+ 23 => 'inband-down',
24
+ 24 => 'down-manual-resume',
25
+ 25 => 'disabled',
26
+ }
27
+
28
+ #
29
+ # Node Naming in SNMP
30
+ #
31
+ # vb.name = SNMPv2-SMI::enterprises.3375.2.2.4.1.2.1.7.{name length}.{name in dot seperated ASCII code} (because why not...)
32
+ #tmp_name = vb.name.to_s.gsub(/SNMPv2-SMI::enterprises\.3375\.2\.2\.4\.1\.2\.1\.7\.\d+\./, '').split('.').collect! { |c| c.to_i.chr } # Create an array of the ASCII chars of the node name
33
+ #name = tmp_name.join
34
+
35
+ #
36
+ # Gather Node Status and report
37
+ #
38
+ def self.get_status(snmp)
39
+ if snmp
40
+ # Init all the states with zeros so we always get them
41
+ base_name = "Nodes/Monitor Status"
42
+ metrics = { }
43
+ NODE_MONITOR_STATES.each do |key,value|
44
+ metrics["#{base_name}/#{value}"] = { :label => "nodes", :count => 0 }
45
+ end
46
+
47
+ # ltmNodeAddrMonitorStatus
48
+ snmp.walk(["1.3.6.1.4.1.3375.2.2.4.1.2.1.7"]) do |row|
49
+ row.each do |vb|
50
+ metric_name = "#{base_name}/#{NODE_MONITOR_STATES[vb.value.to_i]}"
51
+ metrics[metric_name][:count] += 1
52
+ end
53
+ end
54
+
55
+ return metrics
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,89 @@
1
+ ## This is the rakegem gemspec template. Make sure you read and understand
2
+ ## all of the comments. Some sections require modification, and others can
3
+ ## be deleted if you don't need them. Once you understand the contents of
4
+ ## this file, feel free to delete any comments that begin with two hash marks.
5
+ ## You can find comprehensive Gem::Specification documentation, at
6
+ ## http://docs.rubygems.org/read/chapter/20
7
+ Gem::Specification.new do |s|
8
+ s.specification_version = 2 if s.respond_to? :specification_version=
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.rubygems_version = '1.3.5'
11
+
12
+ ## Leave these as is they will be modified for you by the rake gemspec task.
13
+ ## If your rubyforge_project name is different, then edit it and comment out
14
+ ## the sub! line in the Rakefile
15
+ s.name = 'newrelic_f5_plugin'
16
+ s.version = '1.0.0'
17
+ s.date = '2013-06-18'
18
+ s.rubyforge_project = 'newrelic_f5_plugin'
19
+
20
+ ## Make sure your summary is short. The description may be as long
21
+ ## as you like.
22
+ s.summary = "New Relic F5 plugin"
23
+ s.description = <<-EOF
24
+ This is the New Relic plugin for monitoring F5 devices developed by New Relic, Inc.
25
+ EOF
26
+
27
+ ## List the primary authors. If there are a bunch of authors, it's probably
28
+ ## better to set the email to an email list or something. If you don't have
29
+ ## a custom homepage, consider using your GitHub URL or the like.
30
+ s.authors = ["Jonathan Thurman"]
31
+ s.email = 'support@newrelic.com'
32
+ s.homepage = 'http://newrelic.com'
33
+
34
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
35
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
36
+ s.require_paths = %w[lib]
37
+
38
+ ## This sections is only necessary if you have C extensions.
39
+ # s.require_paths << 'ext'
40
+ # s.extensions = %w[ext/extconf.rb]
41
+
42
+ ## If your gem includes any executables, list them here.
43
+ s.executables = ["f5_monitor"]
44
+
45
+ ## Specify any RDoc options here. You'll want to add your README and
46
+ ## LICENSE files to the extra_rdoc_files list.
47
+ s.rdoc_options = ["--charset=UTF-8",
48
+ "--main", "README.rdoc"]
49
+ s.extra_rdoc_files = %w[README.rdoc LICENSE CHANGES]
50
+
51
+ ## The newrelic_plugin needs to be installed. Prior to public release, the
52
+ # gem needs to be downloaded from git@github.com:newrelic-platform/newrelic_plugin.git
53
+ # and built using the "rake build" command
54
+ s.add_dependency('newrelic_plugin', ">= 0.2.11")
55
+ s.add_dependency('snmp', ">= 1.1.0")
56
+
57
+ s.post_install_message = <<-EOF
58
+ To get started with this plugin, create a working directory and do
59
+ f5_monitor -h
60
+ to find out how to install and run the plugin agent.
61
+ EOF
62
+
63
+ ## Leave this section as-is. It will be automatically generated from the
64
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
65
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
66
+ # = MANIFEST =
67
+ s.files = %w[
68
+ CHANGES
69
+ Gemfile
70
+ LICENSE
71
+ NOTES
72
+ README.rdoc
73
+ Rakefile
74
+ bin/f5_monitor
75
+ config/newrelic_plugin.yml
76
+ lib/newrelic_f5_plugin.rb
77
+ lib/newrelic_f5_plugin/agent.rb
78
+ lib/newrelic_f5_plugin/nodes.rb
79
+ newrelic_f5_plugin.gemspec
80
+ test/f5_monitor_test.rb
81
+ test/plugin_test.rb
82
+ test/test_helper.rb
83
+ ]
84
+ # = MANIFEST =
85
+
86
+ ## Test files will be grabbed from the file list. Make sure the path glob
87
+ ## matches what you actually use.
88
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
89
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper.rb'
2
+ class F5MonitorTest < Test::Unit::TestCase
3
+
4
+ context "f5_monitor" do
5
+
6
+ setup do
7
+ @verbose = $VERBOSE
8
+ $VERBOSE = nil
9
+ @file = File.expand_path("../../bin/f5_monitor", __FILE__)
10
+ end
11
+
12
+ teardown do
13
+ $VERBOSE = @verbose
14
+ end
15
+
16
+ should "show help" do
17
+ `#{@file} -h` =~ /Usage:/
18
+ end
19
+
20
+ should "run" do
21
+ ::ARGV = %w[run]
22
+ NewRelic::F5Plugin.expects :run
23
+ load @file
24
+ end
25
+
26
+ should "install" do
27
+ ::ARGV = %w[install --license LICENSE_KEY]
28
+ FileUtils.expects :mkdir_p
29
+ File.expects :open
30
+ load @file
31
+ end
32
+ end
33
+
34
+ end
35
+
@@ -0,0 +1,79 @@
1
+ require 'test_helper.rb'
2
+ class PluginTest < Test::Unit::TestCase
3
+
4
+ context "Plugin" do
5
+
6
+ setup do
7
+ NewRelic::F5Plugin
8
+ NewRelic::Plugin::Config.config_yaml = <<-EOF
9
+ newrelic:
10
+ license_key: 'test_license_key'
11
+ verbose: 0
12
+ host: "localhost"
13
+ agents:
14
+ f5:
15
+ -
16
+ name: 'My F5 LTM'
17
+ hostname: 'my-f5'
18
+ port: 161
19
+ snmp_community: 'public'
20
+ EOF
21
+ NewRelic::Plugin::Setup.install_agent :f5, NewRelic::F5Plugin
22
+ end
23
+
24
+ should "create a run" do
25
+ # The run loop is stubbed out so this just verifies the agent initializes correctly.
26
+ NewRelic::Plugin::Run.any_instance.expects :setup_from_config
27
+ NewRelic::Plugin::Run.any_instance.expects :loop_forever
28
+ NewRelic::F5Plugin.run
29
+ end
30
+
31
+ # This mimics NewRelic::Plugin::Run.setup_and_run except for the loop_forever part
32
+ context "run" do
33
+ setup do
34
+ NewRelic::Plugin::Run.any_instance.stubs :loop_forever
35
+ @run = NewRelic::Plugin::Run.new
36
+ @run.setup_from_config
37
+ agents = @run.configured_agents
38
+ assert_equal 1, agents.size
39
+ @agent = agents.first
40
+ end
41
+
42
+ should "have one configured agent" do
43
+ assert_equal "My F5 LTM", @agent.name
44
+ end
45
+
46
+ #context "test db" do
47
+ # setup do
48
+ # # Setup a test database
49
+ # @client = Mysql2::Client.new :host => 'localhost', :username => 'root'
50
+ # @client.query "create database nr_mysql_plugin" rescue nil
51
+ # @client.query "create table nr_mysql_plugin.example (id int)"
52
+ # @client.query "create table nr_mysql_plugin.ignored (id int)"
53
+ # @client.query "insert into nr_mysql_plugin.example values (1),(2),(3),(4),(5)"
54
+ # end
55
+ # teardown do
56
+ # @client.query "drop database nr_mysql_plugin" rescue nil
57
+ # end
58
+ # should "get table stats" do
59
+ # schemas = @agent.mysql_table_stats
60
+ # assert_equal 1, schemas.size
61
+ # tables = schemas['nr_mysql_plugin']
62
+ # assert_equal 1, tables.size
63
+ # rec = tables.first
64
+ # assert_equal "example", rec.name
65
+ # assert_equal 5, rec.rows
66
+ # end
67
+ # should "poll" do
68
+ # # This stubs out the remote connection--we're not testing the plugin agent here
69
+ # NewRelic::Plugin::DataCollector.any_instance.stubs :process
70
+ # @agent.run 60 # seconds
71
+ # end
72
+ #end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'newrelic_f5_plugin'
3
+ require 'test-unit'
4
+ require 'shoulda'
5
+ require 'mocha/setup'
6
+
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: newrelic_f5_plugin
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonathan Thurman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: newrelic_plugin
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.2.11
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.2.11
30
+ - !ruby/object:Gem::Dependency
31
+ name: snmp
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.1.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.1.0
46
+ description: ! 'This is the New Relic plugin for monitoring F5 devices developed by
47
+ New Relic, Inc.
48
+
49
+ '
50
+ email: support@newrelic.com
51
+ executables:
52
+ - f5_monitor
53
+ extensions: []
54
+ extra_rdoc_files:
55
+ - README.rdoc
56
+ - LICENSE
57
+ - CHANGES
58
+ files:
59
+ - CHANGES
60
+ - Gemfile
61
+ - LICENSE
62
+ - NOTES
63
+ - README.rdoc
64
+ - Rakefile
65
+ - bin/f5_monitor
66
+ - config/newrelic_plugin.yml
67
+ - lib/newrelic_f5_plugin.rb
68
+ - lib/newrelic_f5_plugin/agent.rb
69
+ - lib/newrelic_f5_plugin/nodes.rb
70
+ - newrelic_f5_plugin.gemspec
71
+ - test/f5_monitor_test.rb
72
+ - test/plugin_test.rb
73
+ - test/test_helper.rb
74
+ homepage: http://newrelic.com
75
+ licenses: []
76
+ post_install_message: ! "To get started with this plugin, create a working directory
77
+ and do \n f5_monitor -h\nto find out how to install and run the plugin agent.\n"
78
+ rdoc_options:
79
+ - --charset=UTF-8
80
+ - --main
81
+ - README.rdoc
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project: newrelic_f5_plugin
98
+ rubygems_version: 1.8.23
99
+ signing_key:
100
+ specification_version: 2
101
+ summary: New Relic F5 plugin
102
+ test_files:
103
+ - test/test_helper.rb