-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
-
- if Puppet::PUPPETVERSION.to_f < 3
- commands :rabbitmqctl => 'rabbitmqctl'
- else
- has_command(:rabbitmqctl, 'rabbitmqctl') do
- environment :HOME => "/tmp"
- end
+Puppet::Type.type(:rabbitmq_user).provide(
+ :rabbitmqctl,
+ parent: Puppet::Provider::Rabbitmqctl
+) do
+ has_command(:rabbitmqctl, 'rabbitmqctl') do
+ environment HOME: '/tmp'
end
- defaultfor :feature => :posix
+ confine feature: :posix
+
+ def initialize(value = {})
+ super(value)
+ @property_flush = {}
+ end
def self.instances
- self.run_with_retries {
+ user_list = run_with_retries do
rabbitmqctl('-q', 'list_users')
- }.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 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])
+ 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
+ )
end
end
- def change_password
- rabbitmqctl('change_password', resource[:name], resource[:password])
+ def self.prefetch(resources)
+ users = instances
+ resources.each_key do |user|
+ if (provider = users.find { |u| u.name == user })
+ resources[user].provider = provider
+ end
+ end
end
- def password
- nil
+ def exists?
+ @property_hash[:ensure] == :present
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?
- 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
+ rabbitmqctl('add_user', @resource[:name], @resource[:password])
+
+ tags = @resource[:tags]
+ tags << admin_tag if @resource[:admin] == :true
+ rabbitmqctl('set_user_tags', @resource[:name], tags) unless tags.empty?
+
+ @property_hash[:ensure] = :present
end
def destroy
- rabbitmqctl('delete_user', resource[:name])
+ rabbitmqctl('delete_user', @resource[:name])
+ @property_hash[:ensure] = :absent
end
- 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
+ def password=(password)
+ rabbitmqctl('change_password', @resource[:name], password)
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
- if resource[:admin] == :true
- tags.delete('administrator')
- end
- tags.entries.sort
+ @property_hash[:tags].reject { |tag| tag == admin_tag }
end
-
def tags=(tags)
- if ! tags.nil?
- set_user_tags(tags)
- end
+ @property_flush[:tags] = tags
end
def admin
- 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
+ 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
end
def admin=(state)
if state == :true
- make_user_admin()
+ make_user_admin
else
usertags = get_user_tags
usertags.delete('administrator')
end
end
- 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)
+ def admin
+ @property_hash[:tags].include?(admin_tag) ? :true : :false
end
- def make_user_admin
- usertags = get_user_tags
- usertags.add('administrator')
- rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort)
+ def admin=(state)
+ @property_flush[:admin] = state
+ 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
end
private
- 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
+
+ def admin_tag
+ 'administrator'
end
end