Domain-check for multiple domains

Hi All,

I need to set up domain expiration checks with multiple domains. i.e I need to check the expiration of all my domains under a single check. can anyone help me with this to setup?

Hey!

Do you have a check example that works with a single domain you can share?

I think we can probably do what you want as a proxy_request using a token substitution pattern. I’d setup each of your domains that you want to check as a proxy entity, each with the necessary annotations to make the proxy request in the check operate correctly.

Hi Jspaleta,

Please find below the check-domain.rb script.

#!/usr/bin/ruby

frozen_string_literal: false

check-whois-domain-expiration-multi

DESCRIPTION:

This plugin checks domain expiration dates using the ‘whois’ gem.

OUTPUT:

plain text

PLATFORMS:

*nix systems

DEPENDENCIES:

gem: sensu-plugin

gem: whois

USAGE:

./check-whois-domain-expiration-multi.rb -d therealtimsmith.com,mightyoakspreschool.com

WhoisDomainExpirationCheck WARNING: mightyoakspreschool.com: 30 days

LICENSE:

Copyright 2015 Tim Smith (tim@cozy.co) - Cozy Services Ltd.

Based on check-whois-domain-expiration, Copyright 2015 michael j talarczyk mjt@mijit.com

and contributors.

Released under the same terms as Sensu (the MIT license); see LICENSE

for details.

if RUBY_VERSION < ‘1.9.0’
require ‘rubygems’

round(n) doesn’t exist in ruby < 1.9

class Float
alias_method :oldround, :round

def round(precision = nil)
  if precision.nil?
    return self
  else
    return ((self * 10**precision).oldround.to_f) / (10**precision)
  end
end

end
end

require ‘sensu-plugin/check/cli’
require ‘whois’
require ‘whois-parser’

Check Whois domain expiration

class WhoisDomainExpirationCheck < Sensu::Plugin::Check::CLI
option :domain,
short: ‘-d DOMAINS’,
long: ‘–domains DOMAIN’,
required: true,
description: ‘Domain(s) to check. Separate by commas for 2+’

option :warning,
short: ‘-w DAYS’,
long: ‘–warn DAYS’,
default: 30,
proc: proc(&:to_i),
description: ‘Warn if fewer than DAYS away’

option :critical,
short: ‘-c DAYS’,
long: ‘–critical DAYS’,
proc: proc(&:to_i),
default: 7,
description: ‘Critical if fewer than DAYS away’

option :‘ignore-errors’,
short: ‘-i’,
long: ‘–ignore-errors’,
boolean: true,
default: false,
description: ‘Ignore connection or parsing errors’

option :‘report-errors’,
short: ‘-r LEVEL’,
long: ‘–report-errors LEVEL’,
proc: proc(&:to_sym),
in: %i[unknown warning critical],
default: :unknown,
description: ‘Level for reporting connection or parsing errors’

option :timeout,
short: ‘-t SECONDS’,
long: ‘–timeout SECONDS’,
proc: proc(&:to_i),
default: 10,
description: ‘Timeout for whois lookup’

option :help,
short: ‘-h’,
long: ‘–help’,
description: ‘Show this message’,
on: :tail,
boolean: true,
show_options: true,
exit: 0

split the provided domain list and perform whois lookups on each

return a hash with domains grouped by their status level

def expiration_results
domains = config[:domain].split(’,’)
warning_days = config[:warning].to_i
critical_days = config[:critical].to_i
max_retries = 4

results = {
  critical: {},
  warning: {},
  ok: {},
  unknown: {}
}
whois = Whois::Client.new(timeout: config[:timeout])

