Skip to content

Commit

Permalink
(RE-7014) Add support for statsd
Browse files Browse the repository at this point in the history
They way we were using graphite was incorrect for the type of data we were sending it.  statsd is the appropriate mechanism for our needs.
statsd and graphite are mutually exclusive and configuring statsd will take precendence over Graphite.  Example of configuration in vmpooler.yaml.example
  • Loading branch information
shermdog committed May 10, 2016
1 parent b59a1f8 commit 40bdd8b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 7 deletions.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
source ENV['GEM_SOURCE'] || 'https://rubygems.org'

gem 'json', '>= 1.8'
gem 'net-ldap', '<= 0.11'
gem 'rack', '>= 1.6'
gem 'rake', '>= 10.4'
gem 'rbvmomi', '>= 1.8'
gem 'redis', '>= 3.2'
gem 'sinatra', '>= 1.4'
gem 'statsd-ruby', '>= 1.3.0'

# Test deps
group :test do
gem 'rack-test', '>= 0.6'
gem 'rspec', '>= 3.2'
gem 'simplecov', '>= 0.11.2'
gem 'yarjuf', '>= 2.0'
end
13 changes: 13 additions & 0 deletions lib/vmpooler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Vmpooler
require 'rbvmomi'
require 'redis'
require 'sinatra/base'
require "statsd-ruby"
require 'time'
require 'timeout'
require 'yaml'
Expand Down Expand Up @@ -52,6 +53,10 @@ def self.config(filepath='vmpooler.yaml')
parsed_config[:graphite]['prefix'] ||= 'vmpooler'
end

if parsed_config[:statsd]['server']
parsed_config[:statsd]['prefix'] ||= 'vmpooler'
end

if parsed_config[:tagfilter]
parsed_config[:tagfilter].keys.each do |tag|
parsed_config[:tagfilter][tag] = Regexp.new(parsed_config[:tagfilter][tag])
Expand Down Expand Up @@ -79,6 +84,14 @@ def self.new_graphite(server)
end
end

def self.new_statsd(server, port)
if server.nil? or server.empty? or server.length == 0
nil
else
Statsd.new server, port
end
end

def self.pools(conf)
conf[:pools]
end
Expand Down
15 changes: 12 additions & 3 deletions lib/vmpooler/pool_manager.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
module Vmpooler
class PoolManager
def initialize(config, logger, redis, graphite=nil)
def initialize(config, logger, redis, graphite=nil, statsd=nil)
$config = config

# Load logger library
$logger = logger

unless graphite.nil?
# statsd and graphite are mutex in the context of vmpooler
unless statsd.nil?
$statsd = statsd
end

unless graphite.nil? || !statsd.nil?
$graphite = graphite
end

Expand Down Expand Up @@ -258,6 +263,7 @@ def clone_vm(template, folder, datastore, target)
$redis.decr('vmpooler__tasks__clone')

begin
$statsd.timing($config[:statsd]['prefix'] + ".clone.#{vm['template']}", finish) if defined? $statsd
$graphite.log($config[:graphite]['prefix'] + ".clone.#{vm['template']}", finish) if defined? $graphite
rescue
end
Expand Down Expand Up @@ -565,7 +571,10 @@ def _check_pool(pool)
total = $redis.scard('vmpooler__pending__' + pool['name']) + ready

begin
if defined? $graphite
if defined? $statsd
$statsd.increment($config[:statsd]['prefix'] + '.ready.' + pool['name'], $redis.scard('vmpooler__ready__' + pool['name']))
$statsd.increment($config[:statsd]['prefix'] + '.running.' + pool['name'], $redis.scard('vmpooler__running__' + pool['name']))
elsif defined? $graphite
$graphite.log($config[:graphite]['prefix'] + '.ready.' + pool['name'], $redis.scard('vmpooler__ready__' + pool['name']))
$graphite.log($config[:graphite]['prefix'] + '.running.' + pool['name'], $redis.scard('vmpooler__running__' + pool['name']))
end
Expand Down
12 changes: 12 additions & 0 deletions lib/vmpooler/statsd.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'rubygems' unless defined?(Gem)

module Vmpooler
class Statsd
def initialize(
s = 'statsd',
port = 8125
)
@server = Statsd.new s, port
end
end
end
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
require 'simplecov'
SimpleCov.start do
add_filter '/spec/'
end
require 'helpers'
require 'rbvmomi'
require 'rspec'
Expand Down
62 changes: 60 additions & 2 deletions spec/vmpooler/pool_manager_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
let(:logger) { double('logger') }
let(:redis) { double('redis') }
let(:config) { {} }
let(:graphite) { nil }
let(:pool) { 'pool1' }
let(:vm) { 'vm1' }
let(:timeout) { 5 }
let(:host) { double('host') }

