You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We found the check-http-json.rb was a very helpful check for our JSON returning API calls but wanted to be able to leverage it for our XML returning API calls as well.
So I have made some tweaks (as per code below) to allow you to select response type XML or JSON, then it converts the XML response to JSON and performs the same JSON search on it.
This has been working well for us so far.
Also, in order to be able to output this to influxDB to be able to build a dashboard in grafana I added the ability to select an output type or Check or Metric that will output in the Check output format or metric output format so that it will go into influxdb.
Just sharing this back in case you wanted to consider making this part of the plugin or making your own modification to fit this need.
# ! /usr/bin/env ruby
#
# check-http-json
#
# DESCRIPTION:
# Takes either a URL or a combination of host/path/query/port/ssl, and checks
# for valid JSON output in the response. Can also optionally validate simple
# string key/value pairs.
#
# OUTPUT:
# plain text
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
# gem: json
#
# USAGE:
# #YELLOW
#
# NOTES:
# Based on Check HTTP by Sonian Inc.
# Charles Curran: Made small tweak to allow for XML response use, converts to JSON then does the KEY = VALUE compare
#
# LICENSE:
# Copyright 2013 Matt Revell [email protected]
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
require 'sensu-plugin/check/cli'
require 'json'
require 'net/http'
require 'net/https'
require 'active_support/core_ext/hash'
#
# Check JSON
#
class CheckJson < Sensu::Plugin::Check::CLI
option :url, short: '-u URL'
option :host, short: '-h HOST'
option :path, short: '-p PATH'
option :query, short: '-q QUERY'
option :port, short: '-P PORT', proc: proc(&:to_i)
option :header, short: '-H HEADER', long: '--header HEADER'
option :ssl, short: '-s', boolean: true, default: false
option :insecure, short: '-k', boolean: true, default: false
option :user, short: '-U', long: '--username USER'
option :password, short: '-a', long: '--password PASS'
option :cert, short: '-c FILE'
option :cacert, short: '-C FILE'
option :timeout, short: '-t SECS', proc: proc(&:to_i), default: 15
option :key, short: '-K KEY', long: '--key KEY'
option :value, short: '-v VALUE', long: '--value VALUE'
##CHUCK ADDED OPTIONS
option :responseType, short: '-r RESPONSETYPE', default:'JSON'
option :outputType, short: '-o OUTPUTTYPE', default:'CHECK'
option :metricscheme, short: '-m METRICSCHEME'
##CHUCK ADDED FUNCTION
def output_result(output,metircscheme, status, outputMessage)
if output.upcase == "CHECK"
if status == "OK"
ok outputMessage
elsif status == "WARNING"
warning outputMessage
elsif status == "FAIL"
fail outputMessage
elsif status == "CRITICAL"
critical outputMessage
else #UKNOWN
unknown outputMessage
end
end
if output.upcase == "METRIC"
if status == "OK"
state = 0
elsif status == "WARNING"
state = 1
elsif status == "FAIL"
state = 2
elsif status == "CRITICAL"
state = 2
else #UNKNOWN
state = 3
end
puts "#{metircscheme}\t#{state}\t#{Time.now}"
exit 0
end
end
def run
if config[:url]
uri = URI.parse(config[:url])
config[:host] = uri.host
config[:path] = uri.path
config[:query] = uri.query
config[:port] = uri.port
config[:ssl] = uri.scheme == 'https'
else
# #YELLOW
unless config[:host] && config[:path] # rubocop:disable IfUnlessModifier
# unknown 'No URL specified'
#CHUCK
output_result(config[:outputType],config[:metricscheme], "UKNOWN", "No URL specified")
end
config[:port] ||= config[:ssl] ? 443 : 80
end
begin
timeout(config[:timeout]) do
acquire_resource
end
rescue Timeout::Error
# critical 'Connection timed out'
#CHUCK
output_result(config[:outputType],config[:metricscheme], "CRITICAL", "Connection timed out")
rescue => e
# critical "Connection error: #{e.message}"
#CHUCK
output_result(config[:outputType],config[:metricscheme], "CRITICAL", "Connection error: #{e.message}")
end
end
def json_valid?(str)
JSON.parse(str)
return true
rescue JSON::ParserError
return false
end
def acquire_resource # rubocop:disable all
http = Net::HTTP.new(config[:host], config[:port])
if config[:ssl]
http.use_ssl = true
if config[:cert]
cert_data = File.read(config[:cert])
http.cert = OpenSSL::X509::Certificate.new(cert_data)
http.key = OpenSSL::PKey::RSA.new(cert_data, nil)
end
http.ca_file = config[:cacert] if config[:cacert]
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if config[:insecure]
end
req = Net::HTTP::Get.new([config[:path], config[:query]].compact.join('?'))
if !config[:user].nil? && !config[:password].nil?
req.basic_auth config[:user], config[:password]
end
if config[:header]
config[:header].split(',').each do |header|
h, v = header.split(':', 2)
req[h] = v.strip
end
end
res = http.request(req)
##Chuck: Added Check for New Response Type to Convert XML Response to JSON so it can process it
if config[:responseType] == "XML" then
responseBody = Hash.from_xml(res.body).to_json
# puts "XML Converted To : #{responseBody}"
elsif config[:responseType] == "JSON" then
responseBody = res.body
else
# critical ' is an invalid response type from request'
##CHUCK
output_result(config[:outputType],config[:metricscheme], "CRITICAL", ' is an invalid response type from request')
end
# critical res.code unless res.code =~ /^2/
# critical 'invalid JSON from request' unless json_valid?(responseBody)
# ok 'valid JSON returned' if config[:key].nil? && config[:value].nil?
##CHUCK
if !res.code =~ /^2/
output_result(config[:outputType],config[:metricscheme], "CRITICAL", res.code)
end
if !json_valid?(responseBody)
output_result(config[:outputType],config[:metricscheme], "CRITICAL", " invalid JSON from request")
end
if config[:key].nil? && config[:value].nil?
output_result(config[:outputType],config[:metricscheme], "OK", " valid JSON returned")
end
json = JSON.parse(responseBody)
begin
keys = config[:key].scan(/(?:\\\.|[^.])+/).map { |key| key.gsub(/\\./, '.') }
leaf = keys.reduce(json) do |tree, key|
# fail "could not find key: #{config[:key]}" unless tree.key?(key)
##CHUCK
if !tree.key?(key)
output_result(config[:outputType],config[:metricscheme], "FAIL", "could not find key: #{config[:key]}")
end
tree[key]
end
# fail "unexpected value for key: '#{config[:value]}' != '#{leaf}'" unless leaf == config[:value]
output_result(config[:outputType],config[:metricscheme], "FAIL'" "unexpected value for key: '#{config[:value]}' != '#{leaf}'") unless leaf == config[:value]
# ok "key has expected value: '#{config[:key]}' = '#{config[:value]}'"
output_result(config[:outputType],config[:metricscheme], "OK", "key has expected value: '#{config[:key]}' = '#{config[:value]}'")
rescue => e
# critical "key check failed: #{e}"
output_result(config[:outputType],config[:metricscheme], "CRITICAL", " key check failed: #{e}")
end
end
end
The text was updated successfully, but these errors were encountered:
I would be willing to take a PR for this but this functionality would need to be another check.
The check-http-json should not be checking xml, the name would be misleading ;) If you want to create a new check, check-http-xml, that would be best but we could also create a check called, check-http-response, that could do both.
I would not rename the current check, as that would break versioning rules.
We found the check-http-json.rb was a very helpful check for our JSON returning API calls but wanted to be able to leverage it for our XML returning API calls as well.
So I have made some tweaks (as per code below) to allow you to select response type XML or JSON, then it converts the XML response to JSON and performs the same JSON search on it.
This has been working well for us so far.
Also, in order to be able to output this to influxDB to be able to build a dashboard in grafana I added the ability to select an output type or Check or Metric that will output in the Check output format or metric output format so that it will go into influxdb.
Just sharing this back in case you wanted to consider making this part of the plugin or making your own modification to fit this need.
The text was updated successfully, but these errors were encountered: