Update rabbitmq module
[mirror/dsa-puppet.git] / 3rdparty / modules / rabbitmq / lib / puppet / provider / rabbitmq_user / rabbitmqctl.rb
index da37886..9eab0dd 100644 (file)
-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')
@@ -100,27 +105,25 @@ Puppet::Type.type(:rabbitmq_user).provide(:rabbitmqctl, :parent => Puppet::Provi
     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