Skip to content

Commit

Permalink
Add new resource rabbitmq_queue
Browse files Browse the repository at this point in the history
  • Loading branch information
ironpinguin authored and globin committed Dec 22, 2014
1 parent 04145c1 commit ebc20c2
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 0 deletions.
105 changes: 105 additions & 0 deletions lib/puppet/provider/rabbitmq_queue/rabbitmqadmin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
require 'json'
require 'puppet'
Puppet::Type.type(:rabbitmq_queue).provide(:rabbitmqadmin) do

if Puppet::PUPPETVERSION.to_f < 3
commands :rabbitmqctl => 'rabbitmqctl'
commands :rabbitmqadmin => '/usr/local/bin/rabbitmqadmin'
else
has_command(:rabbitmqctl, 'rabbitmqctl') do
environment :HOME => "/tmp"
end
has_command(:rabbitmqadmin, '/usr/local/bin/rabbitmqadmin') do
environment :HOME => "/tmp"
end
end
defaultfor :feature => :posix

def should_vhost
if @should_vhost
@should_vhost
else
@should_vhost = resource[:name].rpartition('@').last
end
end

def self.all_vhosts
vhosts = []
rabbitmqctl('list_vhosts', '-q').split(/\n/).collect do |vhost|
vhosts.push(vhost)
end
vhosts
end

def self.all_queues(vhost)
rabbitmqctl('list_queues', '-q', '-p', vhost, 'name', 'durable', 'auto_delete', 'arguments').split(/\n/)
end

