Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Max Horbul
committed
Apr 12, 2012
1 parent
254984f
commit c0f657d
Showing
8 changed files
with
382 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module Nagios | ||
|
||
STATUS = { 1 => "WARN", 2 => "CRITICAL", 0 => "OK" } | ||
|
||
module Splunk | ||
|
||
LOGIN_URL = "/services/auth/login" | ||
POOL_LIST_URL = "/services/licenser/pools" | ||
LICENSE_LIST_URL = "/services/licenser/licenses" | ||
|
||
autoload :Check, "splunk/check" | ||
autoload :RestClient, "splunk/rest_client" | ||
autoload :CLI, "splunk/cli" | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
require 'nokogiri' | ||
|
||
module Nagios | ||
|
||
module Splunk | ||
|
||
# Nagios::Splunk::Check implements different types of checks of | ||
class Check | ||
|
||
attr_reader :rest_client | ||
|
||
# @param [String] server_url full server url with username and password (RFC 3986) | ||
# example: https://user:pass@localhost:8089/ | ||
def initialize(client) | ||
@rest_client = client | ||
end | ||
|
||
# license usage check | ||
# @param [Integer] warn license usage threshhold | ||
# @param [Integer] crit license usage threshhold | ||
# @return [Array<Integer, String>] exit code and message | ||
def license_usage(warn, crit) | ||
quota = licenses. | ||
select {|k,v| v["type"] == "enterprise" && v["status"] == "VALID" }. | ||
reduce(0) { |r,l| r+=l[1]["quota"].to_i } | ||
used_quota = pools.reduce(0) {|r,p| r+=p[1]["used_bytes"].to_i } | ||
case true | ||
when used_quota > quota * crit.to_i / 100: | ||
code = 2 | ||
when used_quota > quota * warn.to_i / 100: | ||
code = 1 | ||
else | ||
code = 0 | ||
end | ||
message = "License #{STATUS[code]}: #{used_quota * 100 / quota}% of license capacity is used" | ||
message << " | quota: #{quota} B; used: #{used_quota} B" | ||
return [code, message] | ||
end | ||
|
||
# list of avialable licenses | ||
# @return [Array<Hash>] | ||
def licenses | ||
response = rest_client.get(LICENSE_LIST_URL) | ||
response.code == "200" ? parse_data(response.body) : {} | ||
end | ||
|
||
# list of available pools | ||
# @return [Array<Hash>] | ||
def pools | ||
response = rest_client.get(POOL_LIST_URL) | ||
response.code == "200" ? parse_data(response.body) : {} | ||
end | ||
|
||
private | ||
|
||
def parse_data(data) | ||
doc = Nokogiri::Slop(data) | ||
doc.remove_namespaces! | ||
doc.search("entry").reduce(Hash.new) do |r,e| | ||
name = e.title.content | ||
next r if name =~ /^F+D{0,1}$/ | ||
r[name] ||= Hash.new | ||
e.search("dict/key").each do |k| | ||
r[name][k.attribute("name").value] = k.text | ||
end | ||
r | ||
end | ||
end | ||
|
||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
require 'mixlib/cli' | ||
|
||
module Nagios | ||
module Splunk | ||
|
||
class CLI | ||
include Mixlib::CLI | ||
|
||
option(:server_url, | ||
:short => "-s URL", | ||
:long => "--server URL", | ||
:default => 'https://admin:changeme@localhost:8089/', | ||
:description => "Splunk server url") | ||
|
||
option(:warn, | ||
:short => "-w WARN", | ||
:long => "--warn WARN", | ||
:default => '80', | ||
:description => "Warn % of license capacity usage") | ||
|
||
option(:crit, | ||
:short => "-c CRIT", | ||
:long => "--crit CRIT", | ||
:default => '90', | ||
:description => "Critical % of license capacity usage") | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
require 'net/https' | ||
|
||
module Nagios | ||
module Splunk | ||
|
||
# Rest client which communicates with Splunk via REST API | ||
class RestClient | ||
|
||
attr_reader :token | ||
|
||
# turn on/off debugging | ||
# @param [<True, False>] | ||
def self.debug(value = nil) | ||
@debug = value if value | ||
@debug | ||
end | ||
|
||
# parse server url string and set up intance variables | ||
# @param [String] server_url full server url with username and password (RFC 3986) | ||
# example: https://user:pass@localhost:8089/ | ||
def initialize(server_url) | ||
uri = URI.parse(server_url) | ||
@host = uri.host | ||
@port = uri.port | ||
@username = uri.user | ||
@password = uri.password | ||
end | ||
|
||
# send HTTP request to the server | ||
# @param [String] url | ||
# @return [Net::HTTPRespose] | ||
def get(url) | ||
login unless token | ||
response = client.request(request(url, token)) | ||
end | ||
|
||
private | ||
|
||
# build GET request and include Authorization | ||
# @param [String] url | ||
# @param [String] token authenticate token | ||
def request(url, token) | ||
headers = { "Authorization" => "Splunk #{token}" } | ||
Net::HTTP::Get.new(url, headers) | ||
end | ||
|
||
# build HTTP connection | ||
# @return [Net::HTTP] | ||
def client | ||
@client ||= Net::HTTP.new(@host, @port) | ||
@client.use_ssl = true | ||
@client.set_debug_output $stderr if debug | ||
@client | ||
end | ||
|
||
def debug | ||
self.class.debug | ||
end | ||
|
||
# receive authentication token | ||
def login | ||
request = Net::HTTP::Post.new(LOGIN_URL) | ||
request.set_form_data({"username" => @username, "password" => @password}) | ||
response = client.request(request) | ||
if response.code == "200" | ||
doc = Nokogiri::XML.parse(response.body) | ||
elem = doc.search("//sessionKey").first | ||
@token = elem.text if elem | ||
end | ||
end | ||
|
||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<xml> | ||
<entry> | ||
<title>AAA</title> | ||
<content> | ||
<dict> | ||
<key name="quota">100</key> | ||
<key name="status">VALID</key> | ||
<key name="type">enterprise</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
<entry> | ||
<title>FFF</title> | ||
<content> | ||
<dict> | ||
<key name="quota">100</key> | ||
<key name="status">VALID</key> | ||
<key name="type">enterprise</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
<entry> | ||
<title>FFFD</title> | ||
<content> | ||
<dict> | ||
<key name="quota">100</key> | ||
<key name="status">VALID</key> | ||
<key name="type">enterprise</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
<entry> | ||
<title>BBB</title> | ||
<content> | ||
<dict> | ||
<key name="quota">200</key> | ||
<key name="status">EXPIRED</key> | ||
<key name="type">enterprise</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
<entry> | ||
<title>CCC</title> | ||
<content> | ||
<dict> | ||
<key name="quota">300</key> | ||
<key name="status">VALID</key> | ||
<key name="type">forwarder</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
</xml> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<xml> | ||
<entry> | ||
<title>AAA</title> | ||
<content> | ||
<dict> | ||
<key name="used_bytes">10</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
<entry> | ||
<title>BBB</title> | ||
<content> | ||
<dict> | ||
<key name="used_bytes">20</key> | ||
</dict> | ||
</content> | ||
</entry> | ||
</xml> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
require File.join(File.dirname(__FILE__), '../../test_helper') | ||
|
||
describe Nagios::Splunk::Check do | ||
|
||
before do | ||
@client = MiniTest::Mock.new | ||
@response = MiniTest::Mock.new | ||
@response1 = MiniTest::Mock.new | ||
@check = Nagios::Splunk::Check.new(@client) | ||
@licenses_xml = File.read(File.join(MiniTest.fixtures_path, "licenses.xml")) | ||
@pools_xml = File.read(File.join(MiniTest.fixtures_path, "pools.xml")) | ||
@licenses = { | ||
"AAA" => {"quota" => "100", "status" => "VALID", "type" => "enterprise"}, | ||
"BBB" => {"quota" => "200", "status" => "EXPIRED", "type" => "enterprise"}, | ||
"CCC" => {"quota" => "300", "status" => "VALID", "type" => "forwarder"} | ||
} | ||
@pools = { | ||
"AAA" => {"used_bytes" => "10"}, | ||
"BBB" => {"used_bytes" => "20"} | ||
} | ||
end | ||
|
||
describe "when fetch data" do | ||
|
||
describe "and response code is not 200 OK" do | ||
|
||
before do | ||
@response.expect(:code, "404") | ||
@response.expect(:body, "") | ||
end | ||
|
||
it "should have empty license list" do | ||
@client.expect(:get, @response, [Nagios::Splunk::LICENSE_LIST_URL]) | ||
@check.licenses.must_equal Hash.new | ||
end | ||
|
||
it "should have empty pools list" do | ||
@client.expect(:get, @response, [Nagios::Splunk::POOL_LIST_URL]) | ||
@check.pools.must_equal Hash.new | ||
end | ||
|
||
end | ||
|
||
describe "and body is empty" do | ||
|
||
before do | ||
@response.expect(:code, "200") | ||
@response.expect(:body, "<xml />") | ||
end | ||
|
||
it "should have empty license list" do | ||
@client.expect(:get, @response, [Nagios::Splunk::LICENSE_LIST_URL]) | ||
@check.licenses.must_equal Hash.new | ||
end | ||
|
||
it "should have empty pools list" do | ||
@client.expect(:get, @response, [Nagios::Splunk::POOL_LIST_URL]) | ||
@check.pools.must_equal Hash.new | ||
end | ||
|
||
end | ||
|
||
it "should be able to fetch licenses" do | ||
@response.expect(:code, "200") | ||
@response.expect(:body, @licenses_xml) | ||
@client.expect(:get, @response, [Nagios::Splunk::LICENSE_LIST_URL]) | ||
@check.licenses.must_equal @licenses | ||
end | ||
|
||
it "should be able to fetch pools" do | ||
@response.expect(:code, "200") | ||
@response.expect(:body, @pools_xml) | ||
@client.expect(:get, @response, [Nagios::Splunk::POOL_LIST_URL]) | ||
@check.pools.must_equal @pools | ||
end | ||
|
||
end | ||
|
||
describe "when check license usage" do | ||
|
||
before do | ||
@response.expect(:code, "200") | ||
@response.expect(:body, @licenses_xml) | ||
@client.expect(:get, @response, [Nagios::Splunk::LICENSE_LIST_URL]) | ||
|
||
@response1.expect(:code, "200") | ||
@response1.expect(:body, @pools_xml) | ||
@client.expect(:get, @response1, [Nagios::Splunk::POOL_LIST_URL]) | ||
end | ||
|
||
it "should return CRITICAL alert" do | ||
message = "License CRITICAL: 30% of license capacity is used | quota: 100 B; used: 30 B" | ||
@check.license_usage(10, 20).must_equal [2, message] | ||
end | ||
|
||
it "should return WARN alert" do | ||
message = "License WARN: 30% of license capacity is used | quota: 100 B; used: 30 B" | ||
@check.license_usage(20, 40).must_equal [1, message] | ||
end | ||
|
||
it "should return OK" do | ||
message = "License OK: 30% of license capacity is used | quota: 100 B; used: 30 B" | ||
@check.license_usage(40, 50).must_equal [0, message] | ||
end | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
$:.push File.join(File.dirname(__FILE__), "../lib/nagios") | ||
|
||
require 'rubygems' | ||
require "bundler/setup" | ||
require 'splunk' | ||
require 'minitest/autorun' | ||
|
||
module MiniTest | ||
def self.fixtures_path | ||
File.expand_path(File.join(File.dirname(__FILE__), "fixtures")) | ||
end | ||
end |