subject { Vmpooler::PoolManager.new(config, logger, redis, graphite) }
subject { Vmpooler::PoolManager.new(config, logger, redis) }

describe '#_check_pending_vm' do
let(:pool_helper) { double('pool') }
Expand Down Expand Up @@ -252,6 +251,65 @@
end
end

describe '#_stats_running_ready' do
let(:pool_helper) { double('pool') }
let(:vsphere) { {pool => pool_helper} }
let(:graphite) { double('graphite') }
let(:config) { {
config: { task_limit: 10 },
pools: [ {'name' => 'pool1', 'size' => 5} ],
graphite: { 'prefix' => 'vmpooler' }
} }

before do
expect(subject).not_to be_nil
$vsphere = vsphere
allow(logger).to receive(:log)
allow(pool_helper).to receive(:find_folder)
allow(redis).to receive(:smembers).and_return([])
allow(redis).to receive(:set)
allow(redis).to receive(:get).with('vmpooler__tasks__clone').and_return(0)
allow(redis).to receive(:get).with('vmpooler__empty__pool1').and_return(nil)
end

context 'graphite' do
let(:graphite) { double('graphite') }
subject { Vmpooler::PoolManager.new(config, logger, redis, graphite) }

it 'increments graphite when enabled and statsd disabled' do
allow(redis).to receive(:scard).with('vmpooler__ready__pool1').and_return(1)
allow(redis).to receive(:scard).with('vmpooler__cloning__pool1').and_return(0)
allow(redis).to receive(:scard).with('vmpooler__pending__pool1').and_return(0)
allow(redis).to receive(:scard).with('vmpooler__running__pool1').and_return(5)

expect(graphite).to receive(:log).with('vmpooler.ready.pool1', 1)
expect(graphite).to receive(:log).with('vmpooler.running.pool1', 5)
subject._check_pool(config[:pools][0])
end
end

context 'statsd' do
let(:statsd) { double('statsd') }
let(:config) { {
config: { task_limit: 10 },
pools: [ {'name' => 'pool1', 'size' => 5} ],
statsd: { 'prefix' => 'vmpooler' }
} }
subject { Vmpooler::PoolManager.new(config, logger, redis, graphite, statsd) }

it 'increments statsd when configured' do
allow(redis).to receive(:scard).with('vmpooler__ready__pool1').and_return(1)
allow(redis).to receive(:scard).with('vmpooler__cloning__pool1').and_return(0)
allow(redis).to receive(:scard).with('vmpooler__pending__pool1').and_return(0)
allow(redis).to receive(:scard).with('vmpooler__running__pool1').and_return(5)

expect(statsd).to receive(:increment).with('vmpooler.ready.pool1', 1)
expect(statsd).to receive(:increment).with('vmpooler.running.pool1', 5)
subject._check_pool(config[:pools][0])
end
end
end

describe '#_create_vm_snapshot' do
let(:snapshot_manager) { 'snapshot_manager' }
let(:pool_helper) { double('snapshot_manager') }
Expand Down
5 changes: 4 additions & 1 deletion vmpooler
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ config = Vmpooler.config
redis_host = config[:redis]['server']
logger_file = config[:config]['logfile']
graphite = config[:graphite]['server'] ? config[:graphite]['server'] : nil
statsd = config[:statsd]['server'] ? config[:statsd]['server'] : nil
statsd_port = config[:statsd]['port'] ? config[:statsd]['port'] : 8125

api = Thread.new {
thr = Vmpooler::API.new
Expand All @@ -21,7 +23,8 @@ manager = Thread.new {
config,
Vmpooler.new_logger(logger_file),
Vmpooler.new_redis(redis_host),
Vmpooler.new_graphite(graphite)
Vmpooler.new_graphite(graphite),
Vmpooler.new_statsd(statsd, statsd_port)
).execute!
}

Expand Down
31 changes: 30 additions & 1 deletion vmpooler.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,39 @@
:redis:
server: 'redis.company.com'


# :statsd:
#
# This section contains the connection information required to store
# historical data via statsd. This is mutually exclusive with graphite
# and takes precedence.
#
# Available configuration parameters:
#
# - server
# The FQDN hostname of the statsd daemon.
# (optional)
#
# - prefix
# The prefix to use while storing statsd data.
# (optional; default: 'vmpooler')
#
# - port
# The UDP port to communicate with statsd daemon.
# (optional; default: 8125)

# Example:

:statsd:
server: 'statsd.company.com'
prefix: 'vmpooler'
port: 8125

# :graphite:
#
# This section contains the connection information required to store
# historical data in an external Graphite database.
# historical data in an external Graphite database. This is mutually exclusive
# with statsd.
#
# Available configuration parameters:
#
Expand Down

0 comments on commit 40bdd8b

Please sign in to comment.