def self.instances
resources = []
all_vhosts.each do |vhost|
all_queues(vhost).collect do |line|
name, durable, auto_delete, arguments = line.split()
# Convert output of arguments from the rabbitmqctl command to a json string.
if !arguments.nil?
arguments = arguments.gsub(/^\[(.*)\]$/, "").gsub(/\{("(?:.|\\")*?"),/, '{\1:').gsub(/\},\{/, ",")
if arguments == ""
arguments = '{}'
end
else
arguments = '{}'
end
queue = {
:durable => durable,
:auto_delete => auto_delete,
:arguments => JSON.parse(arguments),
:ensure => :present,
:name => "%s@%s" % [name, vhost],
}
resources << new(queue) if queue[:name]
end
end
resources
end

def self.prefetch(resources)
packages = instances
resources.keys.each do |name|
if provider = packages.find{ |pkg| pkg.name == name }
resources[name].provider = provider
end
end
end

def exists?
@property_hash[:ensure] == :present
end

def create
vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : ''
name = resource[:name].rpartition('@').first
arguments = resource[:arguments]
if arguments.nil?
arguments = {}
end
rabbitmqadmin('declare',
'queue',
vhost_opt,
"--user=#{resource[:user]}",
"--password=#{resource[:password]}",
"name=#{name}",
"durable=#{resource[:durable]}",
"auto_delete=#{resource[:auto_delete]}",
"arguments=#{arguments.to_json}"
)
@property_hash[:ensure] = :present
end

def destroy
vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : ''
name = resource[:name].rpartition('@').first
rabbitmqadmin('delete', 'queue', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}")
@property_hash[:ensure] = :absent
end

end
68 changes: 68 additions & 0 deletions lib/puppet/type/rabbitmq_queue.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Puppet::Type.newtype(:rabbitmq_queue) do
desc 'Native type for managing rabbitmq queue'

ensurable do
defaultto(:present)
newvalue(:present) do
provider.create
end
newvalue(:absent) do
provider.destroy
end
end

newparam(:name, :namevar => true) do
desc 'Name of queue'
newvalues(/^\S*@\S+$/)
end

newparam(:durable) do
desc 'Queue is durable'
newvalues(/true|false/)
defaultto('true')
end

newparam(:auto_delete) do
desc 'Queue will be auto deleted'
newvalues(/true|false/)
defaultto('false')
end

newparam(:arguments) do
desc 'Queue arguments example: {x-message-ttl => 60, x-expires => 10}'
defaultto {}
validate do |value|
resource.validate_argument(value)
end
end

newparam(:user) do
desc 'The user to use to connect to rabbitmq'
defaultto('guest')
newvalues(/^\S+$/)
end

newparam(:password) do
desc 'The password to use to connect to rabbitmq'
defaultto('guest')
newvalues(/\S+/)
end

autorequire(:rabbitmq_vhost) do
[self[:name].split('@')[1]]
end

autorequire(:rabbitmq_user) do
[self[:user]]
end

autorequire(:rabbitmq_user_permissions) do
["#{self[:user]}@#{self[:name].split('@')[1]}"]
end

def validate_argument(argument)
unless [Hash].include?(argument.class)
raise ArgumentError, "Invalid argument"
end
end
end
60 changes: 60 additions & 0 deletions spec/unit/puppet/provider/rabbitmq_queue/rabbitmqadmin_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'puppet'
require 'mocha/api'
RSpec.configure do |config|
config.mock_with :mocha
end
provider_class = Puppet::Type.type(:rabbitmq_queue).provider(:rabbitmqadmin)
describe provider_class do
before :each do
@resource = Puppet::Type::Rabbitmq_queue.new(
{:name => 'test@/',
:durable => :true,
:auto_delete => :false,
:arguments => {}
}
)
@provider = provider_class.new(@resource)
end

it 'should return instances' do
provider_class.expects(:rabbitmqctl).with('list_vhosts', '-q').returns <<-EOT
/
EOT
provider_class.expects(:rabbitmqctl).with('list_queues', '-q', '-p', '/', 'name', 'durable', 'auto_delete', 'arguments').returns <<-EOT
test true false []
test2 true false [{"x-message-ttl",342423},{"x-expires",53253232},{"x-max-length",2332},{"x-max-length-bytes",32563324242},{"x-dead-letter-exchange","amq.direct"},{"x-dead-letter-routing-key","test.routing"}]
EOT
instances = provider_class.instances
instances.size.should == 2
end

it 'should call rabbitmqadmin to create' do
@provider.expects(:rabbitmqadmin).with('declare', 'queue', '--vhost=/', '--user=guest', '--password=guest', 'name=test', 'durable=true', 'auto_delete=false', 'arguments={}')
@provider.create
end

it 'should call rabbitmqadmin to destroy' do
@provider.expects(:rabbitmqadmin).with('delete', 'queue', '--vhost=/', '--user=guest', '--password=guest', 'name=test')
@provider.destroy
end

context 'specifying credentials' do
before :each do
@resource = Puppet::Type::Rabbitmq_queue.new(
{:name => 'test@/',
:durable => 'true',
:auto_delete => 'false',
:arguments => {},
:user => 'colin',
:password => 'secret',
}
)
@provider = provider_class.new(@resource)
end

it 'should call rabbitmqadmin to create' do
@provider.expects(:rabbitmqadmin).with('declare', 'queue', '--vhost=/', '--user=colin', '--password=secret', 'name=test', 'durable=true', 'auto_delete=false', 'arguments={}')
@provider.create
end
end
end
60 changes: 60 additions & 0 deletions spec/unit/puppet/type/rabbitmq_queue_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'puppet'
require 'puppet/type/rabbitmq_queue'
require 'json'
describe Puppet::Type.type(:rabbitmq_queue) do
before :each do
@queue = Puppet::Type.type(:rabbitmq_queue).new(
:name => 'foo@bar',
:durable => :true,
:arguments => {
'x-message-ttl' => 45,
'x-dead-letter-exchange' => 'deadexchange'
}
)
end
it 'should accept an queue name' do
@queue[:name] = 'dan@pl'
@queue[:name].should == 'dan@pl'
end
it 'should require a name' do
expect {
Puppet::Type.type(:rabbitmq_queue).new({})
}.to raise_error(Puppet::Error, 'Title or name must be provided')
end
it 'should not allow whitespace in the name' do
expect {
@queue[:name] = 'b r'
}.to raise_error(Puppet::Error, /Valid values match/)
end
it 'should not allow names without @' do
expect {
@queue[:name] = 'b_r'
}.to raise_error(Puppet::Error, /Valid values match/)
end

it 'should accept an arguments with numbers value' do
@queue[:arguments] = {'x-message-ttl' => 30}
@queue[:arguments].to_json.should == "{\"x-message-ttl\":30}"
@queue[:arguments]['x-message-ttl'].should == 30
end

it 'should accept an arguments with string value' do
@queue[:arguments] = {'x-dead-letter-exchange' => 'catchallexchange'}
@queue[:arguments].to_json.should == "{\"x-dead-letter-exchange\":\"catchallexchange\"}"
end

it 'should accept an queue durable' do
@queue[:durable] = :true
@queue[:durable].should == :true
end

it 'should accept a user' do
@queue[:user] = :root
@queue[:user].should == :root
end

it 'should accept a password' do
@queue[:password] = :PaSsw0rD
@queue[:password].should == :PaSsw0rD
end
end

0 comments on commit ebc20c2

Please sign in to comment.