From: Stephen Gran Date: Sun, 25 Aug 2013 14:44:32 +0000 (+0100) Subject: add rabbitmq module X-Git-Url: https://git.adam-barratt.org.uk/?a=commitdiff_plain;h=0daa0d704c7bc516b1e9a481109e881005144aee;p=mirror%2Fdsa-puppet.git add rabbitmq module Signed-off-by: Stephen Gran --- diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_plugin/default.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_plugin/default.rb new file mode 100644 index 000000000..9f71a9acd --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_plugin/default.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:rabbitmq_plugin).provide(:default) do + + def self.instances + [] + end + + def create + default_fail + end + + def destroy + default_fail + end + + def exists? + default_fail + end + + def default_fail + fail('This is just the default provider for rabbitmq_plugin, all it does is fail') + end +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb new file mode 100644 index 000000000..325fd200b --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb @@ -0,0 +1,30 @@ +Puppet::Type.type(:rabbitmq_plugin).provide(:rabbitmqplugins) do + + commands :rabbitmqplugins => '/usr/lib/rabbitmq/bin/rabbitmq-plugins' + defaultfor :feature => :posix + + def self.instances + rabbitmqplugins('list', '-E').split(/\n/).map do |line| + if line.split(/\s+/)[1] =~ /^(\S+)$/ + new(:name => $1) + else + raise Puppet::Error, "Cannot parse invalid plugins line: #{line}" + end + end + end + + def create + rabbitmqplugins('enable', resource[:name]) + end + + def destroy + rabbitmqplugins('disable', resource[:name]) + end + + def exists? + out = rabbitmqplugins('list', '-E').split(/\n/).detect do |line| + line.split(/\s+/)[1].match(/^#{resource[:name]}$/) + end + end + +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_policy/default.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_policy/default.rb new file mode 100644 index 000000000..77cb9bfbb --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_policy/default.rb @@ -0,0 +1,23 @@ +Puppet::Type.type(:rabbitmq_policy).provide(:default) do + + def self.instances + [] + end + + def create + default_fail + end + + def destroy + default_fail + end + + def exists? + default_fail + end + + def default_fail + fail('This is just the default provider for rabbitmq_policy, all it does is fail') + end +end + diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb new file mode 100644 index 000000000..8e1251038 --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb @@ -0,0 +1,39 @@ +require 'puppet' +Puppet::Type.type(:rabbitmq_policy).provide(:rabbitmqctl) do + + commands :rabbitmqctl => 'rabbitmqctl' + defaultfor :feature => :posix + + def should_vhost + if @should_vhost + @should_vhost + else + @should_vhost = resource[:vhost] + end + end + + def self.instances + rabbitmqctl('list_policies', '-p', should_vhost).split(/\n/)[1..-2].detect do |line| + if line =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+.*$/ + new(:name => $2, :vhost => $1, :match => $3, :policy => $4) + else + raise Puppet::Error, "Cannot parse invalid user line: #{line}" + end + end + end + + def create + rabbitmqctl('set_policy', '-p', should_vhost, resource[:name], resource[:match], resource[:policy]) + end + + def destroy + rabbitmqctl('clear_policy', '-p', should_vhost, resource[:name]) + end + + def exists? + out = rabbitmqctl('list_policies', '-p', should_vhost).split(/\n/)[1..-2].detect do |line| + line.match(/^\S+\s+#{resource[:name]}\s+\S+.*$/) + end + end + +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_user/default.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user/default.rb new file mode 100644 index 000000000..8915dd810 --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user/default.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:rabbitmq_user).provide(:default) do + + def self.instances + [] + end + + def create + default_fail + end + + def destroy + default_fail + end + + def exists? + default_fail + end + + def default_fail + fail('This is just the default provider for rabbitmq_user, all it does is fail') + end +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb new file mode 100644 index 000000000..fde194cc9 --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb @@ -0,0 +1,59 @@ +require 'puppet' +Puppet::Type.type(:rabbitmq_user).provide(:rabbitmqctl) do + + commands :rabbitmqctl => 'rabbitmqctl' + defaultfor :feature => :posix + + def self.instances + rabbitmqctl('list_users').split(/\n/)[1..-2].collect do |line| + if line =~ /^(\S+)(\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 + end + + def destroy + rabbitmqctl('delete_user', resource[:name]) + end + + def exists? + out = rabbitmqctl('list_users').split(/\n/)[1..-2].detect do |line| + line.match(/^#{resource[:name]}(\s+\S+|)$/) + end + end + + # def password + # def password=() + def admin + match = rabbitmqctl('list_users').split(/\n/)[1..-2].collect do |line| + line.match(/^#{resource[:name]}\s+\[(administrator)?\]/) + end.compact.first + if match + (:true if match[1].to_s == '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() + else + rabbitmqctl('set_user_tags', resource[:name]) + end + end + + def make_user_admin + rabbitmqctl('set_user_tags', resource[:name], 'administrator') + end + +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/default.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/default.rb new file mode 100644 index 000000000..42ee0d91d --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/default.rb @@ -0,0 +1,18 @@ +Puppet::Type.type(:rabbitmq_user_permissions).provide(:default) do + + def create + default_fail + end + + def destroy + default_fail + end + + def exists? + default_fail + end + + def default_fail + fail('This is just the default provider for rabbitmq_user, all it does is fail') + end +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb new file mode 100644 index 000000000..2666b4209 --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb @@ -0,0 +1,102 @@ +Puppet::Type.type(:rabbitmq_user_permissions).provide(:rabbitmqctl) do + + commands :rabbitmqctl => 'rabbitmqctl' + defaultfor :feature=> :posix + + #def self.instances + # + #end + + # cache users permissions + def self.users(name, vhost) + @users = {} unless @users + unless @users[name] + @users[name] = {} + out = rabbitmqctl('list_user_permissions', name).split(/\n/)[1..-2].each do |line| + if line =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/ + @users[name][$1] = + {:configure => $2, :read => $3, :write => $4} + else + raise Puppet::Error, "cannot parse line from list_user_permissions:#{line}" + end + end + end + @users[name][vhost] + end + + def users(name, vhost) + self.class.users(name, vhost) + end + + def should_user + if @should_user + @should_user + else + @should_user = resource[:name].split('@')[0] + end + end + + def should_vhost + if @should_vhost + @should_vhost + else + @should_vhost = resource[:name].split('@')[1] + end + end + + def create + resource[:configure_permission] ||= "''" + resource[:read_permission] ||= "''" + resource[:write_permission] ||= "''" + rabbitmqctl('set_permissions', '-p', should_vhost, should_user, resource[:configure_permission], resource[:read_permission], resource[:write_permission]) + end + + def destroy + rabbitmqctl('clear_permissions', '-p', should_vhost, should_user) + end + + # I am implementing prefetching in exists b/c I need to be sure + # that the rabbitmq package is installed before I make this call. + def exists? + users(should_user, should_vhost) + end + + def configure_permission + users(should_user, should_vhost)[:configure] + end + + def configure_permission=(perm) + set_permissions + end + + def read_permission + users(should_user, should_vhost)[:read] + end + + def read_permission=(perm) + set_permissions + end + + def write_permission + users(should_user, should_vhost)[:write] + end + + def write_permission=(perm) + set_permissions + end + + # implement memoization so that we only call set_permissions once + def set_permissions + unless @permissions_set + @permissions_set = true + resource[:configure_permission] ||= configure_permission + resource[:read_permission] ||= read_permission + resource[:write_permission] ||= write_permission + rabbitmqctl('set_permissions', '-p', should_vhost, should_user, + resource[:configure_permission], resource[:read_permission], + resource[:write_permission] + ) + end + end + +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_vhost/default.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_vhost/default.rb new file mode 100644 index 000000000..c4118176a --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_vhost/default.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:rabbitmq_vhost).provide(:default) do + + def self.instances + [] + end + + def create + default_fail + end + + def destroy + default_fail + end + + def exists? + default_fail + end + + def default_fail + fail('This is just the default provider for rabbitmq_vhost, all it does is fail') + end +end diff --git a/modules/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb b/modules/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb new file mode 100644 index 000000000..39d3c0b8a --- /dev/null +++ b/modules/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb @@ -0,0 +1,30 @@ +Puppet::Type.type(:rabbitmq_vhost).provide(:rabbitmqctl) do + + commands :rabbitmqctl => 'rabbitmqctl' + defaultfor :feature => :posix + + def self.instances + rabbitmqctl('list_vhosts').split(/\n/)[1..-2].map do |line| + if line =~ /^(\S+)$/ + new(:name => $1) + else + raise Puppet::Error, "Cannot parse invalid user line: #{line}" + end + end + end + + def create + rabbitmqctl('add_vhost', resource[:name]) + end + + def destroy + rabbitmqctl('delete_vhost', resource[:name]) + end + + def exists? + out = rabbitmqctl('list_vhosts').split(/\n/)[1..-2].detect do |line| + line.match(/^#{resource[:name]}$/) + end + end + +end diff --git a/modules/rabbitmq/lib/puppet/type/rabbitmq_plugin.rb b/modules/rabbitmq/lib/puppet/type/rabbitmq_plugin.rb new file mode 100644 index 000000000..497ced4e6 --- /dev/null +++ b/modules/rabbitmq/lib/puppet/type/rabbitmq_plugin.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:rabbitmq_plugin) do + desc 'manages rabbitmq plugins' + + ensurable do + defaultto(:present) + newvalue(:present) do + provider.create + end + newvalue(:absent) do + provider.destroy + end + end + + newparam(:name, :namevar => true) do + 'name of the plugin to enable' + newvalues(/^\S+$/) + end + +end diff --git a/modules/rabbitmq/lib/puppet/type/rabbitmq_policy.rb b/modules/rabbitmq/lib/puppet/type/rabbitmq_policy.rb new file mode 100644 index 000000000..c7fb70643 --- /dev/null +++ b/modules/rabbitmq/lib/puppet/type/rabbitmq_policy.rb @@ -0,0 +1,39 @@ +Puppet::Type.newtype(:rabbitmq_policy) do + desc 'Native type for managing rabbitmq policy' + + 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 policy' + newvalues(/^\S+$/) + end + + newparam(:vhost) do + desc 'Vhost for policy' + newvalues(/^\S+$/) + end + + newparam(:match) do + desc 'Regex match for policy' + end + + newparam(:policy) do + desc 'Policy to set' + end + + validate do + if self[:ensure] == :present and ! self[:policy] and ! self[:match] + raise ArgumentError, 'must set policy and match' unless self[:policy] and self[:match] + end + end + +end + diff --git a/modules/rabbitmq/lib/puppet/type/rabbitmq_user.rb b/modules/rabbitmq/lib/puppet/type/rabbitmq_user.rb new file mode 100644 index 000000000..9ad9c0f7c --- /dev/null +++ b/modules/rabbitmq/lib/puppet/type/rabbitmq_user.rb @@ -0,0 +1,40 @@ +Puppet::Type.newtype(:rabbitmq_user) do + desc 'Native type for managing rabbitmq users' + + 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 user' + newvalues(/^\S+$/) + end + + # newproperty(:password) do + newparam(:password) do + desc 'User password to be set *on creation*' + end + + newproperty(:admin) do + desc 'rather or not user should be an admin' + newvalues(/true|false/) + munge do |value| + # converting to_s incase its a boolean + value.to_s.to_sym + end + defaultto :false + end + + validate do + if self[:ensure] == :present and ! self[:password] + raise ArgumentError, 'must set password when creating user' unless self[:password] + end + end + +end diff --git a/modules/rabbitmq/lib/puppet/type/rabbitmq_user_permissions.rb b/modules/rabbitmq/lib/puppet/type/rabbitmq_user_permissions.rb new file mode 100644 index 000000000..427da6caa --- /dev/null +++ b/modules/rabbitmq/lib/puppet/type/rabbitmq_user_permissions.rb @@ -0,0 +1,57 @@ +Puppet::Type.newtype(:rabbitmq_user_permissions) do + desc 'Type for managing rabbitmq user permissions' + + ensurable do + defaultto(:present) + newvalue(:present) do + provider.create + end + newvalue(:absent) do + provider.destroy + end + end + + newparam(:name, :namevar => true) do + 'combination of user@vhost to grant privileges to' + newvalues(/^\S+@\S+$/) + end + + newproperty(:configure_permission) do + desc 'regexp representing configuration permissions' + validate do |value| + resource.validate_permissions(value) + end + end + + newproperty(:read_permission) do + desc 'regexp representing read permissions' + validate do |value| + resource.validate_permissions(value) + end + end + + newproperty(:write_permission) do + desc 'regexp representing write permissions' + validate do |value| + resource.validate_permissions(value) + end + end + + autorequire(:rabbitmq_vhost) do + [self[:name].split('@')[1]] + end + + autorequire(:rabbitmq_user) do + [self[:name].split('@')[0]] + end + + # I may want to dissalow whitespace + def validate_permissions(value) + begin + Regexp.new(value) + rescue RegexpError + raise ArgumentError, "Invalid regexp #{value}" + end + end + +end diff --git a/modules/rabbitmq/lib/puppet/type/rabbitmq_vhost.rb b/modules/rabbitmq/lib/puppet/type/rabbitmq_vhost.rb new file mode 100644 index 000000000..9dd0982dc --- /dev/null +++ b/modules/rabbitmq/lib/puppet/type/rabbitmq_vhost.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:rabbitmq_vhost) do + desc 'manages rabbitmq vhosts' + + ensurable do + defaultto(:present) + newvalue(:present) do + provider.create + end + newvalue(:absent) do + provider.destroy + end + end + + newparam(:name, :namevar => true) do + 'name of the vhost to add' + newvalues(/^\S+$/) + end + +end diff --git a/modules/rabbitmq/manifests/config.pp b/modules/rabbitmq/manifests/config.pp new file mode 100644 index 000000000..1bed1fee5 --- /dev/null +++ b/modules/rabbitmq/manifests/config.pp @@ -0,0 +1,16 @@ +# == Class: rabbitmq::config +# +# Sets up the rabbitmq config file +# +class rabbitmq::config { + include rabbitmq::packages + include concat::setup + + concat { '/etc/rabbitmq/rabbitmq.config': + require => Package['rabbitmq-server'], + notify => Service['rabbitmq-server'], + owner => root, + group => $::root_group, + mode => '0644', + } +} diff --git a/modules/rabbitmq/manifests/init.pp b/modules/rabbitmq/manifests/init.pp new file mode 100644 index 000000000..5e12bd4be --- /dev/null +++ b/modules/rabbitmq/manifests/init.pp @@ -0,0 +1,97 @@ +# == Class: rabbitmq +# +# Top level class for all things rabbitmq +# +class rabbitmq ( + $cluster=false, + $clustermembers=[], + $clustercookie='', + $delete_guest_user=false, + $rabbit_num_ofiles=4096, + $master='' +) { + include rabbitmq::config + + package { 'rabbitmq-server': + ensure => installed, + } + + service { 'rabbitmq-server': + ensure => running, + enable => true, + require => Package['rabbitmq-server'] + } + + Service['rabbitmq-server'] -> Rabbitmq_user <| |> + Service['rabbitmq-server'] -> Rabbitmq_vhost <| |> + Service['rabbitmq-server'] -> Rabbitmq_user_permissions <| |> + + concat::fragment { 'rabbitmq_main_conf': + target => '/etc/rabbitmq/rabbitmq.config', + order => 00, + content => template('rabbitmq/rabbitmq.conf.erb'), + } + + concat::fragment { 'rabbitmq_conf_foot': + target => '/etc/rabbitmq/rabbitmq.config', + order => 99, + content => "].\n" + } + + file { '/etc/rabbitmq/rabbitmq.conf.d/': + ensure => directory, + require => Package['rabbitmq-server'] + } + + file { '/etc/rabbitmq/rabbitmq.conf.d/ulimit.conf': + content => template('rabbitmq/rabbitmq.ulimit.erb'), + require => [ Package['rabbitmq-server'], File['/etc/rabbitmq/rabbitmq.conf.d/'] ], + notify => Service['rabbitmq-server'] + } + + if $cluster { + if $clustercookie { + file { '/var/lib/rabbitmq': + ensure => directory, + mode => '0755', + owner => rabbitmq, + group => rabbitmq, + } + + file { '/var/lib/rabbitmq/.erlang.cookie': + content => $clustercookie, + mode => '0500', + owner => rabbitmq, + group => rabbitmq, + before => Package['rabbitmq-server'], + notify => Service['rabbitmq-server'] + } + } + + if $::hostname != $master { + exec { 'reset_mq': + command => 'rabbitmqctl stop_app && rabbitmqctl reset > /var/lib/rabbitmq/.node_reset', + path => '/usr/bin:/bin:/usr/sbin:/sbin', + creates => '/var/lib/rabbitmq/.node_reset', + require => Package['rabbitmq-server'], + notify => Service['rabbitmq-server'] + } + Exec['reset_mq'] -> Rabbitmq_user <| |> + Exec['reset_mq'] -> Rabbitmq_vhost <| |> + Exec['reset_mq'] -> Rabbitmq_user_permissions <| |> + } + } + + if $delete_guest_user { + rabbitmq_user { 'guest': + ensure => absent, + provider => 'rabbitmqctl', + } + } + + site::limit { 'rabbitmq_openfiles': + limit_user => rabbitmq, + limit_value => $rabbit_num_ofiles, + notify => Service['rabbitmq-server'] + } +} diff --git a/modules/rabbitmq/manifests/packages.pp b/modules/rabbitmq/manifests/packages.pp new file mode 100644 index 000000000..00bd0b5b9 --- /dev/null +++ b/modules/rabbitmq/manifests/packages.pp @@ -0,0 +1,12 @@ +# == Class: rabbitmq::packages +# +# Installs all the rabbitmq software +# +class rabbitmq::packages { + $ensure = installed + + package { 'rabbitmq-server': + ensure => $ensure, + require => User['rabbitmq'] + } +} diff --git a/modules/rabbitmq/templates/rabbitmq.conf.erb b/modules/rabbitmq/templates/rabbitmq.conf.erb new file mode 100644 index 000000000..46d3ee9be --- /dev/null +++ b/modules/rabbitmq/templates/rabbitmq.conf.erb @@ -0,0 +1,4 @@ +[ +<% if scope.lookupvar('cluster') -%> +{rabbit, [{cluster_nodes, ['<%= scope.lookupvar('clustermembers').to_a.flatten.join("', '") %>']}]} +<% end -%> diff --git a/modules/rabbitmq/templates/rabbitmq.ulimit.erb b/modules/rabbitmq/templates/rabbitmq.ulimit.erb new file mode 100644 index 000000000..813f5000f --- /dev/null +++ b/modules/rabbitmq/templates/rabbitmq.ulimit.erb @@ -0,0 +1 @@ +ulimit -n <%= scope.lookupvar('rabbit_num_ofiles') %> diff --git a/modules/rabbitmq/tests/config.pp b/modules/rabbitmq/tests/config.pp new file mode 100644 index 000000000..36f5915af --- /dev/null +++ b/modules/rabbitmq/tests/config.pp @@ -0,0 +1,7 @@ +class rabbitmq::packages { + package { 'rabbitmq-server': } + service { 'rabbitmq-server': } +} +class concat::setup {} + +include rabbitmq::config diff --git a/modules/rabbitmq/tests/init.pp b/modules/rabbitmq/tests/init.pp new file mode 100644 index 000000000..01ac11fd1 --- /dev/null +++ b/modules/rabbitmq/tests/init.pp @@ -0,0 +1,6 @@ +class site::users::system::rabbitmq {} +class rabbitmq::config {} +class rabbitmq::packages { + package { 'rabbitmq-server': } +} +include rabbitmq diff --git a/modules/rabbitmq/tests/packages.pp b/modules/rabbitmq/tests/packages.pp new file mode 100644 index 000000000..b1101b99e --- /dev/null +++ b/modules/rabbitmq/tests/packages.pp @@ -0,0 +1,7 @@ +class site::aptrepo::rabbitmq {} +class site::yumrepo::rabbitmq {} +class site::users::system::rabbitmq { + user { 'rabbitmq': } +} +include rabbitmq::packages +