newrelic_f5_plugin 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.
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