I
was presented with a new, not so fun, task.
Create a system that can count e-mails per hour from a sender and if
they go over a certain number react.
Sensu, for our team, is the obvious choice for the reaction part. But how do I count emails/hour from an
Exchange server without using any Microsoft Products?
Here
is my attempt.
Ruby Tools
At the end of the day I want this to be a simple ruby script
I can call from Sensu, so I am going to start there and see what tools I can
find.
I found viewpoint at https://github.com/WinRb/Viewpoint
[1]
Looks like it's in a gem, install it with the following
command
> sudo gem install viewpoint
|
Poking at it
I just want to poke at it a little and see what I can do.
Let me create a new plugin
> cd /etc/sensu/plugins
> sudo touch exchange_email_count.rb
> sudo chmod u+x exchange_email_count.rb
> sudo vi exchange_email_count.rb
|
I stared at the https://github.com/WinRb/Viewpoint
site for a long time and came up with the following code, which simply sends
out an email from your account.
Before you start down this path make sure you can talk to
the SOAP interface for the Exchange server.
First find the URL.
It should in a form like this.
https://example.com/ews/Exchange.asmx
|
Open that URL and see if you can login
You should get a bunch of XML (I blurred this just in case,
but it should be generic wsdl data)
If you confirmed that is working then grab your
Username
Password
And this address
And put them in this bit of code..
#!/usr/bin/ruby
require 'viewpoint'
include Viewpoint::EWS
endpoint = ' https://example.com/ews/Exchange.asmx'
user = 'username'
pass = 'password'
cli = Viewpoint::EWSClient.new endpoint, user, pass
cli.send_message subject: "Test", body: "This is to prove I can
email it out!", to_recipients: ['me@example.com']
puts "Email has been sent!"
|
Change the information for your own.
Now run it
> ./exchange_email_count.rb
|
If
you are lucky it runs! If you are like
me there is one more thing to take care of.
I
get this error back.
/var/lib/gems/1.9.1/gems/viewpoint-1.0.0/lib/ews/connection.rb:107:in
`check_response': SOAP Error:
Message: Code: (Viewpoint::EWS::Errors::SoapResponseError)
from
/var/lib/gems/1.9.1/gems/viewpoint-1.0.0/lib/ews/connection.rb:89:in `post'
from
/var/lib/gems/1.9.1/gems/viewpoint-1.0.0/lib/ews/connection.rb:67:in `dispatch'
from
/var/lib/gems/1.9.1/gems/viewpoint-1.0.0/lib/ews/soap/exchange_web_service.rb:212:in
`do_soap_request'
from
/var/lib/gems/1.9.1/gems/viewpoint-1.0.0/lib/ews/soap/exchange_data_services.rb:150:in
`create_item'
from
/var/lib/gems/1.9.1/gems/viewpoint-1.0.0/lib/ews/message_accessors.rb:65:in
`send_message'
from ./exchange_email_count.rb:16:in
`<main>'
The fix for this was to specify the server you are using.
For example if you Exchange server where Version 2010 SP3
you would change your code to this.
#!/usr/bin/ruby
require 'viewpoint'
include Viewpoint::EWS
endpoint = ' https://example.com/ews/Exchange.asmx'
user = 'username'
pass = 'password'
cli = Viewpoint::EWSClient.new endpoint, user, pass,
server_version: SOAP::ExchangeWebService::VERSION_2010_SP3
cli = Viewpoint::EWSClient.new endpoint, user, pass
cli.send_message subject: "Test", body: "This is to prove I can
email it out!", to_recipients: ['me@example.com']
puts "Email has been sent!"
|
Now run it
> ./exchange_email_count.rb
|
Now it works!
Counting emails
Let me see if I can just count the number of emails in my
inbox. Here is the code I came up with.
#!/usr/bin/ruby
require 'viewpoint'
include Viewpoint::EWS
endpoint = ' https://example.com/ews/Exchange.asmx'
user = 'username'
pass = 'password'
cli = Viewpoint::EWSClient.new endpoint, user, pass,
server_version: SOAP::ExchangeWebService::VERSION_2010_SP3
folder = cli.get_folder_by_name 'inbox'
dname = folder.display_name
count = folder.total_count
puts "In folder " + dname + " there are " + count.to_s + " emails"
|
Now run it
> ./exchange_email_count.rb
|
I got back 1,000 emails in my inbox. That number seems suspicious.
To check how many emails I actually have in my inbox I did
the following.
Right click on my inbox and select Properties
Select "Show Total Number of items" and click OK.
Oh, there is 1,000 emails in there.
As a test I sent myself 2 emails
Now it's 1002.
Really? I just happened to check
when I had 1,000 emails in my inbox…. That is hard to believe!
Running the script again I get
1,002. OK I guess
just an odd timing on my part J
Counting todays emails
A bit more tweaking,
I figured this out that returns the number of emails in the inbox from
today.
#!/usr/bin/ruby
require 'viewpoint'
include Viewpoint::EWS
endpoint = ' https://example.com/ews/Exchange.asmx'
user = 'username'
pass = 'password'
cli = Viewpoint::EWSClient.new endpoint, user, pass,
server_version: SOAP::ExchangeWebService::VERSION_2010_SP3
folder = cli.get_folder_by_name 'inbox'
dname = folder.display_name
count = folder.todays_items.length
puts count.to_s + " emails have been
received today"
|
Now run it
> ./exchange_email_count.rb
|
That worked.
Now to see if I can get just the last X minutes of emails
listed.
Counting the last X minutes of emails
A bit more tweaking, I
want to get a list of all the emails for over a given time frame.
#!/usr/bin/ruby
require 'viewpoint'
include Viewpoint::EWS
endpoint = ' https://example.com/ews/Exchange.asmx'
user = 'username'
pass = 'password'
cli = Viewpoint::EWSClient.new endpoint, user, pass,
server_version: SOAP::ExchangeWebService::VERSION_2010_SP3
folder = cli.get_folder_by_name 'inbox'
days = 5
end_t = Time.now
start_t = end_t - days*24*60*60
count = (folder.items_between start_t, end_t).length
puts count.to_s + " emails have been
received within the last " + days.to_s + " days"
|
Now run it
> ./exchange_email_count.rb
|
That worked. It's
almost what I want. The only addition I
want to add is to filter on a from address.
Let me see if I can do that.
Counting the last X minutes of emails that were send from a single email
address.
A bit more tweaking, I came up with this. Change the email to the one you want to
filter on.
#!/usr/bin/ruby
require 'viewpoint'
include Viewpoint::EWS
endpoint = ' https://example.com/ews/Exchange.asmx'
user = 'username'
pass = 'password'
cli = Viewpoint::EWSClient.new endpoint, user, pass,
server_version: SOAP::ExchangeWebService::VERSION_2010_SP3
folder = cli.get_folder_by_name 'inbox'
days = 3
end_t = Time.now
start_t = end_t - days*24*60*60
emails = folder.items_between(start_t, end_t)
sender_name = "test@example.com"
count = 0
for email in emails
if email.sender.email == sender_name
count += 1
end
end
puts "You have received " + count.to_s + " emails from " +
sender_name + " in the last " + days.to_s + " days"
|
Now run it
> ./exchange_email_count.rb
|
That is basically what I want, now to turn it into a real
Sensu plugin.
Change it into a Sensu plugin
#!/usr/bin/ruby
# # #The MIT License (MIT) # #Copyright (c) 2015 Patrick Bailey # #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal #in the Software without restriction, including without limitation the rights #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the Software is #furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all #copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #SOFTWARE. # # require 'sensu-plugin/check/cli' require 'viewpoint' include Viewpoint::EWS class CountEmails< Sensu::Plugin::Check::CLI option :minutes, :description => "How many minutes prior to check emails", :short => '-m MINUTES', :long => '--minutes MINUTES', :proc => proc {|a| a.to_i}, :default => 15, :required => true option :from_filter, :description => "Only count emails received from this email", :short => '-f FROM_FILTER', :long => '--from FROM_FILTER', :required => false option :warn_limit, :description => "Threshold, above which a warning is issued", :short => '-w WARN_LIMIT', :long => '--warn WARN_LIMIT', :proc => proc {|a| a.to_i}, :required => false option :alarm_limit, :description => "Threshold, above which an alarm is issued", :short => '-a ALARM', :long => '--alarm ALARM', :proc => proc {|a| a.to_i}, :required => false def initilize super end def run endpoint = ' https://example.com/ews/Exchange.asmx' user = 'username' pass = 'password' cli = Viewpoint::EWSClient.new endpoint, user, pass, server_version: SOAP::ExchangeWebService::VERSION_2010_SP1 folder = cli.get_folder_by_name 'inbox' end_t = Time.now start_t = end_t - config[:minutes]*60 emails = folder.items_between(start_t, end_t) count = 0 filter_note = "" #Filter if a from address is given if !config[:from_filter].nil? filter_note = " filtering on '" + config[:from_filter] + "'" for email in emails if email.sender.email == config[:from_filter] count += 1 end end else #No address to filter on count all email count = emails.length end if !config[:alarm_limit].nil? && count >= config[:alarm_limit] critical(message(count, config[:minutes], filter_note)) elsif !config[:warn_limit].nil? && count >= config[:warn_limit] warning(message(count, config[:minutes], filter_note)) else ok(message(count, config[:minutes], filter_note)) end end def message(count, minutes, filter_note) count.to_s + " emails have been received within the last " + minutes.to_s + " minutes" + filter_note end end |
I made a gist of it at https://gist.github.com/patmandenver/7ddafca42c2a555db4d8
Create the actual Check
> sudo vi
/etc/sensu/conf.d/check_email_count.json
|
Place the following into it.
{
"checks": {
"check_email_rate": {
"subscribers":
[
"check-from-sensu-master"
],
"refresh": 3600,
"occurrences": 1,
"interval": 900,
"command": "/etc/sensu/plugins/exchange_email_count.rb
-m 60 -f issue@example.com -w 10 -a 20",
"handlers": [
"default"
]
}
}
}
|
You will need to tweak these to your Sensu Settings. Basically I am running this check every 15
minutes. When it runs it counts the
emails sent in the last 60 minutes that were sent by issue@example.com. If there are more than 20 alarm. If there are more than 10, but less than 20
issue a warning.
Restart the
sensu-server on the client
> sudo service sensu-client restart
|
Restart the Sensu
Master with the following command.
> sudo
service sensu-server restart && sudo service sensu-api restart
|
Opening up my Sensu Uchiwa page at
I can see that the check is there.
This check, as is, will not work since there is no
example.com.
I tweaked it to actual settings and tested it. And it works!
That is cool!
References
[1] Viewpoint (Ruby client for Exchange Web
Services)
Accessed 1/2015
Epic Goal: My goal is to just really figure out how to use Sensu.
No comments:
Post a Comment