riemann-tools 1.10.0 → 1.11.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +7 -6
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +18 -0
  5. data/CHANGELOG.md +23 -0
  6. data/Gemfile +22 -0
  7. data/Rakefile +1 -1
  8. data/bin/riemann-hwmon +8 -0
  9. data/bin/riemann-tls-check +8 -0
  10. data/lib/riemann/tools/apache_status.rb +2 -0
  11. data/lib/riemann/tools/bench.rb +4 -2
  12. data/lib/riemann/tools/consul_health.rb +2 -0
  13. data/lib/riemann/tools/dir_files_count.rb +2 -0
  14. data/lib/riemann/tools/dir_space.rb +2 -0
  15. data/lib/riemann/tools/diskstats.rb +6 -4
  16. data/lib/riemann/tools/fd.rb +2 -0
  17. data/lib/riemann/tools/freeswitch.rb +2 -0
  18. data/lib/riemann/tools/haproxy.rb +2 -0
  19. data/lib/riemann/tools/health.rb +79 -11
  20. data/lib/riemann/tools/http_check.rb +56 -17
  21. data/lib/riemann/tools/hwmon.rb +111 -0
  22. data/lib/riemann/tools/mdstat_parser.tab.rb +4 -2
  23. data/lib/riemann/tools/net.rb +3 -7
  24. data/lib/riemann/tools/nginx_status.rb +8 -4
  25. data/lib/riemann/tools/ntp.rb +2 -0
  26. data/lib/riemann/tools/portcheck.rb +2 -0
  27. data/lib/riemann/tools/proc.rb +2 -0
  28. data/lib/riemann/tools/tls_check.rb +604 -0
  29. data/lib/riemann/tools/utils.rb +39 -0
  30. data/lib/riemann/tools/varnish.rb +2 -0
  31. data/lib/riemann/tools/version.rb +1 -1
  32. data/lib/riemann/tools.rb +26 -9
  33. data/riemann-tools.gemspec +2 -11
  34. data/tools/riemann-aws/lib/riemann/tools/aws/billing.rb +3 -1
  35. data/tools/riemann-aws/lib/riemann/tools/aws/rds_status.rb +2 -0
  36. data/tools/riemann-aws/lib/riemann/tools/aws/s3_status.rb +1 -1
  37. data/tools/riemann-aws/lib/riemann/tools/aws/sqs_status.rb +2 -0
  38. data/tools/riemann-aws/lib/riemann/tools/aws/status.rb +11 -9
  39. data/tools/riemann-chronos/lib/riemann/tools/chronos.rb +2 -0
  40. data/tools/riemann-docker/lib/riemann/tools/docker.rb +5 -5
  41. data/tools/riemann-marathon/lib/riemann/tools/marathon.rb +2 -0
  42. data/tools/riemann-munin/lib/riemann/tools/munin.rb +2 -0
  43. data/tools/riemann-rabbitmq/lib/riemann/tools/rabbitmq.rb +7 -7
  44. data/tools/riemann-riak/lib/riemann/tools/riak.rb +4 -2
  45. metadata +10 -129
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecfc9ade5a8ea50dcf495633c6427b14d41b78c04ef436c062491f96f97cbc16
4
- data.tar.gz: 4ef67c8726d662c449e545601d3e7fe29d7104edaff39be294ca26e963f8e176
3
+ metadata.gz: aa81e2c6ea617e2450bdc8456f8665493241b19256be9a5443b6351e5d417ace
4
+ data.tar.gz: 0eb2bb5e1f6caea452a2babe933acd270840a78fe15520d637b7b3eb1deeb93e
5
5
  SHA512:
