diff --git a/Puppetfile b/Puppetfile index c9eb4b267..57e377c25 100644 --- a/Puppetfile +++ b/Puppetfile @@ -143,7 +143,7 @@ mod 'qpid', :git => 'https://github.com/dprince/puppet-qpid' mod 'rabbitmq', - :commit => '4832bd61b5b1bfea7c9cc985508e65cd10081652', + :commit => '654f3433aaa3c7abaebb0fb2c4574e1ce5da0fcb', :git => 'https://github.com/puppetlabs/puppetlabs-rabbitmq.git' mod 'redis', diff --git a/rabbitmq/.travis.yml b/rabbitmq/.travis.yml index a40ae502e..0618715a1 100644 --- a/rabbitmq/.travis.yml +++ b/rabbitmq/.travis.yml @@ -1,14 +1,10 @@ --- language: ruby -bundler_args: --without development +bundler_args: --without system_tests script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'" matrix: fast_finish: true include: - - rvm: 1.8.7 - env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.6.0" - - rvm: 1.8.7 - env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0" - rvm: 1.9.3 env: PUPPET_GEM_VERSION="~> 3.0" - rvm: 2.0.0 diff --git a/rabbitmq/CHANGELOG b/rabbitmq/CHANGELOG.md similarity index 61% rename from rabbitmq/CHANGELOG rename to rabbitmq/CHANGELOG.md index 72f74ae25..e254a9c91 100644 --- a/rabbitmq/CHANGELOG +++ b/rabbitmq/CHANGELOG.md @@ -1,18 +1,72 @@ -2014-08-20 - Version 4.1.0 - -Summary: +## 2014-12-22 - Version 5.0.0 + +### Summary + +This release fixes a longstanding security issue where the rabbitmq +erlang cookie was exposed as a fact by managing the cookie with a +provider. It also drops support for Puppet 2.7, adds many features +and fixes several bugs. + +#### Backwards-incompatible Changes + +- Removed the rabbitmq_erlang_cookie fact and replaced the logic to + manage that cookie with a provider. +- Dropped official support for Puppet 2.7 (EOL 9/30/2014 + https://groups.google.com/forum/#!topic/puppet-users/QLguMcLraLE ) +- Changed the default value of $rabbitmq::params::ldap_user_dn_pattern + to not contain a variable +- Removed deprecated parameters: $rabbitmq::cluster_disk_nodes, + $rabbitmq::server::manage_service, and + $rabbitmq::server::config_mirrored_queues + +#### Features + +- Add tcp_keepalive parameter to enable TCP keepalive +- Use https to download rabbitmqadmin tool when $rabbitmq::ssl is true +- Add key_content parameter for offline Debian package installations +- Use 16 character apt key to avoid potential collisions +- Add rabbitmq_policy type, including support for rabbitmq <3.2.0 +- Add rabbitmq::ensure_repo parameter +- Add ability to change rabbitmq_user password +- Allow disk as a valid cluster node type + +#### Bugfixes + +- Avoid attempting to install rabbitmqadmin via a proxy (since it is + downloaded from localhost) +- Optimize check for RHEL GPG key +- Configure ssl_listener in stomp only if using ssl +- Use rpm as default package provider for RedHat, bringing the module in + line with the documented instructions to manage erlang separately and allowing + the default version and source parameters to become meaningful +- Configure cacertfile only if verify_none is not set +- Use -q flag for rabbitmqctl commands to avoid parsing inconsistent + debug output +- Use the -m flag for rabbitmqplugins commands, again to avoid parsing + inconsistent debug output +- Strip backslashes from the rabbitmqctl output to avoid parsing issues +- Fix limitation where version parameter was ignored +- Add /etc/rabbitmq/rabbitmqadmin.conf to fix rabbitmqadmin port usage + when ssl is on +- Fix linter errors and warnings +- Add, update, and fix tests +- Update docs + +## 2014-08-20 - Version 4.1.0 + +### Summary This release adds several new features, fixes bugs, and improves tests and documentation. -Features: +#### Features - Autorequire the rabbitmq-server service in the rabbitmq_vhost type - Add credentials to rabbitmqadmin URL - Added $ssl_only parameter to rabbitmq, rabbitmq::params, and rabbitmq::config - Added property tags to rabbitmq_user provider -Bugfixes: +#### Bugfixes - Fix erroneous commas in rabbitmq::config - Use correct ensure value for the rabbitmq_stomp rabbitmq_plugin - Set HOME env variable to nil when leveraging rabbitmq to remove type error @@ -22,18 +76,18 @@ from Python script - Allow LDAP auth configuration without configuring stomp - Added missing $ssl_verify and $ssl_fail_if_no_peer_cert to rabbitmq::config -2014-05-16 - Version 4.0.0 +## 2014-05-16 - Version 4.0.0 -Summary: +### Summary This release includes many new features and bug fixes. With the exception of erlang management this should be backwards compatible with 3.1.0. -Backwards-incompatible Changes: +#### Backwards-incompatible Changes - erlang_manage was removed. You will need to manage erlang separately. See the README for more information on how to configure this. -Features: +#### Features - Improved SSL support - Add LDAP support - Add ability to manage RabbitMQ repositories @@ -45,7 +99,7 @@ Features: - Allow empty permission fields - Convert existing system tests to beaker acceptance tests. -Bugfixes: +#### Bugfixes - exchanges no longer recreated on each puppet run if non-default vhost is used - Allow port to be UNSET - Re-added rabbitmq::server class @@ -59,40 +113,43 @@ Bugfixes: rabbitmq::install -2013-09-14 - Version 3.1.0 +## 2013-09-14 - Version 3.1.0 -Summary: +### Summary This release focuses on a few small (but critical) bugfixes as well as extends the amount of custom RabbitMQ configuration you can do with the module. -Features: +#### Features - You can now change RabbitMQ 'Config Variables' via the parameter `config_variables`. - You can now change RabbitMQ 'Environment Variables' via the parameter `environment_variables`. - ArchLinux support added. -Fixes: +#### Fixes - Make use of the user/password parameters in rabbitmq_exchange{} - Correct the read/write parameter order on set_permissions/list_permissions as they were reversed. - Make the module pull down 3.1.5 by default. -* 2013-07-18 3.0.0 -Summary: +## 2013-07-18 3.0.0 + +### Summary + This release heavily refactors the RabbitMQ and changes functionality in several key ways. Please pay attention to the new README.md file for details of how to interact with the class now. Puppet 3 and RHEL are now fully supported. The default version of RabbitMQ has changed to a 3.x release. -Bugfixes: +#### Bugfixes + - Improve travis testing options. - Stop reimporting the GPG key on every run on RHEL and Debian. - Fix documentation to make it clear you don't have to set provider => each time. - Reference the standard rabbitmq port in the documentation instead of a custom port. - Fixes to the README formatting. -Features: +#### Features - Refactor the module to fix RHEL support. All interaction with the module is now done through the main rabbitmq class. - Add support for mirrored queues (Only on Debian family distributions currently) @@ -101,39 +158,41 @@ is now done through the main rabbitmq class. - `manage_service`: Boolean to choose if Puppet should manage the service. (For pacemaker/HA setups) - Add SuSE support. -Incompatible Changes: +#### Incompatible Changes + - Rabbitmq::server has been removed and is now rabbitmq::config. You should not use this class directly, only via the main rabbitmq class. -* 2013-04-11 2.1.0 +## 2013-04-11 2.1.0 + - remove puppetversion from rabbitmq.config template - add cluster support - escape resource names in regexp -* 2012-07-31 Jeff McCune 2.0.2 +## 2012-07-31 Jeff McCune 2.0.2 - Re-release 2.0.1 with $EDITOR droppings cleaned up -* 2012-05-03 2.0.0 +## 2012-05-03 2.0.0 - added support for new-style admin users - added support for rabbitmq 2.7.1 -* 2011-06-14 Dan Bode 2.0.0rc1 +## 2011-06-14 Dan Bode 2.0.0rc1 - Massive refactor: - added native types for user/vhost/user_permissions - added apt support for vendor packages - added smoke tests -* 2011-04-08 Jeff McCune 1.0.4 +## 2011-04-08 Jeff McCune 1.0.4 - Update module for RabbitMQ 2.4.1 and rabbitmq-plugin-stomp package. -2011-03-24 1.0.3 +## 2011-03-24 1.0.3 - Initial release to the forge. Reviewed by Cody. Whitespace is good. -2011-03-22 1.0.2 +## 2011-03-22 1.0.2 - Whitespace only fix again... ack '\t' is my friend... -2011-03-22 1.0.1 +## 2011-03-22 1.0.1 - Whitespace only fix. -2011-03-22 1.0.0 +## 2011-03-22 1.0.0 - Initial Release. Manage the package, file and service. diff --git a/rabbitmq/Gemfile b/rabbitmq/Gemfile index 02e632165..12fd363ea 100644 --- a/rabbitmq/Gemfile +++ b/rabbitmq/Gemfile @@ -1,14 +1,18 @@ -source 'https://rubygems.org' +source ENV['GEM_SOURCE'] || "https://rubygems.org" -group :development, :test do - gem 'rake', '10.1.1', :require => false - gem 'rspec-puppet', '>=1.0.0', :require => false +group :development, :unit_tests do + gem 'rake', :require => false + gem 'rspec-puppet', :require => false gem 'puppetlabs_spec_helper', :require => false gem 'puppet-lint', :require => false - gem 'serverspec', :require => false - gem 'beaker', :require => false - gem 'beaker-rspec', :require => false - gem 'pry', :require => false + gem 'simplecov', :require => false + gem 'puppet_facts', :require => false + gem 'json', :require => false +end + +group :system_tests do + gem 'beaker-rspec', :require => false + gem 'serverspec', :require => false end if facterversion = ENV['FACTER_GEM_VERSION'] diff --git a/rabbitmq/README.md b/rabbitmq/README.md index ebf879083..258f9bf13 100644 --- a/rabbitmq/README.md +++ b/rabbitmq/README.md @@ -36,6 +36,7 @@ all features against earlier versions. ###Beginning with rabbitmq + ```puppet include '::rabbitmq' ``` @@ -83,8 +84,8 @@ To use RabbitMQ Environment Variables, use the parameters `environment_variables class { 'rabbitmq': port => '5672', environment_variables => { - 'RABBITMQ_NODENAME' => 'node01', - 'RABBITMQ_SERVICENAME' => 'RabbitMQ' + 'NODENAME' => 'node01', + 'SERVICENAME' => 'RabbitMQ' } } ``` @@ -122,9 +123,11 @@ To use RabbitMQ clustering facilities, use the rabbitmq parameters ```puppet class { 'rabbitmq': - config_cluster => true, - cluster_nodes => ['rabbit1', 'rabbit2'], - cluster_node_type => 'ram', + config_cluster => true, + cluster_nodes => ['rabbit1', 'rabbit2'], + cluster_node_type => 'ram', + erlang_cookie => 'A_SECRET_COOKIE_STRING', + wipe_db_on_cookie_change => true, } ``` @@ -138,7 +141,7 @@ class { 'rabbitmq': * rabbitmq::params: Different configuration data for different systems. * rabbitmq::service: Handles the rabbitmq service. * rabbitmq::repo::apt: Handles apt repo for Debian systems. -* rabbitmq::repo::rhel: Handles yum repo for Redhat systems. +* rabbitmq::repo::rhel: Handles rpm repo for Redhat systems. ###Parameters @@ -146,10 +149,6 @@ class { 'rabbitmq': Boolean, if enabled sets up the management interface/plugin for RabbitMQ. -####`cluster_disk_nodes` - -DEPRECATED AND REPLACED BY CLUSTER_NODES. - ####`cluster_node_type` Choose between disk and ram nodes. @@ -221,6 +220,7 @@ RabbitMQ Environment Variables in rabbitmq_env.config ####`erlang_cookie` The erlang cookie to use for clustering - must be the same between all nodes. +This value has no default and must be set explicitly if using clustering. ###`key_content` @@ -261,7 +261,7 @@ The port for the RabbitMQ management interface. ####`node_ip_address` -The value of RABBITMQ_NODE_IP_ADDRESS in rabbitmq_env.config +The value of NODE_IP_ADDRESS in rabbitmq_env.config ####`package_ensure` @@ -271,7 +271,7 @@ be changed to latest. ####`package_gpg_key` RPM package GPG key to import. Uses source method. Should be a URL for Debian/RedHat -OS family, or a file name for RedHat OS family. +OS family, or a file name for RedHat OS family. Set to http://www.rabbitmq.com/rabbitmq-signing-key-public.asc by default. Note, that `key_content`, if specified, would override this parameter for Debian OS family. @@ -287,6 +287,12 @@ What provider to use to install the package. Where should the package be installed from? +On Debian- and Arch-based systems using the default package provider, +this parameter is ignored and the package is installed from the +rabbitmq repository, if enabled with manage_repo => true, or from the +system repository otherwise. If you want to use dpkg as the +package_provider, you must specify a local package_source. + ####`plugin_dir` Location of RabbitMQ plugins. @@ -314,7 +320,7 @@ Configures the service for using SSL. ####`ssl_only` Configures the service to only use SSL. No cleartext TCP listeners will be created. -Requires that ssl => true also. +Requires that ssl => true and port => UNSET also ####`ssl_cacert` @@ -344,6 +350,12 @@ rabbitmq.config SSL verify setting. rabbitmq.config `fail_if_no_peer_cert` setting. +####`ssl_versions` + +Choose which SSL versions to enable. Example: `['tlsv1.2', 'tlsv1.1']`. + +Note that it is recommended to disable `sslv3` and `tlsv1` to prevent against POODLE and BEAST attacks. Please see the [RabbitMQ SSL](https://www.rabbitmq.com/ssl.html) documentation for more information. + ####`stomp_port` The port to use for Stomp. @@ -360,6 +372,11 @@ Boolean to enable TCP connection keepalive for RabbitMQ service. Sets the version to install. +On Debian- and Arch-based operating systems, the version parameter is +ignored and the latest version is installed from the rabbitmq +repository, if enabled with manage_repo => true, or from the system +repository otherwise. + ####`wipe_db_on_cookie_change` Boolean to determine if we should DESTROY AND DELETE the RabbitMQ database. @@ -408,6 +425,35 @@ rabbitmq_exchange { 'myexchange@myhost': } ``` +### rabbitmq\_queue + +```puppet +rabbitmq_queue { 'myqueue@myhost': + user => 'dan', + password => 'bar', + durable => true, + auto_delete => false, + arguments => { + x-message-ttl => 123, + x-dead-letter-exchange => 'other' + }, + ensure => present, +} +``` + +### rabbitmq\_binding + +```puppet +rabbitmq_binding { 'myexchange@myqueue@myhost': + user => 'dan', + password => 'bar', + destination_type => 'queue', + routing_key => '#', + arguments => {}, + ensure => present, +} +``` + ### rabbitmq\_user\_permissions ```puppet @@ -418,6 +464,20 @@ rabbitmq_user_permissions { 'dan@myhost': } ``` +### rabbitmq\_policy + +```puppet +rabbitmq_policy { 'ha-all@myhost': + pattern => '.*', + priority => 0, + applyto => 'all', + definition => { + 'ha-mode' => 'all', + 'ha-sync-mode' => 'automatic', + }, +} +``` + ### rabbitmq\_plugin query all currently enabled plugins `$ puppet resource rabbitmq_plugin` @@ -428,20 +488,33 @@ rabbitmq_plugin {'rabbitmq_stomp': } ``` +### rabbitmq\_erlang\_cookie + +This is essentially a private type used by the rabbitmq::config class +to manage the erlang cookie. It replaces the rabbitmq_erlang_cookie fact +from earlier versions of this module. It manages the content of the cookie +usually located at /var/lib/rabbitmq/.erlang.cookie, which includes +stopping the rabbitmq service and wiping out the database at +/var/lib/rabbitmq/mnesia if the user agrees to it. We don't recommend using +this type directly. + ##Limitations -This module has been built on and tested against Puppet 2.7 and higher. +This module has been built on and tested against Puppet 3.x. The module has been tested on: * RedHat Enterprise Linux 5/6 * Debian 6/7 * CentOS 5/6 -* Ubuntu 12.04 +* Ubuntu 12.04/14.04 Testing on other platforms has been light and cannot be guaranteed. ### Module dependencies + +If running CentOS/RHEL, and using the yum provider, ensure the epel repo is present. + To have a suitable erlang version installed on RedHat and Debian systems, you have to install another puppet module from http://forge.puppetlabs.com/garethr/erlang with: diff --git a/rabbitmq/Rakefile b/rabbitmq/Rakefile index 5868545f2..558b57a1e 100644 --- a/rabbitmq/Rakefile +++ b/rabbitmq/Rakefile @@ -7,4 +7,5 @@ PuppetLint.configuration.send('disable_class_inherits_from_params_class') PuppetLint.configuration.send('disable_class_parameter_defaults') PuppetLint.configuration.send('disable_documentation') PuppetLint.configuration.send('disable_single_quote_string_with_variables') +PuppetLint.configuration.fail_on_warnings = true PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] diff --git a/rabbitmq/lib/facter/rabbitmq_erlang_cookie.rb b/rabbitmq/lib/facter/rabbitmq_erlang_cookie.rb deleted file mode 100644 index 474e12885..000000000 --- a/rabbitmq/lib/facter/rabbitmq_erlang_cookie.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Fact: rabbitmq_erlang_cookie -# -# Purpose: To determine the current erlang cookie value. -# -# Resolution: Returns the cookie. -Facter.add(:rabbitmq_erlang_cookie) do - confine :osfamily => %w[Debian RedHat Suse] - - setcode do - if File.exists?('/var/lib/rabbitmq/.erlang.cookie') - File.read('/var/lib/rabbitmq/.erlang.cookie') - else - nil - end - end -end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_binding/rabbitmqadmin.rb b/rabbitmq/lib/puppet/provider/rabbitmq_binding/rabbitmqadmin.rb new file mode 100644 index 000000000..e0eebd025 --- /dev/null +++ b/rabbitmq/lib/puppet/provider/rabbitmq_binding/rabbitmqadmin.rb @@ -0,0 +1,110 @@ +require 'json' +require 'puppet' +Puppet::Type.type(:rabbitmq_binding).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].split('@').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_bindings(vhost) + rabbitmqctl('list_bindings', '-q', '-p', vhost, 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments').split(/\n/) + end + + def self.instances + resources = [] + all_vhosts.each do |vhost| + all_bindings(vhost).collect do |line| + source_name, destination_name, destination_type, routing_key, arguments = line.split(/\t/) + # 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 + if (source_name != '') + binding = { + :destination_type => destination_type, + :routing_key => routing_key, + :arguments => JSON.parse(arguments), + :ensure => :present, + :name => "%s@%s@%s" % [source_name, destination_name, vhost], + } + resources << new(binding) if binding[:name] + end + 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].split('@').first + destination = resource[:name].split('@')[1] + arguments = resource[:arguments] + if arguments.nil? + arguments = {} + end + rabbitmqadmin('declare', + 'binding', + vhost_opt, + "--user=#{resource[:user]}", + "--password=#{resource[:password]}", + "source=#{name}", + "destination=#{destination}", + "arguments=#{arguments.to_json}", + "routing_key=#{resource[:routing_key]}", + "destination_type=#{resource[:destination_type]}" + ) + @property_hash[:ensure] = :present + end + + def destroy + vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' + name = resource[:name].split('@').first + destination = resource[:name].split('@')[1] + rabbitmqadmin('delete', 'binding', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "source=#{name}", "destination_type=#{resource[:destination_type]}", "destination=#{destination}") + @property_hash[:ensure] = :absent + end + +end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_erlang_cookie/ruby.rb b/rabbitmq/lib/puppet/provider/rabbitmq_erlang_cookie/ruby.rb new file mode 100644 index 000000000..6e05b7811 --- /dev/null +++ b/rabbitmq/lib/puppet/provider/rabbitmq_erlang_cookie/ruby.rb @@ -0,0 +1,38 @@ +require 'puppet' +require 'set' +Puppet::Type.type(:rabbitmq_erlang_cookie).provide(:ruby) do + + defaultfor :feature => :posix + has_command(:puppet, 'puppet') do + environment :PATH => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin' + end + + def exists? + # Hack to prevent the create method from being called. + # We never need to create or destroy this resource, only change its value + true + end + + def content=(value) + if resource[:force] == :true # Danger! + puppet('resource', 'service', resource[:service_name], 'ensure=stopped') + FileUtils.rm_rf('/var/lib/rabbitmq/mnesia') + File.open(resource[:path], 'w') do |cookie| + cookie.chmod(0400) + cookie.write(value) + end + FileUtils.chown('rabbitmq', 'rabbitmq', resource[:path]) + else + fail("The current erlang cookie needs to change. In order to do this the RabbitMQ database needs to be wiped. Please set force => true to allow this to happen automatically.") + end + end + + def content + if File.exists?(resource[:path]) + File.read(resource[:path]) + else + '' + end + end + +end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_exchange/rabbitmqadmin.rb b/rabbitmq/lib/puppet/provider/rabbitmq_exchange/rabbitmqadmin.rb index 0fa354db0..f9ea3d286 100644 --- a/rabbitmq/lib/puppet/provider/rabbitmq_exchange/rabbitmqadmin.rb +++ b/rabbitmq/lib/puppet/provider/rabbitmq_exchange/rabbitmqadmin.rb @@ -1,5 +1,6 @@ require 'puppet' -Puppet::Type.type(:rabbitmq_exchange).provide(:rabbitmqadmin) do +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmqctl')) +Puppet::Type.type(:rabbitmq_exchange).provide(:rabbitmqadmin, :parent => Puppet::Provider::Rabbitmqctl) do if Puppet::PUPPETVERSION.to_f < 3 commands :rabbitmqctl => 'rabbitmqctl' @@ -24,7 +25,11 @@ def should_vhost def self.all_vhosts vhosts = [] - parse_command(rabbitmqctl('list_vhosts')).collect do |vhost| + parse_command( + self.run_with_retries { + rabbitmqctl('list_vhosts') + } + ).collect do |vhost| vhosts.push(vhost) end vhosts @@ -32,7 +37,11 @@ def self.all_vhosts def self.all_exchanges(vhost) exchanges = [] - parse_command(rabbitmqctl('list_exchanges', '-p', vhost, 'name', 'type')) + parse_command( + self.run_with_retries { + rabbitmqctl('list_exchanges', '-p', vhost, 'name', 'type') + } + ) end def self.parse_command(cmd_output) @@ -82,14 +91,14 @@ def exists? def create vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' name = resource[:name].split('@')[0] - rabbitmqadmin('declare', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}", "type=#{resource[:type]}") + rabbitmqadmin('declare', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}", "type=#{resource[:type]}", '-c', '/etc/rabbitmq/rabbitmqadmin.conf') @property_hash[:ensure] = :present end def destroy vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' name = resource[:name].split('@')[0] - rabbitmqadmin('delete', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}") + rabbitmqadmin('delete', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}", '-c', '/etc/rabbitmq/rabbitmqadmin.conf') @property_hash[:ensure] = :absent end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb b/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb index eefc9fb25..7ab5420c3 100644 --- a/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb +++ b/rabbitmq/lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb @@ -1,4 +1,5 @@ -Puppet::Type.type(:rabbitmq_plugin).provide(:rabbitmqplugins) do +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmqctl')) +Puppet::Type.type(:rabbitmq_plugin).provide(:rabbitmqplugins, :parent => Puppet::Provider::Rabbitmqctl) do if Puppet::PUPPETVERSION.to_f < 3 if Facter.value(:osfamily) == 'RedHat' @@ -21,8 +22,10 @@ defaultfor :feature => :posix def self.instances - rabbitmqplugins('list', '-E').split(/\n/).map do |line| - if line.split(/\s+/)[1] =~ /^(\S+)$/ + self.run_with_retries { + rabbitmqplugins('list', '-E', '-m') + }.split(/\n/).map do |line| + if line =~ /^(\S+)$/ new(:name => $1) else raise Puppet::Error, "Cannot parse invalid plugins line: #{line}" @@ -39,8 +42,10 @@ def destroy end def exists? - rabbitmqplugins('list', '-E').split(/\n/).detect do |line| - line.split(/\s+/)[1].match(/^#{resource[:name]}$/) + self.class.run_with_retries { + rabbitmqplugins('list', '-E', '-m') + }.split(/\n/).detect do |line| + line.match(/^#{resource[:name]}$/) end end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb b/rabbitmq/lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb new file mode 100644 index 000000000..7e7329580 --- /dev/null +++ b/rabbitmq/lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb @@ -0,0 +1,119 @@ +require 'json' +require 'puppet/util/package' + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmqctl')) +Puppet::Type.type(:rabbitmq_policy).provide(:rabbitmqctl, :parent => Puppet::Provider::Rabbitmqctl) do + + defaultfor :feature => :posix + + # cache policies + def self.policies(name, vhost) + @policies = {} unless @policies + unless @policies[vhost] + @policies[vhost] = {} + self.run_with_retries { + rabbitmqctl('list_policies', '-q', '-p', vhost) + }.split(/\n/).each do |line| + # rabbitmq<3.2 does not support the applyto field + # 1 2 3? 4 5 6 + # / ha-all all .* {"ha-mode":"all","ha-sync-mode":"automatic"} 0 + if line =~ /^(\S+)\s+(\S+)\s+(all|exchanges|queues)?\s*(\S+)\s+(\S+)\s+(\d+)$/ + applyto = $3 || 'all' + @policies[vhost][$2] = { + :applyto => applyto, + :pattern => $4, + :definition => JSON.parse($5), + :priority => $6} + else + raise Puppet::Error, "cannot parse line from list_policies:#{line}" + end + end + end + @policies[vhost][name] + end + + def policies(name, vhost) + self.class.policies(vhost, name) + end + + def should_policy + @should_policy ||= resource[:name].rpartition('@').first + end + + def should_vhost + @should_vhost ||= resource[:name].rpartition('@').last + end + + def create + set_policy + end + + def destroy + rabbitmqctl('clear_policy', '-p', should_vhost, should_policy) + end + + def exists? + policies(should_vhost, should_policy) + end + + def pattern + policies(should_vhost, should_policy)[:pattern] + end + + def pattern=(pattern) + set_policy + end + + def applyto + policies(should_vhost, should_policy)[:applyto] + end + + def applyto=(applyto) + set_policy + end + + def definition + policies(should_vhost, should_policy)[:definition] + end + + def definition=(definition) + set_policy + end + + def priority + policies(should_vhost, should_policy)[:priority] + end + + def priority=(priority) + set_policy + end + + def set_policy + unless @set_policy + @set_policy = true + resource[:applyto] ||= applyto + resource[:definition] ||= definition + resource[:pattern] ||= pattern + resource[:priority] ||= priority + # rabbitmq>=3.2.0 + if Puppet::Util::Package.versioncmp(self.class.rabbitmq_version, '3.2.0') >= 0 + rabbitmqctl('set_policy', + '-p', should_vhost, + '--priority', resource[:priority], + '--apply-to', resource[:applyto].to_s, + should_policy, + resource[:pattern], + resource[:definition].to_json + ) + else + rabbitmqctl('set_policy', + '-p', should_vhost, + should_policy, + resource[:pattern], + resource[:definition].to_json, + resource[:priority] + ) + end + end + end +end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_queue/rabbitmqadmin.rb b/rabbitmq/lib/puppet/provider/rabbitmq_queue/rabbitmqadmin.rb new file mode 100644 index 000000000..b0ecb1f5a --- /dev/null +++ b/rabbitmq/lib/puppet/provider/rabbitmq_queue/rabbitmqadmin.rb @@ -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 diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb b/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb index ef284bdcd..9cedd2aa6 100644 --- a/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb +++ b/rabbitmq/lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb @@ -1,6 +1,7 @@ require 'puppet' require 'set' -Puppet::Type.type(:rabbitmq_user).provide(:rabbitmqctl) do +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' @@ -13,7 +14,9 @@ defaultfor :feature => :posix def self.instances - rabbitmqctl('list_users').split(/\n/)[1..-2].collect do |line| + self.run_with_retries { + rabbitmqctl('-q', 'list_users') + }.split(/\n/).collect do |line| if line =~ /^(\S+)(\s+\[.*?\]|)$/ new(:name => $1) else @@ -32,17 +35,37 @@ def create end end + def change_password + rabbitmqctl('change_password', resource[:name], resource[:password]) + end + + def password + nil + end + + + def check_password + response = rabbitmqctl('eval', 'rabbit_auth_backend_internal:check_user_login(<<"' + resource[:name] + '">>, [{password, <<"' + resource[:password] +'">>}]).') + if response.include? 'invalid credentials' + false + else + true + end + end + def destroy rabbitmqctl('delete_user', resource[:name]) end def exists? - rabbitmqctl('list_users').split(/\n/)[1..-2].detect do |line| + 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 tags get_user_tags.entries.sort end @@ -90,9 +113,9 @@ def make_user_admin private def get_user_tags - match = rabbitmqctl('list_users').split(/\n/)[1..-2].collect do |line| + 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(/, /)) if match + Set.new(match[1].split(' ').map{|x| x.gsub(/,$/, '')}) if match end end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb b/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb index 83bd808e2..a0b8b5a1a 100644 --- a/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb +++ b/rabbitmq/lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb @@ -1,4 +1,5 @@ -Puppet::Type.type(:rabbitmq_user_permissions).provide(:rabbitmqctl) do +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmqctl')) +Puppet::Type.type(:rabbitmq_user_permissions).provide(:rabbitmqctl, :parent => Puppet::Provider::Rabbitmqctl) do if Puppet::PUPPETVERSION.to_f < 3 commands :rabbitmqctl => 'rabbitmqctl' @@ -15,7 +16,10 @@ def self.users(name, vhost) @users = {} unless @users unless @users[name] @users[name] = {} - rabbitmqctl('list_user_permissions', name).split(/\n/)[1..-2].each do |line| + self.run_with_retries { + rabbitmqctl('-q', 'list_user_permissions', name) + }.split(/\n/).each do |line| + line = self::strip_backslashes(line) if line =~ /^(\S+)\s+(\S*)\s+(\S*)\s+(\S*)$/ @users[name][$1] = {:configure => $2, :read => $4, :write => $3} @@ -51,7 +55,7 @@ def create resource[:configure_permission] ||= "''" resource[:read_permission] ||= "''" resource[:write_permission] ||= "''" - rabbitmqctl('set_permissions', '-p', should_vhost, should_user, resource[:configure_permission], resource[:write_permission], resource[:read_permission]) + rabbitmqctl('set_permissions', '-p', should_vhost, should_user, resource[:configure_permission], resource[:write_permission], resource[:read_permission]) end def destroy @@ -102,4 +106,9 @@ def set_permissions end end + def self.strip_backslashes(string) + # See: https://github.com/rabbitmq/rabbitmq-server/blob/v1_7/docs/rabbitmqctl.1.pod#output-escaping + string.gsub(/\\\\/, '\\') + end + end diff --git a/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb b/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb index 2ee45c311..fbd389d87 100644 --- a/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb +++ b/rabbitmq/lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb @@ -1,4 +1,5 @@ -Puppet::Type.type(:rabbitmq_vhost).provide(:rabbitmqctl) do +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmqctl')) +Puppet::Type.type(:rabbitmq_vhost).provide(:rabbitmqctl, :parent => Puppet::Provider::Rabbitmqctl) do if Puppet::PUPPETVERSION.to_f < 3 commands :rabbitmqctl => 'rabbitmqctl' @@ -9,7 +10,9 @@ end def self.instances - rabbitmqctl('list_vhosts').split(/\n/)[1..-2].map do |line| + self.run_with_retries { + rabbitmqctl('-q', 'list_vhosts') + }.split(/\n/).map do |line| if line =~ /^(\S+)$/ new(:name => $1) else @@ -27,7 +30,9 @@ def destroy end def exists? - out = rabbitmqctl('list_vhosts').split(/\n/)[1..-2].detect do |line| + out = self.class.run_with_retries { + rabbitmqctl('-q', 'list_vhosts') + }.split(/\n/).detect do |line| line.match(/^#{Regexp.escape(resource[:name])}$/) end end diff --git a/rabbitmq/lib/puppet/provider/rabbitmqctl.rb b/rabbitmq/lib/puppet/provider/rabbitmqctl.rb new file mode 100644 index 000000000..d23664569 --- /dev/null +++ b/rabbitmq/lib/puppet/provider/rabbitmqctl.rb @@ -0,0 +1,33 @@ +class Puppet::Provider::Rabbitmqctl < Puppet::Provider + initvars + commands :rabbitmqctl => 'rabbitmqctl' + + def self.rabbitmq_version + output = rabbitmqctl('-q', 'status') + version = output.match(/\{rabbit,"RabbitMQ","([\d\.]+)"\}/) + version[1] if version + end + + # Retry the given code block 'count' retries or until the + # command suceeeds. Use 'step' delay between retries. + # Limit each query time by 'timeout'. + # For example: + # users = self.class.run_with_retries { rabbitmqctl 'list_users' } + def self.run_with_retries(count=30, step=6, timeout=10) + count.times do |n| + begin + output = Timeout::timeout(timeout) do + yield + end + rescue Puppet::ExecutionFailure, Timeout + Puppet.debug 'Command failed, retrying' + sleep step + else + Puppet.debug 'Command succeeded' + return output + end + end + raise Puppet::Error, "Command is still failing after #{count * step} seconds expired!" + end + +end diff --git a/rabbitmq/lib/puppet/type/rabbitmq_binding.rb b/rabbitmq/lib/puppet/type/rabbitmq_binding.rb new file mode 100644 index 000000000..130948003 --- /dev/null +++ b/rabbitmq/lib/puppet/type/rabbitmq_binding.rb @@ -0,0 +1,96 @@ +Puppet::Type.newtype(:rabbitmq_binding) do + desc 'Native type for managing rabbitmq bindings' + + ensurable do + defaultto(:present) + newvalue(:present) do + provider.create + end + newvalue(:absent) do + provider.destroy + end + end + + newparam(:name, :namevar => true) do + desc 'source and destination of bind' + newvalues(/^\S*@\S+@\S+$/) + end + + newparam(:destination_type) do + desc 'binding destination_type' + newvalues(/queue|exchange/) + defaultto('queue') + end + + newparam(:routing_key) do + desc 'binding routing_key' + newvalues(/^\S*$/) + end + + newparam(:arguments) do + desc 'binding arguments' + 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('@')[2]] + end + + autorequire(:rabbitmq_exchange) do + setup_autorequire('exchange') + end + + autorequire(:rabbitmq_queue) do + setup_autorequire('queue') + end + + autorequire(:rabbitmq_user) do + [self[:user]] + end + + autorequire(:rabbitmq_user_permissions) do + [ + "#{self[:user]}@#{self[:name].split('@')[1]}", + "#{self[:user]}@#{self[:name].split('@')[0]}" + ] + end + + def setup_autorequire(type) + destination_type = value(:destination_type) + if type == 'exchange' + rval = ["#{self[:name].split('@')[0]}@#{self[:name].split('@')[2]}"] + if destination_type == type + rval.push("#{self[:name].split('@')[1]}@#{self[:name].split('@')[2]}") + end + else + if destination_type == type + rval = ["#{self[:name].split('@')[1]}@#{self[:name].split('@')[2]}"] + else + rval = [] + end + end + rval + end + + def validate_argument(argument) + unless [Hash].include?(argument.class) + raise ArgumentError, "Invalid argument" + end + end + +end diff --git a/rabbitmq/lib/puppet/type/rabbitmq_erlang_cookie.rb b/rabbitmq/lib/puppet/type/rabbitmq_erlang_cookie.rb new file mode 100644 index 000000000..564af5253 --- /dev/null +++ b/rabbitmq/lib/puppet/type/rabbitmq_erlang_cookie.rb @@ -0,0 +1,22 @@ +Puppet::Type.newtype(:rabbitmq_erlang_cookie) do + desc 'Type to manage the rabbitmq erlang cookie securely' + + newparam(:path, :namevar => true) + + newproperty(:content) do + desc 'Content of cookie' + newvalues(/^\S+$/) + def change_to_s(current, desired) + "The rabbitmq erlang cookie was changed" + end + end + + newparam(:force) do + defaultto(:false) + newvalues(:true, :false) + end + + newparam(:service_name) do + newvalues(/^\S+$/) + end +end diff --git a/rabbitmq/lib/puppet/type/rabbitmq_policy.rb b/rabbitmq/lib/puppet/type/rabbitmq_policy.rb new file mode 100644 index 000000000..c147c8039 --- /dev/null +++ b/rabbitmq/lib/puppet/type/rabbitmq_policy.rb @@ -0,0 +1,76 @@ +Puppet::Type.newtype(:rabbitmq_policy) do + desc 'Type for managing rabbitmq policies' + + ensurable do + defaultto(:present) + newvalue(:present) do + provider.create + end + newvalue(:absent) do + provider.destroy + end + end + + autorequire(:service) { 'rabbitmq-server' } + + validate do + fail('pattern parameter is required.') if self[:ensure] == :present and self[:pattern].nil? + fail('definition parameter is required.') if self[:ensure] == :present and self[:definition].nil? + end + + newparam(:name, :namevar => true) do + desc 'combination of policy@vhost to create policy for' + newvalues(/^\S+@\S+$/) + end + + newproperty(:pattern) do + desc 'policy pattern' + validate do |value| + resource.validate_pattern(value) + end + end + + newproperty(:applyto) do + desc 'policy apply to' + newvalue(:all) + newvalue(:exchanges) + newvalue(:queues) + defaultto :all + end + + newproperty(:definition) do + desc 'policy definition' + validate do |value| + resource.validate_definition(value) + end + end + + newproperty(:priority) do + desc 'policy priority' + newvalues(/^\d+$/) + defaultto 0 + end + + autorequire(:rabbitmq_vhost) do + [self[:name].split('@')[1]] + end + + def validate_pattern(value) + begin + Regexp.new(value) + rescue RegexpError + raise ArgumentError, "Invalid regexp #{value}" + end + end + + def validate_definition(definition) + unless [Hash].include?(definition.class) + raise ArgumentError, "Invalid definition" + end + definition.each do |k,v| + unless [String].include?(v.class) + raise ArgumentError, "Invalid definition" + end + end + end +end diff --git a/rabbitmq/lib/puppet/type/rabbitmq_queue.rb b/rabbitmq/lib/puppet/type/rabbitmq_queue.rb new file mode 100644 index 000000000..464a2ca6e --- /dev/null +++ b/rabbitmq/lib/puppet/type/rabbitmq_queue.rb @@ -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 diff --git a/rabbitmq/lib/puppet/type/rabbitmq_user.rb b/rabbitmq/lib/puppet/type/rabbitmq_user.rb index be5219d5c..66eef92c2 100644 --- a/rabbitmq/lib/puppet/type/rabbitmq_user.rb +++ b/rabbitmq/lib/puppet/type/rabbitmq_user.rb @@ -18,9 +18,17 @@ newvalues(/^\S+$/) end - # newproperty(:password) do - newparam(:password) do - desc 'User password to be set *on creation*' + newproperty(:password) do + desc 'User password to be set *on creation* and validated each run' + def insync?(is) + provider.check_password + end + def set(value) + provider.change_password + end + def change_to_s(current, desired) + "password has been changed" + end end newproperty(:admin) do diff --git a/rabbitmq/manifests/config.pp b/rabbitmq/manifests/config.pp index 2795cd073..c111dab5b 100644 --- a/rabbitmq/manifests/config.pp +++ b/rabbitmq/manifests/config.pp @@ -1,7 +1,9 @@ +# Class: rabbitmq::config +# Sets all the configuration values for RabbitMQ and creates the directories for +# config and ssl. class rabbitmq::config { $admin_enable = $rabbitmq::admin_enable - $cluster_disk_nodes = $rabbitmq::cluster_disk_nodes $cluster_node_type = $rabbitmq::cluster_node_type $cluster_nodes = $rabbitmq::cluster_nodes $config = $rabbitmq::config @@ -29,42 +31,38 @@ $ssl_stomp_port = $rabbitmq::ssl_stomp_port $ssl_verify = $rabbitmq::ssl_verify $ssl_fail_if_no_peer_cert = $rabbitmq::ssl_fail_if_no_peer_cert + $ssl_versions = $rabbitmq::ssl_versions $stomp_port = $rabbitmq::stomp_port + $ldap_auth = $rabbitmq::ldap_auth + $ldap_server = $rabbitmq::ldap_server + $ldap_user_dn_pattern = $rabbitmq::ldap_user_dn_pattern + $ldap_use_ssl = $rabbitmq::ldap_use_ssl + $ldap_port = $rabbitmq::ldap_port + $ldap_log = $rabbitmq::ldap_log $wipe_db_on_cookie_change = $rabbitmq::wipe_db_on_cookie_change $config_variables = $rabbitmq::config_variables $config_kernel_variables = $rabbitmq::config_kernel_variables $cluster_partition_handling = $rabbitmq::cluster_partition_handling $default_env_variables = { - 'RABBITMQ_NODE_PORT' => $port, - 'RABBITMQ_NODE_IP_ADDRESS' => $node_ip_address + 'NODE_PORT' => $port, + 'NODE_IP_ADDRESS' => $node_ip_address } # Handle env variables. $environment_variables = merge($default_env_variables, $rabbitmq::environment_variables) - # Handle deprecated option. - if $cluster_disk_nodes != [] { - notify { 'cluster_disk_nodes': - message => 'WARNING: The cluster_disk_nodes is deprecated. - Use cluster_nodes instead.', - } - $r_cluster_nodes = $cluster_disk_nodes - } else { - $r_cluster_nodes = $cluster_nodes - } - file { '/etc/rabbitmq': - ensure => directory, - owner => '0', - group => '0', - mode => '0644', + ensure => directory, + owner => '0', + group => '0', + mode => '0644', } file { '/etc/rabbitmq/ssl': - ensure => directory, - owner => '0', - group => '0', - mode => '0644', + ensure => directory, + owner => '0', + group => '0', + mode => '0644', } file { 'rabbitmq.config': @@ -87,37 +85,29 @@ notify => Class['rabbitmq::service'], } + file { 'rabbitmqadmin.conf': + ensure => file, + path => '/etc/rabbitmq/rabbitmqadmin.conf', + content => template('rabbitmq/rabbitmqadmin.conf.erb'), + owner => '0', + group => '0', + mode => '0644', + require => File['/etc/rabbitmq'], + } if $config_cluster { - file { 'erlang_cookie': - ensure => 'present', - path => '/var/lib/rabbitmq/.erlang.cookie', - owner => 'rabbitmq', - group => 'rabbitmq', - mode => '0400', - content => $erlang_cookie, - replace => true, - before => File['rabbitmq.config'], - notify => Class['rabbitmq::service'], - } - - # rabbitmq_erlang_cookie is a fact in this module. - if $erlang_cookie != $::rabbitmq_erlang_cookie { - # Safety check. - if $wipe_db_on_cookie_change { - exec { 'wipe_db': - command => "puppet resource service ${service_name} ensure=stopped; rm -rf /var/lib/rabbitmq/mnesia", - path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin', - } - File['erlang_cookie'] { - require => Exec['wipe_db'], - } - } else { - fail("ERROR: The current erlang cookie is ${::rabbitmq_erlang_cookie} and needs to change to ${erlang_cookie}. In order to do this the RabbitMQ database needs to be wiped. Please set the parameter called wipe_db_on_cookie_change to true to allow this to happen automatically.") + if $erlang_cookie == undef { + fail('You must set the $erlang_cookie value in order to configure clustering.') + } else { + rabbitmq_erlang_cookie { '/var/lib/rabbitmq/.erlang.cookie': + content => $erlang_cookie, + force => $wipe_db_on_cookie_change, + service_name => $service_name, + before => File['rabbitmq.config'], + notify => Class['rabbitmq::service'], } } - } diff --git a/rabbitmq/manifests/init.pp b/rabbitmq/manifests/init.pp index aa42b8127..1ac3f6d61 100644 --- a/rabbitmq/manifests/init.pp +++ b/rabbitmq/manifests/init.pp @@ -1,7 +1,6 @@ - # +# Main rabbitmq class class rabbitmq( $admin_enable = $rabbitmq::params::admin_enable, - $cluster_disk_nodes = $rabbitmq::params::cluster_disk_nodes, $cluster_node_type = $rabbitmq::params::cluster_node_type, $cluster_nodes = $rabbitmq::params::cluster_nodes, $config = $rabbitmq::params::config, @@ -21,7 +20,8 @@ $package_gpg_key = $rabbitmq::params::package_gpg_key, $package_name = $rabbitmq::params::package_name, $package_provider = $rabbitmq::params::package_provider, - $package_source = $rabbitmq::params::package_source, + $package_source = undef, + $repos_ensure = $rabbitmq::params::repos_ensure, $manage_repos = $rabbitmq::params::manage_repos, $plugin_dir = $rabbitmq::params::plugin_dir, $port = $rabbitmq::params::port, @@ -39,6 +39,7 @@ $ssl_stomp_port = $rabbitmq::params::ssl_stomp_port, $ssl_verify = $rabbitmq::params::ssl_verify, $ssl_fail_if_no_peer_cert = $rabbitmq::params::ssl_fail_if_no_peer_cert, + $ssl_versions = $rabbitmq::params::ssl_versions, $stomp_ensure = $rabbitmq::params::stomp_ensure, $ldap_auth = $rabbitmq::params::ldap_auth, $ldap_server = $rabbitmq::params::ldap_server, @@ -63,11 +64,10 @@ validate_string($package_gpg_key) validate_string($package_name) validate_string($package_provider) - validate_bool($manage_repos) + validate_bool($repos_ensure) validate_re($version, '^\d+\.\d+\.\d+(-\d+)*$') # Allow 3 digits and optional -n postfix. # Validate config parameters. - validate_array($cluster_disk_nodes) - validate_re($cluster_node_type, '^(ram|disc)$') + validate_re($cluster_node_type, '^(ram|disc|disk)$') # Both disc and disk are valid http://www.rabbitmq.com/clustering.html validate_array($cluster_nodes) validate_string($config) validate_absolute_path($config_path) @@ -118,12 +118,44 @@ warning('$ssl_stomp_port requires that $ssl => true and will be ignored') } + if $ssl_versions { + if $ssl { + validate_array($ssl_versions) + } else { + fail('$ssl_versions requires that $ssl => true') + } + } + + # This needs to happen here instead of params.pp because + # $package_source needs to override the constructed value in params.pp + if $package_source { # $package_source was specified by user so use that one + $real_package_source = $package_source + # NOTE(bogdando) do not enforce the source value for yum provider #MODULES-1631 + } elsif $package_provider != 'yum' { + # package_source was not specified, so construct it, unless the provider is 'yum' + case $::osfamily { + 'RedHat', 'SUSE': { + $base_version = regsubst($version,'^(.*)-\d$','\1') + $real_package_source = "http://www.rabbitmq.com/releases/rabbitmq-server/v${base_version}/rabbitmq-server-${version}.noarch.rpm" + } + default: { # Archlinux and Debian + $real_package_source = '' + } + } + } else { # for yum provider, use the source as is + $real_package_source = $package_source + } + include '::rabbitmq::install' include '::rabbitmq::config' include '::rabbitmq::service' include '::rabbitmq::management' - if $rabbitmq::manage_repos == true { + if $manage_repos != undef { + warning('$manage_repos is now deprecated. Please use $repos_ensure instead') + } + + if $manage_repos != false { case $::osfamily { 'RedHat', 'SUSE': { include '::rabbitmq::repo::rhel' } @@ -142,9 +174,9 @@ include '::rabbitmq::install::rabbitmqadmin' rabbitmq_plugin { 'rabbitmq_management': - ensure => present, - require => Class['rabbitmq::install'], - notify => Class['rabbitmq::service'], + ensure => present, + require => Class['rabbitmq::install'], + notify => Class['rabbitmq::service'], provider => 'rabbitmqplugins' } @@ -153,9 +185,9 @@ if $stomp_ensure { rabbitmq_plugin { 'rabbitmq_stomp': - ensure => present, - require => Class['rabbitmq::install'], - notify => Class['rabbitmq::service'], + ensure => present, + require => Class['rabbitmq::install'], + notify => Class['rabbitmq::service'], provider => 'rabbitmqplugins' } } @@ -169,9 +201,6 @@ } } - # Anchor this as per #8040 - this ensures that classes won't float off and - # mess everything up. You can read about this at: - # http://docs.puppetlabs.com/puppet/2.7/reference/lang_containment.html#known-issues anchor { 'rabbitmq::begin': } anchor { 'rabbitmq::end': } diff --git a/rabbitmq/manifests/install.pp b/rabbitmq/manifests/install.pp index 09fe3b321..f2df83aa0 100644 --- a/rabbitmq/manifests/install.pp +++ b/rabbitmq/manifests/install.pp @@ -1,9 +1,11 @@ +# Class rabbitmq::install +# Ensures the rabbitmq-server exists class rabbitmq::install { $package_ensure = $rabbitmq::package_ensure $package_name = $rabbitmq::package_name $package_provider = $rabbitmq::package_provider - $package_source = $rabbitmq::package_source + $package_source = $rabbitmq::real_package_source package { 'rabbitmq-server': ensure => $package_ensure, diff --git a/rabbitmq/manifests/install/rabbitmqadmin.pp b/rabbitmq/manifests/install/rabbitmqadmin.pp index 184a5258d..5b9f527b9 100644 --- a/rabbitmq/manifests/install/rabbitmqadmin.pp +++ b/rabbitmq/manifests/install/rabbitmqadmin.pp @@ -1,15 +1,24 @@ # class rabbitmq::install::rabbitmqadmin { - $management_port = $rabbitmq::management_port + if($rabbitmq::ssl) { + $management_port = $rabbitmq::ssl_management_port + } + else { + $management_port = $rabbitmq::management_port + } + $default_user = $rabbitmq::default_user $default_pass = $rabbitmq::default_pass $protocol = $rabbitmq::ssl ? { false => 'http', default => 'https' } staging::file { 'rabbitmqadmin': - target => '/var/lib/rabbitmq/rabbitmqadmin', - source => "${protocol}://${default_user}:${default_pass}@localhost:${management_port}/cli/rabbitmqadmin", - require => [ + target => '/var/lib/rabbitmq/rabbitmqadmin', + source => "${protocol}://${default_user}:${default_pass}@localhost:${management_port}/cli/rabbitmqadmin", + curl_option => '-k --noproxy localhost --retry 30 --retry-delay 6', + timeout => '180', + wget_option => '--no-proxy', + require => [ Class['rabbitmq::service'], Rabbitmq_plugin['rabbitmq_management'] ], diff --git a/rabbitmq/manifests/params.pp b/rabbitmq/manifests/params.pp index abe7c52b7..4e4ba3221 100644 --- a/rabbitmq/manifests/params.pp +++ b/rabbitmq/manifests/params.pp @@ -9,28 +9,21 @@ $package_ensure = 'installed' $package_name = 'rabbitmq' $service_name = 'rabbitmq' - $package_source = '' $version = '3.1.3-1' - $base_version = regsubst($version,'^(.*)-\d$','\1') - # This must remain at the end as we need $base_version and $version defined first } 'Debian': { $package_ensure = 'installed' $package_name = 'rabbitmq-server' $service_name = 'rabbitmq-server' $package_provider = 'apt' - $package_source = '' $version = '3.1.5' } 'RedHat': { $package_ensure = 'installed' $package_name = 'rabbitmq-server' $service_name = 'rabbitmq-server' - $package_provider = 'yum' + $package_provider = 'rpm' $version = '3.1.5-1' - $base_version = regsubst($version,'^(.*)-\d$','\1') - # This must remain at the end as we need $base_version and $version defined first. - $package_source = "http://www.rabbitmq.com/releases/rabbitmq-server/v${base_version}/rabbitmq-server-${version}.noarch.rpm" } 'SUSE': { $package_ensure = 'installed' @@ -38,9 +31,6 @@ $service_name = 'rabbitmq-server' $package_provider = 'zypper' $version = '3.1.5-1' - $base_version = regsubst($version,'^(.*)-\d$','\1') - # This must remain at the end as we need $base_version and $version defined first. - $package_source = "http://www.rabbitmq.com/releases/rabbitmq-server/v${base_version}/rabbitmq-server-${version}.noarch.rpm" } default: { fail("The ${module_name} module is not supported on an ${::osfamily} based system.") @@ -52,11 +42,11 @@ $management_port = '15672' $package_apt_pin = '' $package_gpg_key = 'http://www.rabbitmq.com/rabbitmq-signing-key-public.asc' - $manage_repos = true + $repos_ensure = true + $manage_repos = undef $service_ensure = 'running' $service_manage = true #config - $cluster_disk_nodes = [] $cluster_node_type = 'disc' $cluster_nodes = [] $config = 'rabbitmq/rabbitmq.config.erb' @@ -68,7 +58,7 @@ $delete_guest_user = false $env_config = 'rabbitmq/rabbitmq-env.conf.erb' $env_config_path = '/etc/rabbitmq/rabbitmq-env.conf' - $erlang_cookie = 'EOKOWXQREETZSHFNTPEY' + $erlang_cookie = undef $node_ip_address = 'UNSET' $plugin_dir = "/usr/lib/rabbitmq/lib/rabbitmq_server-${version}/plugins" $port = '5672' @@ -82,11 +72,12 @@ $ssl_management_port = '15671' $ssl_stomp_port = '6164' $ssl_verify = 'verify_none' - $ssl_fail_if_no_peer_cert = 'false' + $ssl_fail_if_no_peer_cert = false + $ssl_versions = undef $stomp_ensure = false $ldap_auth = false $ldap_server = 'ldap' - $ldap_user_dn_pattern = 'cn=${username},ou=People,dc=example,dc=com' + $ldap_user_dn_pattern = 'cn=username,ou=People,dc=example,dc=com' $ldap_use_ssl = false $ldap_port = '389' $ldap_log = false diff --git a/rabbitmq/manifests/repo/apt.pp b/rabbitmq/manifests/repo/apt.pp index 56d08af8a..707c619dc 100644 --- a/rabbitmq/manifests/repo/apt.pp +++ b/rabbitmq/manifests/repo/apt.pp @@ -6,7 +6,7 @@ $release = 'testing', $repos = 'main', $include_src = false, - $key = '056E8E56', + $key = 'F7B8CEA6056E8E56', $key_source = 'http://www.rabbitmq.com/rabbitmq-signing-key-public.asc', $key_content = undef, ) { @@ -15,7 +15,13 @@ Class['rabbitmq::repo::apt'] -> Package<| title == 'rabbitmq-server' |> + $ensure_source = $rabbitmq::repos_ensure ? { + false => 'absent', + default => 'present', + } + apt::source { 'rabbitmq': + ensure => $ensure_source, location => $location, release => $release, repos => $repos, @@ -25,7 +31,7 @@ key_content => $key_content, } - if $pin { + if $pin != '' { validate_re($pin, '\d\d\d') apt::pin { 'rabbitmq': packages => 'rabbitmq-server', diff --git a/rabbitmq/manifests/repo/rhel.pp b/rabbitmq/manifests/repo/rhel.pp index f2271cd46..284909945 100644 --- a/rabbitmq/manifests/repo/rhel.pp +++ b/rabbitmq/manifests/repo/rhel.pp @@ -1,12 +1,16 @@ +# Class: rabbitmq::repo::rhel +# Imports the gpg key if it doesn't already exist. class rabbitmq::repo::rhel { - $package_gpg_key = $rabbitmq::package_gpg_key + if $rabbitmq::repos_ensure { - Class['rabbitmq::repo::rhel'] -> Package<| title == 'rabbitmq-server' |> + $package_gpg_key = $rabbitmq::package_gpg_key - exec { "rpm --import ${package_gpg_key}": - path => ['/bin','/usr/bin','/sbin','/usr/sbin'], - onlyif => 'test `rpm -qa | grep gpg-pubkey-056e8e56-468e43f2 | wc -l` -eq 0', - } + Class['rabbitmq::repo::rhel'] -> Package<| title == 'rabbitmq-server' |> + exec { "rpm --import ${package_gpg_key}": + path => ['/bin','/usr/bin','/sbin','/usr/sbin'], + unless => 'rpm -q gpg-pubkey-056e8e56-468e43f2 2>/dev/null', + } + } } diff --git a/rabbitmq/manifests/server.pp b/rabbitmq/manifests/server.pp index 495ea2f2d..05de184fc 100644 --- a/rabbitmq/manifests/server.pp +++ b/rabbitmq/manifests/server.pp @@ -14,10 +14,8 @@ # [*config*] - contents of config file # [*env_config*] - contents of env-config file # [*config_cluster*] - whether to configure a RabbitMQ cluster -# [*config_mirrored_queues*] - DEPRECATED (doesn't do anything) -# [*cluster_disk_nodes*] - DEPRECATED (use cluster_nodes instead) # [*cluster_nodes*] - which nodes to cluster with (including the current one) -# [*cluster_node_type*] - Type of cluster node (disc or ram) +# [*cluster_node_type*] - Type of cluster node (disc/disk or ram) # [*erlang_cookie*] - erlang cookie, must be the same for all nodes in a cluster # [*wipe_db_on_cookie_change*] - whether to wipe the RabbitMQ data if the specified # erlang_cookie differs from the current one. This is a sad parameter: actually, @@ -45,7 +43,6 @@ $config_stomp = $rabbitmq::params::config_stomp, $stomp_port = $rabbitmq::params::stomp_port, $config_cluster = $rabbitmq::params::config_cluster, - $cluster_disk_nodes = $rabbitmq::params::cluster_disk_nodes, $cluster_nodes = $rabbitmq::params::cluster_nodes, $cluster_node_type = $rabbitmq::params::cluster_node_type, $node_ip_address = $rabbitmq::params::node_ip_address, @@ -53,22 +50,8 @@ $env_config = $rabbitmq::params::env_config, $erlang_cookie = $rabbitmq::params::erlang_cookie, $wipe_db_on_cookie_change = $rabbitmq::params::wipe_db_on_cookie_change, - # DEPRECATED - $manage_service = undef, - $config_mirrored_queues = undef, ) inherits rabbitmq::params { - if $manage_service != undef { - warning('The $manage_service parameter is deprecated; please use $service_manage instead') - $_service_manage = $manage_service - } else { - $_service_manage = $service_manage - } - - if $config_mirrored_queues != undef { - warning('The $config_mirrored_queues parameter is deprecated; it does not affect anything') - } - anchor {'before::rabbimq::class': before => Class['rabbitmq'], } @@ -78,23 +61,22 @@ } class { 'rabbitmq': - port => $port, - delete_guest_user => $delete_guest_user, - package_name => $package_name, - version => $version, - service_name => $service_name, - service_ensure => $service_ensure, - service_manage => $_service_manage, - config_stomp => $config_stomp, - stomp_port => $stomp_port, - config_cluster => $config_cluster, - cluster_disk_nodes => $cluster_disk_nodes, - cluster_nodes => $cluster_nodes, - cluster_node_type => $cluster_node_type, - node_ip_address => $node_ip_address, - config => $config, - env_config => $env_config, - erlang_cookie => $erlang_cookie, - wipe_db_on_cookie_change => $wipe_db_on_cookie_change, + port => $port, + delete_guest_user => $delete_guest_user, + package_name => $package_name, + version => $version, + service_name => $service_name, + service_ensure => $service_ensure, + service_manage => $service_manage, + config_stomp => $config_stomp, + stomp_port => $stomp_port, + config_cluster => $config_cluster, + cluster_nodes => $cluster_nodes, + cluster_node_type => $cluster_node_type, + node_ip_address => $node_ip_address, + config => $config, + env_config => $env_config, + erlang_cookie => $erlang_cookie, + wipe_db_on_cookie_change => $wipe_db_on_cookie_change, } } diff --git a/rabbitmq/metadata.json b/rabbitmq/metadata.json index 3e0f33385..acc819146 100644 --- a/rabbitmq/metadata.json +++ b/rabbitmq/metadata.json @@ -1,24 +1,55 @@ { "name": "puppetlabs-rabbitmq", - "version": "4.1.0", + "version": "5.0.0", "author": "puppetlabs", - "summary": "RabbitMQ Puppet Module", - "license": "Apache 2.0", + "summary": "Installs, configures, and manages RabbitMQ.", + "license": "Apache-2.0", "source": "https://github.com/puppetlabs/puppetlabs-rabbitmq", "project_page": "https://github.com/puppetlabs/puppetlabs-rabbitmq", "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", - "dependencies": [ + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "5", + "6" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "5", + "6" + ] + }, { - "name": "puppetlabs/stdlib", - "version_requirement": ">= 2.0.0" + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7" + ] }, { - "name": "puppetlabs/apt", - "version_requirement": ">= 1.0.0" + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" }, { - "name": "nanliu/staging", - "version_requirement": ">= 0.3.1" + "name": "puppet", + "version_requirement": "3.x" } + ], + "dependencies": [ + { "name": "puppetlabs/stdlib", "version_requirement": ">=2.0.0 <5.0.0" }, + { "name": "puppetlabs/apt", "version_requirement": ">=1.0.0 <2.0.0" }, + { "name": "nanliu/staging", "version_requirement": ">=0.3.1 <2.0.0" } ] } diff --git a/rabbitmq/spec/acceptance/class_spec.rb b/rabbitmq/spec/acceptance/class_spec.rb index c0b557673..b5b50cd34 100644 --- a/rabbitmq/spec/acceptance/class_spec.rb +++ b/rabbitmq/spec/acceptance/class_spec.rb @@ -83,7 +83,6 @@ class { 'erlang': epel_enable => true} } EOS - apply_manifest(pp_pre, :catch_failures => true) apply_manifest(pp, :catch_failures => true) end diff --git a/rabbitmq/spec/acceptance/clustering_spec.rb b/rabbitmq/spec/acceptance/clustering_spec.rb index 04627fa6f..438c65ba1 100644 --- a/rabbitmq/spec/acceptance/clustering_spec.rb +++ b/rabbitmq/spec/acceptance/clustering_spec.rb @@ -1,13 +1,38 @@ require 'spec_helper_acceptance' describe 'rabbitmq clustering' do - context 'rabbitmq::config_cluster => true' do + context 'rabbitmq::wipe_db_on_cookie_change => false' do it 'should run successfully' do pp = <<-EOS class { 'rabbitmq': config_cluster => true, cluster_nodes => ['rabbit1', 'rabbit2'], cluster_node_type => 'ram', + erlang_cookie => 'TESTCOOKIE', + wipe_db_on_cookie_change => false, + } + if $::osfamily == 'RedHat' { + class { 'erlang': epel_enable => true} + Class['erlang'] -> Class['rabbitmq'] + } + EOS + + apply_manifest(pp, :expect_failures => true) + end + + describe file('/var/lib/rabbitmq/.erlang.cookie') do + it { should_not contain 'TESTCOOKIE' } + end + + end + context 'rabbitmq::wipe_db_on_cookie_change => true' do + it 'should run successfully' do + pp = <<-EOS + class { 'rabbitmq': + config_cluster => true, + cluster_nodes => ['rabbit1', 'rabbit2'], + cluster_node_type => 'ram', + erlang_cookie => 'TESTCOOKIE', wipe_db_on_cookie_change => true, } if $::osfamily == 'RedHat' { @@ -15,7 +40,7 @@ class { 'erlang': epel_enable => true} Class['erlang'] -> Class['rabbitmq'] } EOS - + apply_manifest(pp, :catch_failures => true) end @@ -29,6 +54,7 @@ class { 'erlang': epel_enable => true} describe file('/var/lib/rabbitmq/.erlang.cookie') do it { should be_file } + it { should contain 'TESTCOOKIE' } end end end diff --git a/rabbitmq/spec/acceptance/nodesets/ubuntu-server-1310-x64.yml b/rabbitmq/spec/acceptance/nodesets/ubuntu-server-1310-x64.yml deleted file mode 100644 index f4b2366f3..000000000 --- a/rabbitmq/spec/acceptance/nodesets/ubuntu-server-1310-x64.yml +++ /dev/null @@ -1,11 +0,0 @@ -HOSTS: - ubuntu-server-1310-x64: - roles: - - master - platform: ubuntu-13.10-amd64 - box : ubuntu-server-1310-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-x64-virtualbox-nocm.box - hypervisor : vagrant -CONFIG: - log_level : debug - type: git diff --git a/rabbitmq/spec/acceptance/policy_spec.rb b/rabbitmq/spec/acceptance/policy_spec.rb new file mode 100644 index 000000000..26858ecc5 --- /dev/null +++ b/rabbitmq/spec/acceptance/policy_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper_acceptance' + +describe 'rabbitmq policy on a vhost:' do + + + context "create policy resource" do + it 'should run successfully' do + pp = <<-EOS + if $::osfamily == 'RedHat' { + class { 'erlang': epel_enable => true } + Class['erlang'] -> Class['::rabbitmq'] + } + class { '::rabbitmq': + service_manage => true, + port => '5672', + delete_guest_user => true, + admin_enable => true, + } -> + + rabbitmq_vhost { 'myhost': + ensure => present, + } -> + + rabbitmq_policy { 'ha-all@myhost': + pattern => '.*', + priority => 0, + applyto => 'all', + definition => { + 'ha-mode' => 'all', + 'ha-sync-mode' => 'automatic', + }, + } + EOS + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + it 'should have the policy' do + shell('rabbitmqctl list_policies -p myhost') do |r| + expect(r.stdout).to match(/myhost.*ha-all.*ha-sync-mode/) + expect(r.exit_code).to be_zero + end + end + + end +end diff --git a/rabbitmq/spec/acceptance/user_spec.rb b/rabbitmq/spec/acceptance/user_spec.rb new file mode 100644 index 000000000..6aab665a4 --- /dev/null +++ b/rabbitmq/spec/acceptance/user_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper_acceptance' + +describe 'rabbitmq user:' do + + + context "create user resource" do + it 'should run successfully' do + pp = <<-EOS + if $::osfamily == 'RedHat' { + class { 'erlang': epel_enable => true } + Class['erlang'] -> Class['::rabbitmq'] + } + class { '::rabbitmq': + service_manage => true, + port => '5672', + delete_guest_user => true, + admin_enable => true, + } -> + + rabbitmq_user { 'dan': + admin => true, + password => 'bar', + } + EOS + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + it 'should have the user' do + shell('rabbitmqctl list_users') do |r| + expect(r.stdout).to match(/dan.*administrator/) + expect(r.exit_code).to be_zero + end + end + + end +end diff --git a/rabbitmq/spec/acceptance/vhost_spec.rb b/rabbitmq/spec/acceptance/vhost_spec.rb new file mode 100644 index 000000000..ef1c2a342 --- /dev/null +++ b/rabbitmq/spec/acceptance/vhost_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper_acceptance' + +describe 'rabbitmq vhost:' do + + + context "create vhost resource" do + it 'should run successfully' do + pp = <<-EOS + if $::osfamily == 'RedHat' { + class { 'erlang': epel_enable => true } + Class['erlang'] -> Class['::rabbitmq'] + } + class { '::rabbitmq': + service_manage => true, + port => '5672', + delete_guest_user => true, + admin_enable => true, + } -> + + rabbitmq_vhost { 'myhost': + ensure => present, + } + EOS + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + it 'should have the vhost' do + shell('rabbitmqctl list_vhosts') do |r| + expect(r.stdout).to match(/myhost/) + expect(r.exit_code).to be_zero + end + end + + end +end diff --git a/rabbitmq/spec/classes/rabbitmq_spec.rb b/rabbitmq/spec/classes/rabbitmq_spec.rb index e82a64e6b..8429c98c4 100644 --- a/rabbitmq/spec/classes/rabbitmq_spec.rb +++ b/rabbitmq/spec/classes/rabbitmq_spec.rb @@ -19,6 +19,7 @@ describe 'apt::source default values' do it 'should add a repo with defaults values' do should contain_apt__source('rabbitmq').with( { + :ensure => 'present', :location => 'http://www.rabbitmq.com/debian/', :release => 'testing', :repos => 'main', @@ -30,8 +31,111 @@ context 'on Debian' do let(:params) {{ :manage_repos => false }} let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} - it 'does not include rabbitmq::repo::apt when manage_repos is false' do - should_not contain_class('rabbitmq::repo::apt') + it 'does ensure rabbitmq apt::source is absent when manage_repos is false' do + should_not contain_apt__source('rabbitmq') + end + end + + context 'on Debian' do + let(:params) {{ :manage_repos => true }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + + it 'includes rabbitmq::repo::apt' do + should contain_class('rabbitmq::repo::apt') + end + + describe 'apt::source default values' do + it 'should add a repo with defaults values' do + should contain_apt__source('rabbitmq').with( { + :ensure => 'present', + :location => 'http://www.rabbitmq.com/debian/', + :release => 'testing', + :repos => 'main', + }) + end + end + end + + context 'on Debian' do + let(:params) {{ :repos_ensure => false }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + it 'does ensure rabbitmq apt::source is absent when repos_ensure is false' do + should contain_apt__source('rabbitmq').with( + 'ensure' => 'absent' + ) + end + end + + context 'on Debian' do + let(:params) {{ :repos_ensure => true }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + + it 'includes rabbitmq::repo::apt' do + should contain_class('rabbitmq::repo::apt') + end + + describe 'apt::source default values' do + it 'should add a repo with defaults values' do + should contain_apt__source('rabbitmq').with( { + :ensure => 'present', + :location => 'http://www.rabbitmq.com/debian/', + :release => 'testing', + :repos => 'main', + }) + end + end + end + + context 'on Debian' do + let(:params) {{ :manage_repos => true, :repos_ensure => false }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + + it 'includes rabbitmq::repo::apt' do + should contain_class('rabbitmq::repo::apt') + end + + describe 'apt::source default values' do + it 'should add a repo with defaults values' do + should contain_apt__source('rabbitmq').with( { + :ensure => 'absent', + }) + end + end + end + + context 'on Debian' do + let(:params) {{ :manage_repos => true, :repos_ensure => true }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + + it 'includes rabbitmq::repo::apt' do + should contain_class('rabbitmq::repo::apt') + end + + describe 'apt::source default values' do + it 'should add a repo with defaults values' do + should contain_apt__source('rabbitmq').with( { + :ensure => 'present', + :location => 'http://www.rabbitmq.com/debian/', + :release => 'testing', + :repos => 'main', + }) + end + end + end + + context 'on Debian' do + let(:params) {{ :manage_repos => false, :repos_ensure => true }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + it 'does ensure rabbitmq apt::source is absent when manage_repos is false and repos_ensure is true' do + should_not contain_apt__source('rabbitmq') + end + end + + context 'on Debian' do + let(:params) {{ :manage_repos => false, :repos_ensure => false }} + let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }} + it 'does ensure rabbitmq apt::source is absent when manage_repos is false and repos_ensure is false' do + should_not contain_apt__source('rabbitmq') end end @@ -39,14 +143,79 @@ let(:facts) {{ :osfamily => 'RedHat' }} it 'includes rabbitmq::repo::rhel' do should contain_class('rabbitmq::repo::rhel') + should contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :repos_ensure => false }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does not import repo public key when repos_ensure is false' do + should contain_class('rabbitmq::repo::rhel') + should_not contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :repos_ensure => true }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does import repo public key when repos_ensure is true' do + should contain_class('rabbitmq::repo::rhel') + should contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') end end context 'on Redhat' do let(:params) {{ :manage_repos => false }} let(:facts) {{ :osfamily => 'RedHat' }} - it 'does not include rabbitmq::repo::rhel when manage_repos is false' do + it 'does not import repo public key when manage_repos is false' do should_not contain_class('rabbitmq::repo::rhel') + should_not contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :manage_repos => true }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does import repo public key when manage_repos is true' do + should contain_class('rabbitmq::repo::rhel') + should contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :manage_repos => false, :repos_ensure => true }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does not import repo public key when manage_repos is false and repos_ensure is true' do + should_not contain_class('rabbitmq::repo::rhel') + should_not contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :manage_repos => true, :repos_ensure => true }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does import repo public key when manage_repos is true and repos_ensure is true' do + should contain_class('rabbitmq::repo::rhel') + should contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :manage_repos => false, :repos_ensure => false }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does not import repo public key when manage_repos is false and repos_ensure is false' do + should_not contain_class('rabbitmq::repo::rhel') + should_not contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') + end + end + + context 'on Redhat' do + let(:params) {{ :manage_repos => true, :repos_ensure => false }} + let(:facts) {{ :osfamily => 'RedHat' }} + it 'does not import repo public key when manage_repos is true and repos_ensure is false' do + should contain_class('rabbitmq::repo::rhel') + should_not contain_exec('rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc') end end @@ -54,7 +223,6 @@ context "on #{distro}" do let(:facts) {{ :osfamily => distro, - :rabbitmq_erlang_cookie => 'EOKOWXQREETZSHFNTPEY', :lsbdistcodename => 'squeeze', :lsbdistid => 'Debian' }} @@ -98,14 +266,6 @@ end end - context 'deprecated parameters' do - describe 'cluster_disk_nodes' do - let(:params) {{ :cluster_disk_nodes => ['node1', 'node2'] }} - - it { should contain_notify('cluster_disk_nodes') } - end - end - describe 'manages configuration directory correctly' do it { should contain_file('/etc/rabbitmq').with( 'ensure' => 'directory' @@ -117,22 +277,21 @@ end context 'configures config_cluster' do - let(:facts) {{ :osfamily => distro, :rabbitmq_erlang_cookie => 'ORIGINAL', :lsbdistid => 'Debian' }} + let(:facts) {{ :osfamily => distro, :lsbdistid => 'Debian' }} let(:params) {{ :config_cluster => true, :cluster_nodes => ['hare-1', 'hare-2'], :cluster_node_type => 'ram', - :erlang_cookie => 'TESTCOOKIE', :wipe_db_on_cookie_change => false }} describe 'with defaults' do it 'fails' do - expect{subject}.to raise_error(/^ERROR: The current erlang cookie is ORIGINAL/) + expect{subject}.to raise_error(/^You must set the \$erlang_cookie value/) end end - describe 'with wipe_db_on_cookie_change set' do + describe 'with erlang_cookie set' do let(:params) {{ :config_cluster => true, :cluster_nodes => ['hare-1', 'hare-2'], @@ -140,22 +299,8 @@ :erlang_cookie => 'TESTCOOKIE', :wipe_db_on_cookie_change => true }} - it 'wipes the database' do - should contain_exec('wipe_db') - should contain_file('erlang_cookie') - end - end - - describe 'correctly when cookies match' do - let(:params) {{ - :config_cluster => true, - :cluster_nodes => ['hare-1', 'hare-2'], - :cluster_node_type => 'ram', - :erlang_cookie => 'ORIGINAL', - :wipe_db_on_cookie_change => true - }} - it 'and doesnt wipe anything' do - should contain_file('erlang_cookie') + it 'contains the rabbitmq_erlang_cookie' do + should contain_rabbitmq_erlang_cookie('/var/lib/rabbitmq/.erlang.cookie') end end @@ -173,35 +318,30 @@ }) end - it 'for erlang_cookie' do - should contain_file('erlang_cookie').with({ - 'content' => 'ORIGINAL', - }) - end end end describe 'rabbitmq-env configuration' do let(:params) {{ :environment_variables => { - 'RABBITMQ_NODE_IP_ADDRESS' => '1.1.1.1', - 'RABBITMQ_NODE_PORT' => '5656', - 'RABBITMQ_NODENAME' => 'HOSTNAME', - 'RABBITMQ_SERVICENAME' => 'RabbitMQ', - 'RABBITMQ_CONSOLE_LOG' => 'RabbitMQ.debug', - 'RABBITMQ_CTL_ERL_ARGS' => 'verbose', - 'RABBITMQ_SERVER_ERL_ARGS' => 'v', - 'RABBITMQ_SERVER_START_ARGS' => 'debug' + 'NODE_IP_ADDRESS' => '1.1.1.1', + 'NODE_PORT' => '5656', + 'NODENAME' => 'HOSTNAME', + 'SERVICENAME' => 'RabbitMQ', + 'CONSOLE_LOG' => 'RabbitMQ.debug', + 'CTL_ERL_ARGS' => 'verbose', + 'SERVER_ERL_ARGS' => 'v', + 'SERVER_START_ARGS' => 'debug' }}} it 'should set environment variables' do should contain_file('rabbitmq-env.config') \ - .with_content(/RABBITMQ_NODE_IP_ADDRESS=1.1.1.1/) \ - .with_content(/RABBITMQ_NODE_PORT=5656/) \ - .with_content(/RABBITMQ_NODENAME=HOSTNAME/) \ - .with_content(/RABBITMQ_SERVICENAME=RabbitMQ/) \ - .with_content(/RABBITMQ_CONSOLE_LOG=RabbitMQ.debug/) \ - .with_content(/RABBITMQ_CTL_ERL_ARGS=verbose/) \ - .with_content(/RABBITMQ_SERVER_ERL_ARGS=v/) \ - .with_content(/RABBITMQ_SERVER_START_ARGS=debug/) + .with_content(/NODE_IP_ADDRESS=1.1.1.1/) \ + .with_content(/NODE_PORT=5656/) \ + .with_content(/NODENAME=HOSTNAME/) \ + .with_content(/SERVICENAME=RabbitMQ/) \ + .with_content(/CONSOLE_LOG=RabbitMQ.debug/) \ + .with_content(/CTL_ERL_ARGS=verbose/) \ + .with_content(/SERVER_ERL_ARGS=v/) \ + .with_content(/SERVER_START_ARGS=debug/) end end @@ -224,9 +364,9 @@ context 'configuration setting' do describe 'node_ip_address when set' do let(:params) {{ :node_ip_address => '172.0.0.1' }} - it 'should set RABBITMQ_NODE_IP_ADDRESS to specified value' do + it 'should set NODE_IP_ADDRESS to specified value' do should contain_file('rabbitmq-env.config'). - with_content(%r{RABBITMQ_NODE_IP_ADDRESS=172\.0\.0\.1}) + with_content(%r{NODE_IP_ADDRESS=172\.0\.0\.1}) end end @@ -277,7 +417,7 @@ it { should contain_rabbitmq_plugin('rabbitmq_auth_backend_ldap') } it 'should contain ldap parameters' do - verify_contents(subject, 'rabbitmq.config', + verify_contents(subject, 'rabbitmq.config', ['[', ' {rabbit, [', ' {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]},', ' ]}', ' {rabbitmq_auth_backend_ldap, [', ' {other_bind, anon},', ' {servers, ["ldap.example.com"]},', @@ -301,7 +441,7 @@ it { should contain_rabbitmq_plugin('rabbitmq_auth_backend_ldap') } it 'should contain ldap parameters' do - verify_contents(subject, 'rabbitmq.config', + verify_contents(subject, 'rabbitmq.config', ['[', ' {rabbit, [', ' {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]},', ' ]}', ' {rabbitmq_auth_backend_ldap, [', ' {other_bind, anon},', ' {servers, ["ldap.example.com"]},', @@ -363,6 +503,79 @@ end end + describe 'ssl options with specific ssl versions' do + let(:params) { + { :ssl => true, + :ssl_port => 3141, + :ssl_cacert => '/path/to/cacert', + :ssl_cert => '/path/to/cert', + :ssl_key => '/path/to/key', + :ssl_versions => ['tlsv1.2', 'tlsv1.1'] + } } + + it 'should set ssl options to specified values' do + should contain_file('rabbitmq.config').with_content(%r{ssl_listeners, \[3141\]}) + should contain_file('rabbitmq.config').with_content(%r{ssl_options, \[\{cacertfile,"/path/to/cacert"}) + should contain_file('rabbitmq.config').with_content(%r{certfile,"/path/to/cert"}) + should contain_file('rabbitmq.config').with_content(%r{keyfile,"/path/to/key}) + should contain_file('rabbitmq.config').with_content(%r{ssl, \[\{versions, \['tlsv1.1', 'tlsv1.2'\]\}\]}) + should contain_file('rabbitmq.config').with_content(%r{versions, \['tlsv1.1', 'tlsv1.2'\]}) + end + end + + describe 'ssl options with invalid ssl_versions type' do + let(:params) { + { :ssl => true, + :ssl_port => 3141, + :ssl_cacert => '/path/to/cacert', + :ssl_cert => '/path/to/cert', + :ssl_key => '/path/to/key', + :ssl_versions => 'tlsv1.2, tlsv1.1' + } } + + it 'fails' do + expect{subject}.to raise_error(/is not an Array/) + end + end + + describe 'ssl options with ssl_versions and not ssl' do + let(:params) { + { :ssl => false, + :ssl_port => 3141, + :ssl_cacert => '/path/to/cacert', + :ssl_cert => '/path/to/cert', + :ssl_key => '/path/to/key', + :ssl_versions => ['tlsv1.2', 'tlsv1.1'] + } } + + it 'fails' do + expect{subject}.to raise_error(/^\$ssl_versions requires that \$ssl => true/) + end + end + + describe 'ssl admin options with specific ssl versions' do + let(:params) { + { :ssl => true, + :ssl_management_port => 5926, + :ssl_cacert => '/path/to/cacert', + :ssl_cert => '/path/to/cert', + :ssl_key => '/path/to/key', + :ssl_versions => ['tlsv1.2', 'tlsv1.1'], + :admin_enable => true + } } + + it 'should set admin ssl opts to specified values' do + should contain_file('rabbitmq.config').with_content(%r{rabbitmq_management, \[}) + should contain_file('rabbitmq.config').with_content(%r{listener, \[}) + should contain_file('rabbitmq.config').with_content(%r{port, 5926\}}) + should contain_file('rabbitmq.config').with_content(%r{ssl, true\}}) + should contain_file('rabbitmq.config').with_content(%r{ssl_opts, \[\{cacertfile, "/path/to/cacert"\},}) + should contain_file('rabbitmq.config').with_content(%r{certfile, "/path/to/cert"\},}) + should contain_file('rabbitmq.config').with_content(%r{keyfile, "/path/to/key"\}}) + should contain_file('rabbitmq.config').with_content(%r{,\{versions, \['tlsv1.1', 'tlsv1.2'\]\}[\r\n ]*\]\}}) + end + end + describe 'ssl admin options' do let(:params) { { :ssl => true, @@ -380,7 +593,7 @@ should contain_file('rabbitmq.config').with_content(%r{ssl, true\}}) should contain_file('rabbitmq.config').with_content(%r{ssl_opts, \[\{cacertfile, "/path/to/cacert"\},}) should contain_file('rabbitmq.config').with_content(%r{certfile, "/path/to/cert"\},}) - should contain_file('rabbitmq.config').with_content(%r{keyfile, "/path/to/key"\}\]\}}) + should contain_file('rabbitmq.config').with_content(%r{keyfile, "/path/to/key"\}[\r\n ]*\]\}}) end end @@ -415,7 +628,7 @@ should contain_file('rabbitmq.config').with_content(%r{ssl, true\},}) should contain_file('rabbitmq.config').with_content(%r{ssl_opts, \[\{cacertfile, "/path/to/cacert"\},}) should contain_file('rabbitmq.config').with_content(%r{certfile, "/path/to/cert"\},}) - should contain_file('rabbitmq.config').with_content(%r{keyfile, "/path/to/key"\}\]\}}) + should contain_file('rabbitmq.config').with_content(%r{keyfile, "/path/to/key"\}[\r\n ]*\]\}}) end end @@ -460,7 +673,7 @@ it 'should set config variables' do should contain_file('rabbitmq.config') \ .with_content(/\{inet_dist_listen_min, 9100\}/) \ - .with_content(/\{inet_dist_listen_max, 9105\}/) + .with_content(/\{inet_dist_listen_max, 9105\}/) end end @@ -564,7 +777,7 @@ should contain_package('rabbitmq-server').with( 'ensure' => 'installed', 'name' => 'rabbitmq-server', - 'provider' => 'yum', + 'provider' => 'rpm', 'source' => 'http://www.rabbitmq.com/releases/rabbitmq-server/v3.2.3/rabbitmq-server-3.2.3-1.noarch.rpm' ) end @@ -602,7 +815,7 @@ 'release' => 'testing', 'repos' => 'main', 'include_src' => false, - 'key' => '056E8E56' + 'key' => 'F7B8CEA6056E8E56' ) } end end @@ -616,7 +829,7 @@ 'release' => 'testing', 'repos' => 'main', 'include_src' => false, - 'key' => '056E8E56' + 'key' => 'F7B8CEA6056E8E56' ) } it { should contain_apt__pin('rabbitmq').with( diff --git a/rabbitmq/spec/spec_helper_acceptance.rb b/rabbitmq/spec/spec_helper_acceptance.rb index 1dbc82a86..4c52dee15 100644 --- a/rabbitmq/spec/spec_helper_acceptance.rb +++ b/rabbitmq/spec/spec_helper_acceptance.rb @@ -20,8 +20,8 @@ # Readable test descriptions c.formatter = :documentation c.before :suite do - puppet_module_install(:source => proj_root, :module_name => 'rabbitmq') hosts.each do |host| + copy_module_to(host, :source => proj_root, :module_name => 'rabbitmq') shell("/bin/touch #{default['puppetpath']}/hiera.yaml") shell('puppet module install puppetlabs-stdlib', { :acceptable_exit_codes => [0,1] }) diff --git a/rabbitmq/spec/unit/facts/rabbitmq_erlang_cookie_spec.rb b/rabbitmq/spec/unit/facts/rabbitmq_erlang_cookie_spec.rb deleted file mode 100644 index f4daf79bd..000000000 --- a/rabbitmq/spec/unit/facts/rabbitmq_erlang_cookie_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' - -describe 'rabbitmq_erlang_cookie', :type => :fact do - before(:each) { Facter.clear } - - it 'works correctly' do - Facter.fact(:osfamily).stubs(:value).returns('RedHat') - File.stubs(:exists?).with('/var/lib/rabbitmq/.erlang.cookie').returns(true) - File.stubs(:read).with('/var/lib/rabbitmq/.erlang.cookie').returns('THISISACOOKIE') - Facter.fact(:rabbitmq_erlang_cookie).value.should == 'THISISACOOKIE' - end - - it 'fails if file doesnt exist' do - Facter.fact(:osfamily).stubs(:value).returns('RedHat') - File.stubs(:exists?).with('/var/lib/rabbitmq/.erlang.cookie').returns(false) - Facter.fact(:rabbitmq_erlang_cookie).value.should == nil - end - -end diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_binding/rabbitmqadmin_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_binding/rabbitmqadmin_spec.rb new file mode 100644 index 000000000..d1ff0667c --- /dev/null +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_binding/rabbitmqadmin_spec.rb @@ -0,0 +1,59 @@ +require 'puppet' +require 'mocha/api' +RSpec.configure do |config| + config.mock_with :mocha +end +provider_class = Puppet::Type.type(:rabbitmq_binding).provider(:rabbitmqadmin) +describe provider_class do + before :each do + @resource = Puppet::Type::Rabbitmq_binding.new( + {:name => 'source@target@/', + :destination_type => :queue, + :routing_key => 'blablub', + :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_bindings', '-q', '-p', '/', 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments').returns <<-EOT + queue queue queue [] +EOT + instances = provider_class.instances + instances.size.should == 1 + end + + it 'should call rabbitmqadmin to create' do + @provider.expects(:rabbitmqadmin).with('declare', 'binding', '--vhost=/', '--user=guest', '--password=guest', 'source=source', 'destination=target', 'arguments={}', 'routing_key=blablub', 'destination_type=queue') + @provider.create + end + + it 'should call rabbitmqadmin to destroy' do + @provider.expects(:rabbitmqadmin).with('delete', 'binding', '--vhost=/', '--user=guest', '--password=guest', 'source=source', 'destination_type=queue', 'destination=target') + @provider.destroy + end + + context 'specifying credentials' do + before :each do + @resource = Puppet::Type::Rabbitmq_binding.new( + {:name => 'source@test2@/', + :destination_type => :queue, + :routing_key => 'blablubd', + :arguments => {}, + :user => 'colin', + :password => 'secret' + } + ) + @provider = provider_class.new(@resource) + end + + it 'should call rabbitmqadmin to create' do + @provider.expects(:rabbitmqadmin).with('declare', 'binding', '--vhost=/', '--user=colin', '--password=secret', 'source=source', 'destination=test2', 'arguments={}', 'routing_key=blablubd', 'destination_type=queue') + @provider.create + end + end +end diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_exchange/rabbitmqadmin_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_exchange/rabbitmqadmin_spec.rb index ac68970cf..89d6e94e3 100644 --- a/rabbitmq/spec/unit/puppet/provider/rabbitmq_exchange/rabbitmqadmin_spec.rb +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_exchange/rabbitmqadmin_spec.rb @@ -36,12 +36,12 @@ end it 'should call rabbitmqadmin to create' do - @provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=amq.direct', 'type=topic') + @provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=amq.direct', 'type=topic', '-c', '/etc/rabbitmq/rabbitmqadmin.conf') @provider.create end it 'should call rabbitmqadmin to destroy' do - @provider.expects(:rabbitmqadmin).with('delete', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=amq.direct') + @provider.expects(:rabbitmqadmin).with('delete', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=amq.direct', '-c', '/etc/rabbitmq/rabbitmqadmin.conf') @provider.destroy end @@ -58,7 +58,7 @@ end it 'should call rabbitmqadmin to create' do - @provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=colin', '--password=secret', 'name=amq.direct', 'type=topic') + @provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=colin', '--password=secret', 'name=amq.direct', 'type=topic', '-c', '/etc/rabbitmq/rabbitmqadmin.conf') @provider.create end end diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_plugin/rabbitmqctl_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_plugin/rabbitmqctl_spec.rb new file mode 100644 index 000000000..c398b6292 --- /dev/null +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_plugin/rabbitmqctl_spec.rb @@ -0,0 +1,26 @@ +require 'puppet' +require 'mocha' +RSpec.configure do |config| + config.mock_with :mocha +end +provider_class = Puppet::Type.type(:rabbitmq_plugin).provider(:rabbitmqplugins) +describe provider_class do + before :each do + @resource = Puppet::Type::Rabbitmq_plugin.new( + {:name => 'foo'} + ) + @provider = provider_class.new(@resource) + end + it 'should match plugins' do + @provider.expects(:rabbitmqplugins).with('list', '-E', '-m').returns("foo\n") + @provider.exists?.should == 'foo' + end + it 'should call rabbitmqplugins to enable' do + @provider.expects(:rabbitmqplugins).with('enable', 'foo') + @provider.create + end + it 'should call rabbitmqplugins to disable' do + @provider.expects(:rabbitmqplugins).with('disable', 'foo') + @provider.destroy + end +end diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_policy/rabbitmqctl_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_policy/rabbitmqctl_spec.rb new file mode 100644 index 000000000..cddb6c0c0 --- /dev/null +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_policy/rabbitmqctl_spec.rb @@ -0,0 +1,114 @@ +require 'puppet' +require 'mocha' + +RSpec.configure do |config| + config.mock_with :mocha +end + +describe Puppet::Type.type(:rabbitmq_policy).provider(:rabbitmqctl) do + + let(:resource) do + Puppet::Type.type(:rabbitmq_policy).new( + :name => 'ha-all@/', + :pattern => '.*', + :definition => { + 'ha-mode' => 'all' + }, + :provider => described_class.name + ) + end + + let(:provider) { resource.provider } + + after(:each) do + described_class.instance_variable_set(:@policies, nil) + end + + it 'should accept @ in policy name' do + resource = Puppet::Type.type(:rabbitmq_policy).new( + :name => 'ha@home@/', + :pattern => '.*', + :definition => { + 'ha-mode' => 'all' + }, + :provider => described_class.name + ) + provider = described_class.new(resource) + provider.should_policy.should == 'ha@home' + provider.should_vhost.should == '/' + end + + it 'should fail with invalid output from list' do + provider.class.expects(:rabbitmqctl).with('list_policies', '-q', '-p', '/').returns 'foobar' + expect { provider.exists? }.to raise_error(Puppet::Error, /cannot parse line from list_policies/) + end + + it 'should match policies from list (>=3.2.0)' do + provider.class.expects(:rabbitmqctl).with('list_policies', '-q', '-p', '/').returns <<-EOT +/ ha-all all .* {"ha-mode":"all","ha-sync-mode":"automatic"} 0 +/ test exchanges .* {"ha-mode":"all"} 0 +EOT + provider.exists?.should == { + :applyto => 'all', + :pattern => '.*', + :priority => '0', + :definition => { + 'ha-mode' => 'all', + 'ha-sync-mode' => 'automatic'} + } + end + + it 'should match policies from list (<3.2.0)' do + provider.class.expects(:rabbitmqctl).with('list_policies', '-q', '-p', '/').returns <<-EOT +/ ha-all .* {"ha-mode":"all","ha-sync-mode":"automatic"} 0 +/ test .* {"ha-mode":"all"} 0 +EOT + provider.exists?.should == { + :applyto => 'all', + :pattern => '.*', + :priority => '0', + :definition => { + 'ha-mode' => 'all', + 'ha-sync-mode' => 'automatic'} + } + end + + it 'should not match an empty list' do + provider.class.expects(:rabbitmqctl).with('list_policies', '-q', '-p', '/').returns '' + provider.exists?.should == nil + end + + it 'should destroy policy' do + provider.expects(:rabbitmqctl).with('clear_policy', '-p', '/', 'ha-all') + provider.destroy + end + + it 'should only call set_policy once (<3.2.0)' do + provider.class.expects(:rabbitmq_version).returns '3.1.0' + provider.resource[:priority] = '10' + provider.resource[:applyto] = 'exchanges' + provider.expects(:rabbitmqctl).with('set_policy', + '-p', '/', + 'ha-all', + '.*', + '{"ha-mode":"all"}', + '10').once + provider.priority = '10' + provider.applyto = 'exchanges' + end + + it 'should only call set_policy once (>=3.2.0)' do + provider.class.expects(:rabbitmq_version).returns '3.2.0' + provider.resource[:priority] = '10' + provider.resource[:applyto] = 'exchanges' + provider.expects(:rabbitmqctl).with('set_policy', + '-p', '/', + '--priority', '10', + '--apply-to', 'exchanges', + 'ha-all', + '.*', + '{"ha-mode":"all"}').once + provider.priority = '10' + provider.applyto = 'exchanges' + end +end diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_queue/rabbitmqadmin_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_queue/rabbitmqadmin_spec.rb new file mode 100644 index 000000000..97410a8b4 --- /dev/null +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_queue/rabbitmqadmin_spec.rb @@ -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 diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_user/rabbitmqctl_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_user/rabbitmqctl_spec.rb index 2c13b886a..2012ccc05 100644 --- a/rabbitmq/spec/unit/puppet/provider/rabbitmq_user/rabbitmqctl_spec.rb +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_user/rabbitmqctl_spec.rb @@ -12,44 +12,34 @@ @provider = provider_class.new(@resource) end it 'should match user names' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo -...done. EOT @provider.exists?.should == 'foo' end it 'should match user names with 2.4.1 syntax' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo bar -...done. EOT @provider.exists?.should == 'foo bar' end it 'should not match if no users on system' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... -...done. + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT EOT @provider.exists?.should be_nil end it 'should not match if no matching users on system' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT fooey -...done. EOT @provider.exists?.should be_nil end it 'should match user names from list' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT one two three foo bar -...done. EOT @provider.exists?.should == 'foo' end @@ -62,13 +52,11 @@ @resource[:password] = 'bar' @resource[:admin] = 'true' @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar') - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['administrator']) @provider.create @@ -78,99 +66,81 @@ @provider.destroy end it 'should be able to retrieve admin value' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [administrator] -...done. EOT @provider.admin.should == :true - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT one [administrator] foo [] -...done. EOT @provider.admin.should == :false end it 'should fail if admin value is invalid' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo fail -...done. EOT expect { @provider.admin }.to raise_error(Puppet::Error, /Could not match line/) end it 'should be able to set admin value' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['administrator']) @provider.admin=:true end it 'should not interfere with existing tags on the user when setting admin value' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [bar, baz] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT - @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['bar','baz', 'administrator'].sort) + @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['bar','baz', 'administrator'].sort) @provider.admin=:true end it 'should be able to unset admin value' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [administrator] guest [administrator] icinga [] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', []) @provider.admin=:false end it 'should not interfere with existing tags on the user when unsetting admin value' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [administrator, bar, baz] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT - @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['bar','baz'].sort) + @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['bar','baz'].sort) @provider.admin=:false end it 'should clear all tags on existing user' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT one [administrator] foo [tag1,tag2] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', []) @provider.tags=[] end it 'should set multiple tags' do - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT one [administrator] foo [] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['tag1','tag2']) @provider.tags=['tag1','tag2'] @@ -178,14 +148,12 @@ it 'should clear tags while keep admin tag' do @resource[:admin] = true - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT one [administrator] foo [administrator, tag1, tag2] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator"]) @provider.tags=[] @@ -193,14 +161,12 @@ it 'should change tags while keep admin tag' do @resource[:admin] = true - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT one [administrator] foo [administrator, tag1, tag2] icinga [monitoring] kitchen [] kitchen2 [abc, def, ghi] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator","tag1","tag3","tag7"]) @provider.tags=['tag1','tag7','tag3'] @@ -210,10 +176,8 @@ @resource[:tags] = [ "tag1", "tag2" ] @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar') @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["tag1","tag2"]) - @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').returns <<-EOT foo [] -...done. EOT @provider.create end @@ -222,15 +186,12 @@ @resource[:tags] = [ "tag1", "tag2" ] @resource[:admin] = true @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar') - @provider.expects(:rabbitmqctl).with('list_users').twice.returns <<-EOT -Listing users ... + @provider.expects(:rabbitmqctl).with('-q', 'list_users').twice.returns <<-EOT foo [] -...done. EOT @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator"]) @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator","tag1","tag2"]) @provider.create end - end diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_user_permissions/rabbitmqctl_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_user_permissions/rabbitmqctl_spec.rb index a8824fdf4..bdbc73e82 100644 --- a/rabbitmq/spec/unit/puppet/provider/rabbitmq_user_permissions/rabbitmqctl_spec.rb +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_user_permissions/rabbitmqctl_spec.rb @@ -15,33 +15,25 @@ @provider_class.instance_variable_set(:@users, nil) end it 'should match user permissions from list' do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 1 2 3 -...done. EOT @provider.exists?.should == {:configure=>"1", :write=>"2", :read=>"3"} end it 'should match user permissions with empty columns' do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 3 -...done. EOT @provider.exists?.should == {:configure=>"", :write=>"", :read=>"3"} end it 'should not match user permissions with more than 3 columns' do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 1 2 3 4 -...done. EOT expect { @provider.exists? }.to raise_error(Puppet::Error, /cannot parse line from list_user_permissions/) end it 'should not match an empty list' do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... -...done. + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT EOT @provider.exists?.should == nil end @@ -49,30 +41,26 @@ @provider.instance_variable_set(:@should_vhost, "bar") @provider.instance_variable_set(:@should_user, "foo") @provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', "''", "''", "''") - @provider.create + @provider.create end it 'should destroy permissions' do @provider.instance_variable_set(:@should_vhost, "bar") @provider.instance_variable_set(:@should_user, "foo") @provider.expects(:rabbitmqctl).with('clear_permissions', '-p', 'bar', 'foo') - @provider.destroy + @provider.destroy end {:configure_permission => '1', :write_permission => '2', :read_permission => '3'}.each do |k,v| it "should be able to retrieve #{k}" do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 1 2 3 -...done. EOT @provider.send(k).should == v end end {:configure_permission => '1', :write_permission => '2', :read_permission => '3'}.each do |k,v| it "should be able to retrieve #{k} after exists has been called" do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 1 2 3 -...done. EOT @provider.exists? @provider.send(k).should == v @@ -83,10 +71,8 @@ :write_permission => ['1', 'foo', '3'] }.each do |perm, columns| it "should be able to sync #{perm}" do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 1 2 3 -...done. EOT @provider.resource[perm] = 'foo' @provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', *columns) @@ -94,10 +80,8 @@ end end it 'should only call set_permissions once' do - @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT -Listing users ... + @provider.class.expects(:rabbitmqctl).with('-q', 'list_user_permissions', 'foo').returns <<-EOT bar 1 2 3 -...done. EOT @provider.resource[:configure_permission] = 'foo' @provider.resource[:read_permission] = 'foo' diff --git a/rabbitmq/spec/unit/puppet/provider/rabbitmq_vhost/rabbitmqctl_spec.rb b/rabbitmq/spec/unit/puppet/provider/rabbitmq_vhost/rabbitmqctl_spec.rb index a1f89ad2c..6c8cce8df 100644 --- a/rabbitmq/spec/unit/puppet/provider/rabbitmq_vhost/rabbitmqctl_spec.rb +++ b/rabbitmq/spec/unit/puppet/provider/rabbitmq_vhost/rabbitmqctl_spec.rb @@ -12,7 +12,7 @@ @provider = provider_class.new(@resource) end it 'should match vhost names' do - @provider.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT + @provider.expects(:rabbitmqctl).with('-q', 'list_vhosts').returns <<-EOT Listing vhosts ... foo ...done. @@ -20,14 +20,14 @@ @provider.exists?.should == 'foo' end it 'should not match if no vhosts on system' do - @provider.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT + @provider.expects(:rabbitmqctl).with('-q', 'list_vhosts').returns <<-EOT Listing vhosts ... ...done. EOT @provider.exists?.should be_nil end it 'should not match if no matching vhosts on system' do - @provider.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT + @provider.expects(:rabbitmqctl).with('-q', 'list_vhosts').returns <<-EOT Listing vhosts ... fooey ...done. diff --git a/rabbitmq/spec/unit/puppet/type/rabbitmq_binding_spec.rb b/rabbitmq/spec/unit/puppet/type/rabbitmq_binding_spec.rb new file mode 100644 index 000000000..b0671e7c2 --- /dev/null +++ b/rabbitmq/spec/unit/puppet/type/rabbitmq_binding_spec.rb @@ -0,0 +1,50 @@ +require 'puppet' +require 'puppet/type/rabbitmq_binding' +describe Puppet::Type.type(:rabbitmq_binding) do + before :each do + @binding = Puppet::Type.type(:rabbitmq_binding).new( + :name => 'foo@blub@bar', + :destination_type => :queue + ) + end + it 'should accept an queue name' do + @binding[:name] = 'dan@dude@pl' + @binding[:name].should == 'dan@dude@pl' + end + it 'should require a name' do + expect { + Puppet::Type.type(:rabbitmq_binding).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + it 'should not allow whitespace in the name' do + expect { + @binding[:name] = 'b r' + }.to raise_error(Puppet::Error, /Valid values match/) + end + it 'should not allow names without one @' do + expect { + @binding[:name] = 'b_r' + }.to raise_error(Puppet::Error, /Valid values match/) + end + + it 'should not allow names without two @' do + expect { + @binding[:name] = 'b@r' + }.to raise_error(Puppet::Error, /Valid values match/) + end + + it 'should accept an binding destination_type' do + @binding[:destination_type] = :exchange + @binding[:destination_type].should == :exchange + end + + it 'should accept a user' do + @binding[:user] = :root + @binding[:user].should == :root + end + + it 'should accept a password' do + @binding[:password] = :PaSsw0rD + @binding[:password].should == :PaSsw0rD + end +end diff --git a/rabbitmq/spec/unit/puppet/type/rabbitmq_policy_spec.rb b/rabbitmq/spec/unit/puppet/type/rabbitmq_policy_spec.rb new file mode 100644 index 000000000..2a8064a1a --- /dev/null +++ b/rabbitmq/spec/unit/puppet/type/rabbitmq_policy_spec.rb @@ -0,0 +1,91 @@ +require 'puppet' +require 'puppet/type/rabbitmq_policy' + +describe Puppet::Type.type(:rabbitmq_policy) do + + before do + @policy = Puppet::Type.type(:rabbitmq_policy).new( + :name => 'ha-all@/', + :pattern => '.*', + :definition => { + 'ha-mode' => 'all' + }) + end + + it 'should accept a valid name' do + @policy[:name] = 'ha-all@/' + @policy[:name].should == 'ha-all@/' + end + + it 'should require a name' do + expect { + Puppet::Type.type(:rabbitmq_policy).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + it 'should fail when name does not have a @' do + expect { + @policy[:name] = 'ha-all' + }.to raise_error(Puppet::Error, /Valid values match/) + end + + it 'should accept a valid regex for pattern' do + @policy[:pattern] = '.*?' + @policy[:pattern].should == '.*?' + end + + it 'should accept an empty string for pattern' do + @policy[:pattern] = '' + @policy[:pattern].should == '' + end + + it 'should not accept invalid regex for pattern' do + expect { + @policy[:pattern] = '*' + }.to raise_error(Puppet::Error, /Invalid regexp/) + end + + it 'should accept valid value for applyto' do + [:all, :exchanges, :queues].each do |v| + @policy[:applyto] = v + @policy[:applyto].should == v + end + end + + it 'should not accept invalid value for applyto' do + expect { + @policy[:applyto] = 'me' + }.to raise_error(Puppet::Error, /Invalid value/) + end + + it 'should accept a valid hash for definition' do + definition = {'ha-mode' => 'all', 'ha-sync-mode' => 'automatic'} + @policy[:definition] = definition + @policy[:definition].should == definition + end + + it 'should not accept invalid hash for definition' do + expect { + @policy[:definition] = 'ha-mode' + }.to raise_error(Puppet::Error, /Invalid definition/) + + expect { + @policy[:definition] = {'ha-mode' => ['a', 'b']} + }.to raise_error(Puppet::Error, /Invalid definition/) + end + + it 'should accept valid value for priority' do + [0, 10, '0', '10'].each do |v| + @policy[:priority] = v + @policy[:priority].should == v + end + end + + it 'should not accept invalid value for priority' do + ['-1', -1, '1.0', 1.0, 'abc', ''].each do |v| + expect { + @policy[:priority] = v + }.to raise_error(Puppet::Error, /Invalid value/) + end + end +end diff --git a/rabbitmq/spec/unit/puppet/type/rabbitmq_queue_spec.rb b/rabbitmq/spec/unit/puppet/type/rabbitmq_queue_spec.rb new file mode 100644 index 000000000..4fd7b34ef --- /dev/null +++ b/rabbitmq/spec/unit/puppet/type/rabbitmq_queue_spec.rb @@ -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 diff --git a/rabbitmq/templates/rabbitmq.config.erb b/rabbitmq/templates/rabbitmq.config.erb index 8f6b14f75..591a1cb17 100644 --- a/rabbitmq/templates/rabbitmq.config.erb +++ b/rabbitmq/templates/rabbitmq.config.erb @@ -1,12 +1,15 @@ % This file managed by Puppet % Template Path: <%= @module_name %>/templates/rabbitmq.config [ +<%- if @ssl and @ssl_versions -%> + {ssl, [{versions, [<%= @ssl_versions.sort.map { |v| "'#{v}'" }.join(', ') %>]}]}, +<%- end -%> {rabbit, [ <% if @ldap_auth -%> {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]}, <% end -%> <% if @config_cluster -%> - {cluster_nodes, {[<%= @r_cluster_nodes.map { |n| "\'rabbit@#{n}\'" }.join(', ') %>], <%= @cluster_node_type %>}}, + {cluster_nodes, {[<%= @cluster_nodes.map { |n| "\'rabbit@#{n}\'" }.join(', ') %>], <%= @cluster_node_type %>}}, {cluster_partition_handling, <%= @cluster_partition_handling %>}, <% end -%> <%- if @tcp_keepalive -%> @@ -17,11 +20,14 @@ <%- end -%> <%- if @ssl -%> {ssl_listeners, [<%= @ssl_port %>]}, - {ssl_options, [{cacertfile,"<%= @ssl_cacert %>"}, + {ssl_options, [<%- if @ssl_cacert != 'UNSET' -%>{cacertfile,"<%= @ssl_cacert %>"},<%- end -%> {certfile,"<%= @ssl_cert %>"}, {keyfile,"<%= @ssl_key %>"}, {verify,<%= @ssl_verify %>}, - {fail_if_no_peer_cert,<%= @ssl_fail_if_no_peer_cert %>}]}, + {fail_if_no_peer_cert,<%= @ssl_fail_if_no_peer_cert %>} + <%- if @ssl_versions -%> + ,{versions, [<%= @ssl_versions.sort.map { |v| "'#{v}'" }.join(', ') %>]} + <% end -%>]}, <%- end -%> <% if @config_variables -%> <%- @config_variables.keys.sort.each do |key| -%> @@ -41,9 +47,12 @@ <%- if @ssl -%> {port, <%= @ssl_management_port %>}, {ssl, true}, - {ssl_opts, [{cacertfile, "<%= @ssl_cacert %>"}, + {ssl_opts, [<%- if @ssl_cacert != 'UNSET' -%>{cacertfile, "<%= @ssl_cacert %>"},<%- end -%> {certfile, "<%= @ssl_cert %>"}, - {keyfile, "<%= @ssl_key %>"}]} + {keyfile, "<%= @ssl_key %>"} + <%- if @ssl_versions -%> + ,{versions, [<%= @ssl_versions.sort.map { |v| "'#{v}'" }.join(', ') %>]} + <% end -%>]} <%- else -%> {port, <%= @management_port %>} <%- end -%> diff --git a/rabbitmq/templates/rabbitmqadmin.conf.erb b/rabbitmq/templates/rabbitmqadmin.conf.erb new file mode 100644 index 000000000..d76c81147 --- /dev/null +++ b/rabbitmq/templates/rabbitmqadmin.conf.erb @@ -0,0 +1,7 @@ +[default] +<% if @ssl -%> +ssl = True +port = <%= @ssl_management_port %> +<% else -%> +port = <%= @management_port %> +<% end -%>