domains.each do |domain|
  begin
    tries ||= 0
    whois_result = whois.lookup(domain).parser
  rescue Timeout::Error, Errno::ECONNRESET, Whois::ConnectionError
    tries += 1
    if tries < max_retries
      retry
    else
      results[:unknown][domain] = 'Connection error' unless config[:'ignore-errors']
      next
    end
  end

  begin
    expires_on = DateTime.parse(whois_result.expires_on.to_s)
    domain_result = (expires_on - DateTime.now).to_i
    if domain_result <= critical_days
      results[:critical][domain] = domain_result
    elsif domain_result <= warning_days
      results[:warning][domain] = domain_result
    else
      results[:ok][domain] = domain_result
    end
  rescue StandardError
    results[:unknown][domain] = 'Parsing error' unless config[:'ignore-errors']
  end
end
results

end

def run
results = expiration_results

warn_results = results[:critical].merge(results[:warning]).map { |u, v| "#{u} (#{v} days left)" }
unknown_results = results[:unknown].map { |u, v| "#{u} (#{v})" }
message warn_results.concat(unknown_results).join(', ')

if !results[:critical].empty? || (!results[:unknown].empty? && config[:'report-errors'] == :critical)
  critical
elsif !results[:warning].empty? || (!results[:unknown].empty? && config[:'report-errors'] == :warning)
  warning
elsif !results[:unknown].empty?
  unknown
else
  ok 'No domains expire in the near term'
end

end
end

Hey!

Looks like you are using the sensu-plugins-network-checks. Okay, instead of using the multi version of the check, what you could do instead is use check-whois-domain-expiration.rb together with some proxy entities so you can generate separate events for each domain.

Here’s my check, it’s using a proxy_requests attribute to ensure that the check only gets applied to proxy entities that have the whois_domain label defined.

It’s also using token substitution in the check command arguments so I can override the defaults using labels in each proxy entity.

type: CheckConfig
api_version: core/v2
metadata:
  name: whois_domain_check
spec:
  command: check-whois-domain-expiration.rb -d  {{ .labels.whois_domain }} -w {{.labels.whois_warning | default 90}} -c {{.labels.whois_critical | default 30}}
  interval: 60
  proxy_requests:
    entity_attributes:
    - entity.entity_class == 'proxy'
    - entity.labels.whois_domain != null
    splay: false
    splay_coverage: 0
  publish: true
  runtime_assets:
  - sensu-plugins/sensu-plugins-network-checks
  - sensu/sensu-ruby-runtime
  subscriptions:
  - localhost
  timeout: 0
  ttl: 0

So here are a couple of proxy entities that will will match the proxy_requests section in that check.

This one will check the the cnn.com domain as defined by the whois_domain entity label

type: Entity
api_version: core/v2
metadata:
  labels:
    whois_domain: cnn.com
  name: cnn.com
spec:
  entity_class: proxy
  sensu_agent_version: ""
  subscriptions:
  - domain_check

This one will check the google.com domain and will result in a warning event status, as I an using a very high value for whois_warning label, to ensure the check returns a warning. Because I’m using token substitution in the check command, I have complete control of how the check operates using entity labels in each proxy entity definition.

type: Entity
api_version: core/v2
metadata:
  labels:
    whois_domain: google.com
    whois_critical: "90"
    whois_warning: "4000"
  name: google.com
spec:
  entity_class: proxy
  subscriptions:
  - domain_check

So here’s what this looks like in my event list

sensuctl event list
     Entity                   Check                                                                  Output                                                       Status   Silenced             Timestamp             
 ─────────────── ─────────────────────────────── ─────────────────────────────────────────────────────────────────────────────────────────────────────────────── ──────── ────────── ──────────────────────────────── 
  cnn.com         proxy_domain_check              WhoisDomainExpirationCheck OK: cnn.com expires on 09-21-2026 (2508 days away)                                        0   false      2019-11-08 10:15:30 -0900 AKST  
  google.com      proxy_domain_check              WhoisDomainExpirationCheck WARNING: google.com expires on 09-13-2028 (3231 days away)                                1   false      2019-11-08 10:17:30 -0900 AKST                                                                                                                                                                                                             

The google.com proxy_domain_check is returning warning as expected because of the label value i’m using.