6
- metadata.gz: 1d6b3a8872ffd2f8e73415f1108cb853d04ddf5fcf4fa0a9de81701f993d286f6b9337f3448d54d56d6da4f50f5d2582d29c1d4da18be418dcb5e5b1addd3eab
7
- data.tar.gz: 8753726be6f187c0d88cbc8cf08eea6df9d4d5d5996e6d0ac44c5fc7bfe5d5dc648e9c191f9d0691f780d6b5e4a60ef75176f3ead1803e97e1a107e67234eb9c
6
+ metadata.gz: eccb9331a24c1db7812365ee6c52d811a962b681563237f1e4f196aad7ae59171daaf9548db8792ff8ab548b393a04c00078c8ba59701373f8c452077960cae6
7
+ data.tar.gz: 75508745d0f31fd2b5457531ae68158f514ca5ac9fa65c64c00c9ceedf67df8644b87bd324ef0aca94527e862c51ad063702ab8be95181723b6c73fefd2c9fb9
@@ -17,7 +17,7 @@ jobs:
17
17
  - name: Setup ruby
18
18
  uses: ruby/setup-ruby@v1
19
19
  with:
20
- ruby-version: '2.7'
20
+ ruby-version: '3.1'
21
21
  bundler-cache: true
22
22
  - name: Run rubocop
23
23
  run: bundle exec rubocop
@@ -27,11 +27,12 @@ jobs:
27
27
  strategy:
28
28
  matrix:
29
29
  ruby-version:
30
- - 2.6
31
- - 2.7
32
- - 3.0
33
- - 3.1
34
- - 3.2
30
+ - '2.6'
31
+ - '2.7'
32
+ - '3.0'
33
+ - '3.1'
34
+ - '3.2'
35
+ - '3.3'
35
36
  steps:
36
37
  - uses: actions/checkout@v4
37
38
  - name: Setup Ruby
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ pkg/
6
6
  .*.swp
7
7
  *.log
8
8
  lib/riemann/tools/*_parser.tab.rb
9
+ spec/fixtures/test-asn/test-asn
data/.rubocop.yml CHANGED
@@ -1,14 +1,20 @@
1
1
  ---
2
2
  AllCops:
3
+ NewCops: enable
3
4
  Exclude:
4
5
  - lib/riemann/tools/*_parser.tab.rb
5
6
  - vendor/bundle/**/*
7
+ require:
8
+ - rubocop-rake
9
+ - rubocop-rspec
6
10
  Gemspec/RequiredRubyVersion:
7
11
  Enabled: false
8
12
  Layout/HashAlignment:
9
13
  EnforcedHashRocketStyle: table
10
14
  Layout/LineLength:
11
15
  Enabled: false
16
+ Lint/EmptyBlock:
17
+ Enabled: false
12
18
  Metrics/AbcSize:
13
19
  Enabled: false
14
20
  Metrics/BlockLength:
@@ -28,10 +34,22 @@ Naming/MethodParameterName:
28
34
  - az # availability zone
29
35
  - id
30
36
  - lb # load balancer
37
+ RSpec/ExampleLength:
38
+ Enabled: false
39
+ RSpec/MultipleExpectations:
40
+ Enabled: false
41
+ RSpec/NamedSubject:
42
+ Enabled: false
43
+ RSpec/NestedGroups:
44
+ Enabled: false
45
+ RSpec/SubjectStub:
46
+ Enabled: false
31
47
  Style/Documentation:
32
48
  Enabled: false
33
49
  Style/HashSyntax:
34
50
  EnforcedShorthandSyntax: never
51
+ Style/NegatedIfElseCondition:
52
+ Enabled: false
35
53
  Style/TrailingCommaInArguments:
36
54
  EnforcedStyleForMultiline: consistent_comma
