riemann-tools 1.10.0 → 1.11.0

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