+require 'puppet'
+require 'set'
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmqctl'))
-Puppet::Type.type(:rabbitmq_user).provide(
- :rabbitmqctl,
- parent: Puppet::Provider::Rabbitmqctl
-) do
- has_command(:rabbitmqctl, 'rabbitmqctl') do
- environment HOME: '/tmp'
- end
-
- confine feature: :posix
+Puppet::Type.type(:rabbitmq_user).provide(:rabbitmqctl, :parent => Puppet::Provider::Rabbitmqctl) do
- def initialize(value = {})
- super(value)
- @property_flush = {}
+ if Puppet::PUPPETVERSION.to_f < 3
+ commands :rabbitmqctl => 'rabbitmqctl'
+ else
+ has_command(:rabbitmqctl, 'rabbitmqctl') do
+ environment :HOME => "/tmp"
+ end
end
+ defaultfor :feature => :posix
+
def self.instances
- user_list = run_with_retries do
+ self.run_with_retries {
rabbitmqctl('-q', 'list_users')
- end
-
- user_list.split(%r{\n}).map do |line|
- raise Puppet::Error, "Cannot parse invalid user line: #{line}" unless line =~ %r{^(\S+)\s+\[(.*?)\]$}
- user = Regexp.last_match(1)
- tags = Regexp.last_match(2).split(%r{,\s*})
- new(
- ensure: :present,
- name: user,
- tags: tags
- )
+ }.split(/\n/).collect do |line|
+ if line =~ /^(\S+)(\s+\[.*?\]|)$/
+ new(:name => $1)
+ else
+ raise Puppet::Error, "Cannot parse invalid user line: #{line}"
+ end
end
end
- def self.prefetch(resources)
- users = instances
- resources.each_key do |user|
- if (provider = users.find { |u| u.name == user })
- resources[user].provider = provider
- end
+ def create
+ rabbitmqctl('add_user', resource[:name], resource[:password])
+ if resource[:admin] == :true
+ make_user_admin()
+ end
+ if ! resource[:tags].empty?
+ set_user_tags(resource[:tags])
end
end
- def exists?
- @property_hash[:ensure] == :present
+ def change_password
+ rabbitmqctl('change_password', resource[:name], resource[:password])
end
- def create
- # Fail here (rather than a validate block in the type) if password is not
- # set, so that "puppet resource" still works.
- raise Puppet::Error, "Password is a required parameter for rabbitmq_user (user: #{name})" if @resource[:password].nil?
-
- rabbitmqctl('add_user', @resource[:name], @resource[:password])
+ def password
+ nil
+ end
- tags = @resource[:tags]
- tags << admin_tag if @resource[:admin] == :true
- rabbitmqctl('set_user_tags', @resource[:name], tags) unless tags.empty?
- @property_hash[:ensure] = :present
+ def check_password
+ response = rabbitmqctl('eval', 'rabbit_access_control:check_user_pass_login(list_to_binary("' + resource[:name] + '"), list_to_binary("' + resource[:password] +'")).')
+ if response.include? 'refused'
+ false
+ else
+ true
+ end
end
def destroy
- rabbitmqctl('delete_user', @resource[:name])
- @property_hash[:ensure] = :absent
+ rabbitmqctl('delete_user', resource[:name])
end
- def password=(password)
- rabbitmqctl('change_password', @resource[:name], password)
+ def exists?
+ self.class.run_with_retries {
+ rabbitmqctl('-q', 'list_users')
+ }.split(/\n/).detect do |line|
+ line.match(/^#{Regexp.escape(resource[:name])}(\s+(\[.*?\]|\S+)|)$/)
+ end
end
- def password; end
-
- def check_password(password)
- check_access_control = [
- 'rabbit_access_control:check_user_pass_login(',
- %[list_to_binary("#{@resource[:name]}"), ],
- %[list_to_binary("#{password}")).]
- ]
-
- response = rabbitmqctl('eval', check_access_control.join)
- !response.include? 'refused'
- end
def tags
+ tags = get_user_tags
# do not expose the administrator tag for admins
- @property_hash[:tags].reject { |tag| tag == admin_tag }
+ if resource[:admin] == :true
+ tags.delete('administrator')
+ end
+ tags.entries.sort
end
+
def tags=(tags)
- @property_flush[:tags] = tags
+ if ! tags.nil?
+ set_user_tags(tags)
+ end
end
def admin
- usertags = get_user_tags
- raise Puppet::Error, "Could not match line '#{resource[:name]} (true|false)' from list_users (perhaps you are running on an older version of rabbitmq that does not support admin users?)" unless usertags
- (:true if usertags.include?('administrator')) || :false
+ if usertags = get_user_tags
+ (:true if usertags.include?('administrator')) || :false
+ else
+ raise Puppet::Error, "Could not match line '#{resource[:name]} (true|false)' from list_users (perhaps you are running on an older version of rabbitmq that does not support admin users?)"
+ end
end
def admin=(state)
if state == :true
- make_user_admin
+ make_user_admin()
else
usertags = get_user_tags
usertags.delete('administrator')
end
end
- def admin
- @property_hash[:tags].include?(admin_tag) ? :true : :false
- end
-
- def admin=(state)
- @property_flush[:admin] = state
+ def set_user_tags(tags)
+ is_admin = get_user_tags().member?("administrator") \
+ || resource[:admin] == :true
+ usertags = Set.new(tags)
+ if is_admin
+ usertags.add("administrator")
+ end
+ rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort)
end
- def flush
- return if @property_flush.empty?
- tags = @property_flush[:tags] || @resource[:tags]
- tags << admin_tag if @resource[:admin] == :true
- rabbitmqctl('set_user_tags', @resource[:name], tags)
- @property_flush.clear
+ def make_user_admin
+ usertags = get_user_tags
+ usertags.add('administrator')
+ rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort)
end
private
-
- def admin_tag
- 'administrator'
+ def get_user_tags
+ match = rabbitmqctl('-q', 'list_users').split(/\n/).collect do |line|
+ line.match(/^#{Regexp.escape(resource[:name])}\s+\[(.*?)\]/)
+ end.compact.first
+ Set.new(match[1].split(' ').map{|x| x.gsub(/,$/, '')}) if match
end
end