37
55
  Style/TrailingCommaInArrayLiteral:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.11.0](https://github.com/riemann/riemann-tools/tree/v1.11.0) (2024-07-07)
4
+
5
+ [Full Changelog](https://github.com/riemann/riemann-tools/compare/v1.10.0...v1.11.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add a new `riemann-hwmon` tool for harware monitors [\#297](https://github.com/riemann/riemann-tools/pull/297) ([smortex](https://github.com/smortex))
10
+ - Add support for ignoring IPs by ASN in `riemann-http` [\#295](https://github.com/riemann/riemann-tools/pull/295) ([smortex](https://github.com/smortex))
11
+ - Add support for a minimum TTL for events [\#294](https://github.com/riemann/riemann-tools/pull/294) ([smortex](https://github.com/smortex))
12
+ - Detect and report stray arguments [\#293](https://github.com/riemann/riemann-tools/pull/293) ([smortex](https://github.com/smortex))
13
+ - Add leniency to disk thresholds of `riemann-health` [\#282](https://github.com/riemann/riemann-tools/pull/282) ([smortex](https://github.com/smortex))
14
+ - Add `riemann-tls-check` to monitor TLS certificates [\#253](https://github.com/riemann/riemann-tools/pull/253) ([smortex](https://github.com/smortex))
15
+
16
+ **Fixed bugs:**
17
+
18
+ - Minor `riemann-hwmon` improvements [\#298](https://github.com/riemann/riemann-tools/pull/298) ([smortex](https://github.com/smortex))
19
+ - Fix `riemann-nginx` checks selection [\#292](https://github.com/riemann/riemann-tools/pull/292) ([smortex](https://github.com/smortex))
20
+ - Fix `riemann-health` memory reporting when using ZFS on Linux [\#289](https://github.com/riemann/riemann-tools/pull/289) ([smortex](https://github.com/smortex))
21
+
22
+ **Closed issues:**
23
+
24
+ - RFC: `riemann-domain-check` to monitor domain name expiration date [\#249](https://github.com/riemann/riemann-tools/issues/249)
25
+
3
26
  ## [v1.10.0](https://github.com/riemann/riemann-tools/tree/v1.10.0) (2024-01-13)
4
27
 
5
28
  [Full Changelog](https://github.com/riemann/riemann-tools/compare/v1.9.1...v1.10.0)
data/Gemfile CHANGED
@@ -4,3 +4,25 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in riemann-tools.gemspec
6
6
  gemspec
7
+
8
+ gem 'github_changelog_generator'
9
+ gem 'maxmind-geoip2'
10
+ gem 'racc'
11
+ gem 'rake'
12
+ gem 'rspec'
13
+ gem 'rubocop'
14
+ gem 'rubocop-rake'
15
+ gem 'rubocop-rspec'
16
+ gem 'sinatra'
17
+ gem 'webrick'
18
+
19
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
20
+ # XXX: Needed for Ruby 2.6 compatibility
21
+ #
22
+ # With Ruby 2.6 an older version of rakup is installed that cause other gems
23
+ # to be installed with a legacy version.
24
+ #
25
+ # Because rakup is only needed when using rack 3, we can just ignore this
26
+ # with Ruby 2.6.
27
+ gem 'rackup'
28
+ end
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ task :rbuild do
20
20
  end
21
21
  end
22
22
 
23
- task build: :gen_parser
23
+ Rake::Task['build'].enhance(['gen_parser'])
24
24
 
25
25
  desc 'Generate parsers'
26
26
  task gen_parser: [
data/bin/riemann-hwmon ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ Process.setproctitle($PROGRAM_NAME)
5
+
6
+ require 'riemann/tools/hwmon'
7
+
8
+ Riemann::Tools::Hwmon.run
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ Process.setproctitle($PROGRAM_NAME)
5
+
6
+ require 'riemann/tools/tls_check'
7
+
8
+ Riemann::Tools::TLSCheck.run
@@ -18,6 +18,8 @@ module Riemann
18
18
  opt :user_agent, 'User-Agent header for HTTP requests', short: :none, default: "#{File.basename($PROGRAM_NAME)}/#{Riemann::Tools::VERSION} (+https://github.com/riemann/riemann-tools)"
19
19
 
20
20
  def initialize
21
+ super
22
+
21
23
  @uri = URI.parse("#{opts[:uri]}?auto")
22
24
  # Sample Response with ExtendedStatus On
23
25
  # Total Accesses: 20643
@@ -11,6 +11,8 @@ module Riemann
11
11
  attr_accessor :client, :hosts, :services, :states
12
12
 
13
13
  def initialize
14
+ super
15
+
14
16
  @hosts = [nil] + (0...10).map { |i| "host#{i}" }
15
17
  @hosts = %w[a b c d e f g h i j]
16
18
  @services = %w[test1 test2 test3 foo bar baz xyzzy attack cat treat]
@@ -19,8 +21,8 @@ module Riemann
19
21
  end
20
22
 
21
23
  def evolve(state)
22
- m = state[:metric] + (rand - 0.5) * 0.1
23
- m = [[0, m].max, 1].min
24
+ m = state[:metric] + ((rand - 0.5) * 0.1)
25
+ m = m.clamp(0, 1)
24
26
 
25
27
  s = case m
26
28
  when 0...0.75
@@ -20,6 +20,8 @@ module Riemann
20
20
  opt :user_agent, 'User-Agent header for HTTP requests', short: :none, default: "#{File.basename($PROGRAM_NAME)}/#{Riemann::Tools::VERSION} (+https://github.com/riemann/riemann-tools)"
21
21
 
22
22
  def initialize
23
+ super
24
+
23
25
  @hostname = opts[:consul_host]
24
26
  @prefix = opts[:prefix]
25
27
  @minimum_services_per_node = opts[:minimum_services_per_node]
@@ -15,6 +15,8 @@ module Riemann
15
15
  opt :alert_on_missing, 'Send a critical metric if the directory is missing?', default: true
16
16
 
17
17
  def initialize
18
+ super
19
+
18
20
  @dir = opts.fetch(:directory)
19
21
  @service_prefix = opts.fetch(:service_prefix)
20
22
  @warning = opts.fetch(:warning, nil)
@@ -15,6 +15,8 @@ module Riemann
15
15
  opt :alert_on_missing, 'Send a critical metric if the directory is missing?', default: true
16
16
 
17
17
  def initialize
18
+ super
19
+
18
20
  @dir = opts.fetch(:directory)
19
21
  @service_prefix = opts.fetch(:service_prefix)
20
22
  @warning = opts.fetch(:warning, nil)
@@ -11,12 +11,14 @@ module Riemann
11
11
  opt :ignore_devices, 'Devices to ignore', type: :strings, default: nil
12
12
 
13
13
  def initialize
14
+ super
15
+
14
16
  @old_state = nil
15
17
  end
16
18
 
17
19
  def state
18
20
  f = File.read('/proc/diskstats')
19
- state = f.split("\n").reject { |d| d =~ /(ram|loop)/ }.each_with_object({}) do |line, s|
21
+ state = f.split("\n").grep_v(/(ram|loop)/).each_with_object({}) do |line, s|
20
22
  next unless line =~ /^(?:\s+\d+){2}\s+([\w\d-]+) (.*)$/
21
23
 
22
24
  dev = Regexp.last_match(1)
@@ -43,13 +45,13 @@ module Riemann
43
45
  # Filter interfaces
44
46
  if (is = opts[:devices])
45
47
  state = state.select do |service, _value|
46
- is.include? service.split(' ').first
48
+ is.include? service.split.first
47
49
  end
48
50
  end
49
51
 
50
52
  if (ign = opts[:ignore_devices])
51
53
  state = state.reject do |service, _value|
52
- ign.include? service.split(' ').first
54
+ ign.include? service.split.first
53
55
  end
54
56
  end
55
57
 
@@ -80,7 +82,7 @@ module Riemann
80
82
  next unless service =~ /io time$/
81
83
 
82
84
  report(
83
- service: "diskstats #{service.gsub(/time/, 'util')}",
85
+ service: "diskstats #{service.gsub('time', 'util')}",
84
86
  metric: (delta.to_f / (opts[:interval] * 1000)),
85
87
  state: 'ok',
86
88
  )
@@ -16,6 +16,8 @@ module Riemann
16
16
  opt :processes, 'list of processes to measure fd usage in addition to system total', type: :ints
17
17
 
18
18
  def initialize
19
+ super
20
+
19
21
  @limits = {
20
22
  fd: { critical: opts[:fd_sys_critical], warning: opts[:fd_sys_warning] },
21
23
  process: { critical: opts[:fd_proc_critical], warning: opts[:fd_proc_warning] },
@@ -13,6 +13,8 @@ module Riemann
13
13
  opt :pid_file, 'FreeSWITCH daemon pidfile', type: String, default: '/var/run/freeswitch/freeswitch.pid'
14
14
 
15
15
  def initialize
16
+ super
17
+
16
18
  @limits = {
17
19
  calls: { critical: opts[:calls_critical], warning: opts[:calls_warning] },
18
20
  }
@@ -16,6 +16,8 @@ module Riemann
16
16
  opt :user_agent, 'User-Agent header for HTTP requests', short: :none, default: "#{File.basename($PROGRAM_NAME)}/#{Riemann::Tools::VERSION} (+https://github.com/riemann/riemann-tools)"
17
17
 
18
18
  def initialize
19
+ super
20
+
19
21
  @uri = URI("#{opts[:stats_url]};csv")
20
22
  end
21
23
 
@@ -11,10 +11,15 @@ module Riemann
11
11
  include Riemann::Tools
12
12
  include Riemann::Tools::Utils
13
13
 
14
+ PROC_PID_INIT_INO = 0xEFFFFFFC
15
+ SI_UNITS = '_kMGTPEZYRQ'
16
+
14
17
  opt :cpu_warning, 'CPU warning threshold (fraction of total jiffies)', default: 0.9
15
18
  opt :cpu_critical, 'CPU critical threshold (fraction of total jiffies)', default: 0.95
16
19
  opt :disk_warning, 'Disk warning threshold (fraction of space used)', default: 0.9
17
20
  opt :disk_critical, 'Disk critical threshold (fraction of space used)', default: 0.95
21
+ opt :disk_warning_leniency, 'Disk warning threshold (amount of free space)', short: :none, default: '500G'
22
+ opt :disk_critical_leniency, 'Disk critical threshold (amount of free space)', short: :none, default: '250G'
18
23
  opt :disk_ignorefs, 'A list of filesystem types to ignore',
19
24
  default: %w[anon_inodefs autofs cd9660 devfs devtmpfs fdescfs iso9660 linprocfs linsysfs nfs overlay procfs squashfs tmpfs]
20
25
  opt :load_warning, 'Load warning threshold (load average / core)', default: 3.0
@@ -30,9 +35,11 @@ module Riemann
30
35
  opt :checks, 'A list of checks to run.', type: :strings, default: %w[cpu load memory disk swap]
31
36
 
32
37
  def initialize
38
+ super
39
+
33
40
  @limits = {
34
41
  cpu: { critical: opts[:cpu_critical], warning: opts[:cpu_warning] },
35
- disk: { critical: opts[:disk_critical], warning: opts[:disk_warning] },
42
+ disk: { critical: opts[:disk_critical], warning: opts[:disk_warning], critical_leniency_kb: human_size_to_number(opts[:disk_critical_leniency]) / 1024, warning_leniency_kb: human_size_to_number(opts[:disk_warning_leniency]) / 1024 },
36
43
  load: { critical: opts[:load_critical], warning: opts[:load_warning] },
37
44
  memory: { critical: opts[:memory_critical], warning: opts[:memory_warning] },
38
45
  uptime: { critical: opts[:uptime_critical], warning: opts[:uptime_warning] },
@@ -154,6 +161,11 @@ module Riemann
154
161
  end
155
162
  end
156
163
 
164
+ def linux_running_in_container?
165
+ @linux_running_in_container = File.readlink('/proc/self/ns/pid') != "pid:[#{PROC_PID_INIT_INO}]" if @linux_running_in_container.nil?
166
+ @linux_running_in_container
167
+ end
168
+
157
169
  def linux_cpu
158
170
  new = File.read('/proc/stat')
159
171
  unless new[/cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/]
@@ -188,19 +200,50 @@ module Riemann
188
200
  end
189
201
 
190
202
  def linux_memory
191
- m = File.read('/proc/meminfo').split(/\n/).each_with_object({}) do |line, info|
203
+ m = File.read('/proc/meminfo').split("\n").each_with_object({}) do |line, info|
192
204
  x = line.split(/:?\s+/)
193
205
  # Assume kB...
194
206
  info[x[0]] = x[1].to_i
195
207
  end
196
208
 
197
- free = m['MemFree'].to_i + m['Buffers'].to_i + m['Cached'].to_i
198
- total = m['MemTotal'].to_i
209
+ free = m['MemFree'] + m['Buffers'] + m['Cached'] + linux_zfs_arc_evictable_memory
210
+ total = m['MemTotal']
199
211
  fraction = 1 - (free.to_f / total)
200
212
 
201
213
  report_pct :memory, fraction, "used\n\n#{reverse_numeric_sort_with_header(`ps -eo pmem,pid,comm`)}"
202
214
  end
203
215
 
216
+ # On Linux, the ZFS ARC is reported as used, not as cached memory.
217
+ # https://github.com/openzfs/zfs/issues/10251
218
+ #
219
+ # Gather ZFS ARC statisticts about evictable memory. The available
220
+ # fields are listed here:
221
+ # https://github.com/openzfs/zfs/blob/master/include/sys/arc_impl.h
222
+ def linux_zfs_arc_evictable_memory
223
+ # When the system is a container, it can access the hosts stats that
224
+ # cause invalid memory usage reporting. We should only remove
225
+ # evictable memory from the ZFS ARC on the host system.
226
+ return 0 if linux_running_in_container?
227
+
228
+ m = File.readlines('/proc/spl/kstat/zfs/arcstats').each_with_object(Hash.new(0)) do |line, info|
229
+ x = line.split(/\s+/)
230
+ info[x[0]] = x[2].to_i
231
+ end
232
+
233
+ (
234
+ m['anon_evictable_data'] +
235
+ m['anon_evictable_metadata'] +
236
+ m['mru_evictable_data'] +
237
+ m['mru_evictable_metadata'] +
238
+ m['mfu_evictable_data'] +
239
+ m['mfu_evictable_metadata'] +
240
+ m['uncached_evictable_data'] +
241
+ m['uncached_evictable_metadata']
242
+ ) / 1024 # We want kB...
243
+ rescue Errno::ENOENT
244
+ 0
245
+ end
246
+
204
247
  def freebsd_cpu
205
248
  u2, n2, s2, t2, i2 = `sysctl -n kern.cp_time 2>/dev/null`.split.map(&:to_i) # FreeBSD has 5 cpu stats
206
249
 
@@ -374,14 +417,14 @@ module Riemann
374
417
  def df
375
418
  case @ostype
376
419
  when 'darwin', 'freebsd', 'openbsd'
377
- `df -P -t no#{opts[:disk_ignorefs].join(',')}`
420
+ `df -Pk -t no#{opts[:disk_ignorefs].join(',')}`
378
421
  when 'sunos'
379
- `df -P` # Is there a good way to exlude iso9660 here?
422
+ `df -Pk` # Is there a good way to exlude iso9660 here?
380
423
  else
381
424
  if @supports_exclude_type
382
- `df -P #{opts[:disk_ignorefs].map { |fstype| "--exclude-type=#{fstype}" }.join(' ')}`
425
+ `df -Pk #{opts[:disk_ignorefs].map { |fstype| "--exclude-type=#{fstype}" }.join(' ')}`
383
426
  else
384
- `df -P`
427
+ `df -Pk`
385
428
  end
386
429
  end
387
430
  end
@@ -397,12 +440,12 @@ module Riemann
397
440
 
398
441
  x = used.to_f / total_without_reservation
399
442
 
400
- if x > @limits[:disk][:critical]
443
+ if x > @limits[:disk][:critical] && available < @limits[:disk][:critical_leniency_kb]
401
444
  alert "disk #{f[5]}", :critical, x, "#{f[4]} used"
402
- elsif x > @limits[:disk][:warning]
445
+ elsif x > @limits[:disk][:warning] && available < @limits[:disk][:warning_leniency_kb]
403
446
  alert "disk #{f[5]}", :warning, x, "#{f[4]} used"
404
447
  else
405
- alert "disk #{f[5]}", :ok, x, "#{f[4]} used"
448
+ alert "disk #{f[5]}", :ok, x, "#{f[4]} used, #{number_to_human_size(available * 1024, :floor)} free"
406
449
  end
407
450
  end
408
451
  end
@@ -468,6 +511,31 @@ module Riemann
468
511
  ].compact.join(' ')
469
512
  end
470
513
 
514
+ def human_size_to_number(value)
515
+ case value
516
+ when /^\d+$/ then value.to_i
517
+ when /^\d+k$/i then value.to_i * 1024
518
+ when /^\d+M$/i then value.to_i * (1024**2)
519
+ when /^\d+G$/i then value.to_i * (1024**3)
520
+ when /^\d+T$/i then value.to_i * (1024**4)
521
+ when /^\d+P$/i then value.to_i * (1024**5)
522
+ when /^\d+E$/i then value.to_i * (1024**6)
523
+ when /^\d+Z$/i then value.to_i * (1024**7)
524
+ when /^\d+Y$/i then value.to_i * (1024**8)
525
+ when /^\d+R$/i then value.to_i * (1024**9)
526
+ when /^\d+Q$/i then value.to_i * (1024**10)
527
+ else
528
+ raise %(Malformed size "#{value}", syntax is [0-9]+[#{SI_UNITS[1..]}]?)
529
+ end
530
+ end
531
+
532
+ def number_to_human_size(value, rounding = :round)
533
+ return value.to_s if value < 1024
534
+
535
+ r = Math.log(value, 1024).floor
536
+ format('%<size>.1f%<unit>ciB', size: (value.to_f / (1024**r)).send(rounding, 1), unit: SI_UNITS[r])
537
+ end
538
+
471
539
  def tick
472
540
  invalidate_cache
473
541
 
@@ -32,15 +32,24 @@ module Riemann
32
32
  opt :resolvers, 'Run this number of resolver threads', short: :none, type: :integer, default: 5
33
33
  opt :workers, 'Run this number of worker threads', short: :none, type: :integer, default: 20
34
34
  opt :user_agent, 'User-Agent header for HTTP requests', short: :none, default: "#{File.basename($PROGRAM_NAME)}/#{Riemann::Tools::VERSION} (+https://github.com/riemann/riemann-tools)"
35
+ opt :ignored_asn, 'Ignore addresses belonging to these ASN', short: :none, type: :integers, default: []
36
+ opt :geoip_asn_database, 'Path to the GeoIP ASN database', short: :none, default: '/usr/share/GeoIP/GeoLite2-ASN.mmdb'
35
37
 
36
38
  def initialize
39
+ super
40
+
37
41
  @resolve_queue = Queue.new
38
42
  @work_queue = Queue.new
39
43
 
44
+ @resolvers = []
45
+ @workers = []
46
+
40
47
  opts[:resolvers].times do
41
- Thread.new do
48
+ @resolvers << Thread.new do
42
49
  loop do
43
50
  uri = @resolve_queue.pop
51
+ Thread.exit unless uri
52
+
44
53
  host = uri.host
45
54
 
46
55
  addresses = Resolv::DNS.new.getaddresses(host)
@@ -53,21 +62,61 @@ module Riemann
53
62
  end
54
63
  end
55
64
 
65
+ if opts[:ignored_asn].any?
66
+ addresses.reject! do |address|
67
+ address_belongs_to_ignored_asn?(address)
68
+ end
69
+ end
70
+
71
+ next if addresses.empty?
72
+
56
73
  @work_queue.push([uri, addresses])
57
74
  end
58
75
  end
59
76
  end
60
77
 
61
78
  opts[:workers].times do
62
- Thread.new do
79
+ @workers << Thread.new do
63
80
  loop do
64
81
  uri, addresses = @work_queue.pop
82
+ Thread.exit unless uri
83
+
65
84
  test_uri_addresses(uri, addresses)
66
85
  end
67
86
  end
68
87
  end
88
+ end
69
89
 
70
- super
90
+ def address_belongs_to_ignored_asn?(address)
91
+ begin
92
+ require 'maxmind/geoip2'
93
+ rescue LoadError
94
+ raise StandardError, 'MaxMind::GeoIP2 is not available. Please install the maxmind-geoip2 gem for filtering by ASN.'
95
+ end
96
+
97
+ @reader ||= MaxMind::GeoIP2::Reader.new(database: opts[:geoip_asn_database])
98
+ asn = @reader.asn(address.to_s)
99
+
100
+ opts[:ignored_asn].include?(asn&.autonomous_system_number)
101
+ rescue MaxMind::GeoIP2::AddressNotFoundError
102
+ false
103
+ end
104
+
105
+ # Under normal operation, we have a single instance of this class for the
106
+ # lifetime of the process. But when testing, we create a new instance
107
+ # for each test, each with its resolvers and worker threads. The test
108
+ # process may end-up with a lot of running threads, hitting the OS limit
109
+ # of max threads by process and being unable to create more thread:
110
+ #
111
+ # ThreadError: can't create Thread: Resource temporarily unavailable
112
+ #
113
+ # To avoid this situation, we provide this method.
114
+ def shutdown
115
+ @resolve_queue.close
116
+ @resolvers.map(&:join)
117
+
118
+ @work_queue.close
119
+ @workers.map(&:join)
71
120
  end
72
121
 
73
122
  def tick
@@ -104,10 +153,8 @@ module Riemann
104
153
  def test_uri_addresses(uri, addresses)
105
154
  request = get_request(uri)
106
155
 
107
- responses = []
108
-
109
- addresses.each do |address|
110
- responses << test_uri_address(uri, address.to_s, request)
156
+ responses = addresses.map do |address|
157
+ test_uri_address(uri, address.to_s, request)
111
158
  end
112
159
 
113
160
  responses.compact!
@@ -265,8 +312,8 @@ module Riemann
265
312
  end
266
313
 
267
314
  def latency_state(name, latency)
268
- critical_threshold = opts["#{name}_latency_critical".to_sym]
269
- warning_threshold = opts["#{name}_latency_warning".to_sym]
315
+ critical_threshold = opts[:"#{name}_latency_critical"]
316
+ warning_threshold = opts[:"#{name}_latency_warning"]
270
317
 
271
318
  return if critical_threshold.zero? || warning_threshold.zero?
272
319
 
@@ -301,14 +348,6 @@ module Riemann
301
348
  reported_uri.password = '**redacted**' if reported_uri.password
302
349
  reported_uri
303
350
  end
304
-
305
- def endpoint_name(address, port)
306
- if address.ipv6?
307
- "[#{address}]:#{port}"
308
- else
309
- "#{address}:#{port}"
310
- end
311
- end
312
351
  end
313
352
  end
314
353
  end