├── .editorconfig ├── .fixtures.yml ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── labeler.yml ├── release.yml └── workflows │ ├── ci.yml │ ├── labeler.yml │ ├── prepare_release.yml │ └── release.yml ├── .gitignore ├── .msync.yml ├── .overcommit.yml ├── .pmtignore ├── .project ├── .puppet-lint.rc ├── .rubocop.yml ├── .rubocop_todo.yml ├── .sync.yml ├── CHANGELOG.md ├── Gemfile ├── HISTORY.md ├── LICENSE ├── MAINTAINERS.md ├── NOTICE ├── README.md ├── REFERENCE.md ├── Rakefile ├── data ├── common.yaml ├── family │ ├── Archlinux.yaml │ ├── Debian.yaml │ ├── FreeBSD.yaml │ ├── OpenBSD.yaml │ ├── RedHat.yaml │ └── Suse.yaml └── os │ └── CentOS.yaml ├── examples ├── cluster │ └── join_cluster_and_change_name.pp ├── erlang_deps.pp ├── full.pp ├── permissions │ └── add.pp ├── plugin.pp ├── repo │ └── apt.pp ├── site.pp ├── user │ └── add.pp └── vhosts │ └── add.pp ├── files ├── README.markdown └── plugins │ ├── amqp_client-2.3.1.ez │ └── rabbit_stomp-2.3.1.ez ├── hiera.yaml ├── lib ├── facter │ ├── erl_ssl_path.rb │ ├── rabbitmq_clustername.rb │ ├── rabbitmq_nodename.rb │ ├── rabbitmq_plugins_dirs.rb │ └── rabbitmq_version.rb └── puppet │ ├── provider │ ├── rabbitmq_binding │ │ └── rabbitmqadmin.rb │ ├── rabbitmq_cli.rb │ ├── rabbitmq_cluster │ │ └── rabbitmqctl.rb │ ├── rabbitmq_erlang_cookie │ │ └── ruby.rb │ ├── rabbitmq_exchange │ │ └── rabbitmqadmin.rb │ ├── rabbitmq_parameter │ │ └── rabbitmqctl.rb │ ├── rabbitmq_plugin │ │ └── rabbitmqplugins.rb │ ├── rabbitmq_policy │ │ └── rabbitmqctl.rb │ ├── rabbitmq_queue │ │ └── rabbitmqadmin.rb │ ├── rabbitmq_user │ │ └── rabbitmqctl.rb │ ├── rabbitmq_user_permissions │ │ └── rabbitmqctl.rb │ └── rabbitmq_vhost │ │ └── rabbitmqctl.rb │ └── type │ ├── rabbitmq_binding.rb │ ├── rabbitmq_cluster.rb │ ├── rabbitmq_erlang_cookie.rb │ ├── rabbitmq_exchange.rb │ ├── rabbitmq_parameter.rb │ ├── rabbitmq_plugin.rb │ ├── rabbitmq_policy.rb │ ├── rabbitmq_queue.rb │ ├── rabbitmq_user.rb │ ├── rabbitmq_user_permissions.rb │ └── rabbitmq_vhost.rb ├── locales └── config.yaml ├── manifests ├── config.pp ├── init.pp ├── install.pp ├── install │ └── rabbitmqadmin.pp ├── management.pp ├── repo │ ├── apt.pp │ └── rhel.pp └── service.pp ├── metadata.json ├── spec ├── README.markdown ├── acceptance │ ├── class_spec.rb │ ├── clustering_spec.rb │ ├── delete_guest_user_spec.rb │ ├── parameter_spec.rb │ ├── policy_spec.rb │ ├── queue_spec.rb │ ├── rabbitmqadmin_spec.rb │ ├── user_spec.rb │ └── vhost_spec.rb ├── classes │ └── rabbitmq_spec.rb ├── spec_helper.rb ├── spec_helper_acceptance.rb ├── spec_helper_local.rb └── unit │ ├── facter │ └── util │ │ ├── fact_erl_ssl_path_spec.rb │ │ ├── fact_rabbitmq_clustername_spec.rb │ │ ├── fact_rabbitmq_nodename_spec.rb │ │ ├── fact_rabbitmq_plugins_dirs_spec.rb │ │ └── fact_rabbitmq_version_spec.rb │ └── puppet │ ├── provider │ ├── rabbitmq_binding │ │ └── rabbitmqadmin_spec.rb │ ├── rabbitmq_cli_spec.rb │ ├── rabbitmq_cluster │ │ └── rabbitmqctl_spec.rb │ ├── rabbitmq_exchange │ │ └── rabbitmqadmin_spec.rb │ ├── rabbitmq_parameter │ │ ├── rabbitmqctl_federation_spec.rb │ │ └── rabbitmqctl_spec.rb │ ├── rabbitmq_plugin │ │ └── rabbitmqctl_spec.rb │ ├── rabbitmq_policy │ │ └── rabbitmqctl_spec.rb │ ├── rabbitmq_queue │ │ └── rabbitmqadmin_spec.rb │ ├── rabbitmq_user │ │ └── rabbitmqctl_spec.rb │ ├── rabbitmq_user_permissions │ │ └── rabbitmqctl_spec.rb │ └── rabbitmq_vhost │ │ └── rabbitmqctl_spec.rb │ └── type │ ├── rabbitmq_binding_spec.rb │ ├── rabbitmq_cluster_spec.rb │ ├── rabbitmq_exchange_spec.rb │ ├── rabbitmq_parameter_spec.rb │ ├── rabbitmq_plugin_spec.rb │ ├── rabbitmq_policy_spec.rb │ ├── rabbitmq_queue_spec.rb │ ├── rabbitmq_user_permissions_spec.rb │ ├── rabbitmq_user_spec.rb │ └── rabbitmq_vhost_spec.rb └── templates ├── README.markdown ├── enabled_plugins.epp ├── inetrc.erb ├── limits.conf ├── rabbitmq-env.conf.epp ├── rabbitmq.config.epp └── rabbitmqadmin.conf.epp /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | root = true 7 | 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | tab_width = 2 13 | indent_style = space 14 | insert_final_newline = true 15 | trim_trailing_whitespace = true 16 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fixtures: 3 | repositories: 4 | stdlib: 'https://github.com/puppetlabs/puppetlabs-stdlib' 5 | apt: 'https://github.com/puppetlabs/puppetlabs-apt' 6 | archive: 'https://github.com/voxpupuli/puppet-archive' 7 | systemd: 'https://github.com/voxpupuli/puppet-systemd' 8 | yumrepo_core: 'https://github.com/puppetlabs/puppetlabs-yumrepo_core' 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | #This file is generated by ModuleSync, do not edit. 2 | *.rb eol=lf 3 | *.erb eol=lf 4 | *.pp eol=lf 5 | *.sh eol=lf 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | ## Affected Puppet, Ruby, OS and module versions/distributions 12 | 13 | - Puppet: 14 | - Ruby: 15 | - Distribution: 16 | - Module version: 17 | 18 | ## How to reproduce (e.g Puppet code you use) 19 | 20 | ## What are you seeing 21 | 22 | ## What behaviour did you expect instead 23 | 24 | ## Output log 25 | 26 | ## Any additional information you'd like to impart 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | #### Pull Request (PR) description 10 | 13 | 14 | #### This Pull Request (PR) fixes the following issues 15 | 21 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | skip-changelog: 6 | - head-branch: ['^release-*', 'release'] 7 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes 6 | 7 | changelog: 8 | exclude: 9 | labels: 10 | - duplicate 11 | - invalid 12 | - modulesync 13 | - question 14 | - skip-changelog 15 | - wont-fix 16 | - wontfix 17 | 18 | categories: 19 | - title: Breaking Changes 🛠 20 | labels: 21 | - backwards-incompatible 22 | 23 | - title: New Features 🎉 24 | labels: 25 | - enhancement 26 | 27 | - title: Bug Fixes 🐛 28 | labels: 29 | - bug 30 | 31 | - title: Documentation Updates 📚 32 | labels: 33 | - documentation 34 | - docs 35 | 36 | - title: Dependency Updates ⬆️ 37 | labels: 38 | - dependencies 39 | 40 | - title: Other Changes 41 | labels: 42 | - "*" 43 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: CI 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | pull_request: {} 10 | push: 11 | branches: 12 | - main 13 | - master 14 | 15 | concurrency: 16 | group: ${{ github.ref_name }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | puppet: 21 | name: Puppet 22 | uses: voxpupuli/gha-puppet/.github/workflows/beaker.yml@v3 23 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: "Pull Request Labeler" 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | pull_request_target: {} 10 | 11 | jobs: 12 | labeler: 13 | permissions: 14 | contents: read 15 | pull-requests: write 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/labeler@v5 19 | -------------------------------------------------------------------------------- /.github/workflows/prepare_release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: 'Prepare Release' 6 | 7 | on: 8 | workflow_dispatch: 9 | inputs: 10 | version: 11 | description: 'Module version to be released. Must be a valid semver string without leading v. (1.2.3)' 12 | required: false 13 | 14 | jobs: 15 | release_prep: 16 | uses: 'voxpupuli/gha-puppet/.github/workflows/prepare_release.yml@v3' 17 | with: 18 | version: ${{ github.event.inputs.version }} 19 | allowed_owner: 'voxpupuli' 20 | secrets: 21 | # Configure secrets here: 22 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 23 | github_pat: '${{ secrets.PCCI_PAT_RELEASE_PREP }}' 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: Release 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | push: 10 | tags: 11 | - '*' 12 | 13 | jobs: 14 | release: 15 | name: Release 16 | uses: voxpupuli/gha-puppet/.github/workflows/release.yml@v3 17 | with: 18 | allowed_owner: 'voxpupuli' 19 | secrets: 20 | # Configure secrets here: 21 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 22 | username: ${{ secrets.PUPPET_FORGE_USERNAME }} 23 | api_key: ${{ secrets.PUPPET_FORGE_API_KEY }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | /pkg/ 5 | /Gemfile.lock 6 | /Gemfile.local 7 | /vendor/ 8 | /.vendor/ 9 | /spec/fixtures/manifests/ 10 | /spec/fixtures/modules/ 11 | /.vagrant/ 12 | /.bundle/ 13 | /.ruby-version 14 | /coverage/ 15 | /log/ 16 | /.idea/ 17 | /.dependencies/ 18 | /.librarian/ 19 | /Puppetfile.lock 20 | *.iml 21 | .*.sw? 22 | /.yardoc/ 23 | /Guardfile 24 | bolt-debug.log 25 | .rerun.json 26 | -------------------------------------------------------------------------------- /.msync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | modulesync_config_version: '9.5.0' 6 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | # 4 | # Hooks are only enabled if you take action. 5 | # 6 | # To enable the hooks run: 7 | # 8 | # ``` 9 | # bundle exec overcommit --install 10 | # # ensure .overcommit.yml does not harm to you and then 11 | # bundle exec overcommit --sign 12 | # ``` 13 | # 14 | # (it will manage the .git/hooks directory): 15 | # 16 | # Examples howto skip a test for a commit or push: 17 | # 18 | # ``` 19 | # SKIP=RuboCop git commit 20 | # SKIP=PuppetLint git commit 21 | # SKIP=RakeTask git push 22 | # ``` 23 | # 24 | # Don't invoke overcommit at all: 25 | # 26 | # ``` 27 | # OVERCOMMIT_DISABLE=1 git commit 28 | # ``` 29 | # 30 | # Read more about overcommit: https://github.com/brigade/overcommit 31 | # 32 | # To manage this config yourself in your module add 33 | # 34 | # ``` 35 | # .overcommit.yml: 36 | # unmanaged: true 37 | # ``` 38 | # 39 | # to your modules .sync.yml config 40 | --- 41 | PreCommit: 42 | RuboCop: 43 | enabled: true 44 | description: 'Runs rubocop on modified files only' 45 | command: ['bundle', 'exec', 'rubocop'] 46 | RakeTarget: 47 | enabled: true 48 | description: 'Runs lint on modified files only' 49 | targets: 50 | - 'lint' 51 | command: ['bundle', 'exec', 'rake'] 52 | YamlSyntax: 53 | enabled: true 54 | JsonSyntax: 55 | enabled: true 56 | TrailingWhitespace: 57 | enabled: true 58 | 59 | PrePush: 60 | RakeTarget: 61 | enabled: true 62 | description: 'Run rake targets' 63 | targets: 64 | - 'validate' 65 | - 'test' 66 | - 'rubocop' 67 | command: ['bundle', 'exec', 'rake'] 68 | -------------------------------------------------------------------------------- /.pmtignore: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | /docs/ 5 | /pkg/ 6 | /Gemfile 7 | /Gemfile.lock 8 | /Gemfile.local 9 | /vendor/ 10 | /.vendor/ 11 | /spec/ 12 | /Rakefile 13 | /.vagrant/ 14 | /.bundle/ 15 | /.ruby-version 16 | /coverage/ 17 | /log/ 18 | /.idea/ 19 | /.dependencies/ 20 | /.github/ 21 | /.librarian/ 22 | /Puppetfile.lock 23 | /Puppetfile 24 | *.iml 25 | /.editorconfig 26 | /.fixtures.yml 27 | /.gitignore 28 | /.msync.yml 29 | /.overcommit.yml 30 | /.pmtignore 31 | /.rspec 32 | /.rspec_parallel 33 | /.rubocop.yml 34 | /.sync.yml 35 | .*.sw? 36 | /.yardoc/ 37 | /.yardopts 38 | /Dockerfile 39 | /HISTORY.md 40 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | puppetlabs-rabbitmq 4 | 5 | 6 | 7 | 8 | 9 | com.puppetlabs.geppetto.pp.dsl.ui.modulefileBuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.xtext.ui.shared.xtextBuilder 15 | 16 | 17 | 18 | 19 | 20 | com.puppetlabs.geppetto.pp.dsl.ui.puppetNature 21 | org.eclipse.xtext.ui.shared.xtextNature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | --fail-on-warnings 5 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | inherit_from: .rubocop_todo.yml 6 | inherit_gem: 7 | voxpupuli-test: rubocop.yml 8 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2024-05-18 22:27:55 UTC using RuboCop version 1.50.2. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 8 10 | # This cop supports unsafe autocorrection (--autocorrect-all). 11 | RSpec/BeEq: 12 | Exclude: 13 | - 'spec/unit/puppet/provider/rabbitmq_plugin/rabbitmqctl_spec.rb' 14 | - 'spec/unit/puppet/provider/rabbitmq_policy/rabbitmqctl_spec.rb' 15 | - 'spec/unit/puppet/provider/rabbitmq_user_permissions/rabbitmqctl_spec.rb' 16 | - 'spec/unit/puppet/provider/rabbitmq_vhost/rabbitmqctl_spec.rb' 17 | - 'spec/unit/puppet/type/rabbitmq_user_permissions_spec.rb' 18 | 19 | # Offense count: 3 20 | RSpec/PendingWithoutReason: 21 | Exclude: 22 | - 'spec/acceptance/class_spec.rb' 23 | 24 | # Offense count: 4 25 | RSpec/RepeatedExampleGroupBody: 26 | Exclude: 27 | - 'spec/classes/rabbitmq_spec.rb' 28 | 29 | # Offense count: 14 30 | RSpec/RepeatedExampleGroupDescription: 31 | Exclude: 32 | - 'spec/classes/rabbitmq_spec.rb' 33 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spec/spec_helper.rb: 3 | facterdb_string_keys: true 4 | mock_with: ':mocha' 5 | spec_overrides: "require 'spec_helper_local'" 6 | .puppet-lint.rc: 7 | enabled_lint_checks: 8 | - parameter_documentation 9 | - parameter_types 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 5 | 6 | group :test do 7 | gem 'voxpupuli-test', '~> 9.0', :require => false 8 | gem 'coveralls', :require => false 9 | gem 'simplecov-console', :require => false 10 | gem 'puppet_metadata', '~> 5.0', :require => false 11 | end 12 | 13 | group :development do 14 | gem 'guard-rake', :require => false 15 | gem 'overcommit', '>= 0.39.1', :require => false 16 | end 17 | 18 | group :system_tests do 19 | gem 'voxpupuli-acceptance', '~> 3.5', :require => false 20 | end 21 | 22 | group :release do 23 | gem 'voxpupuli-release', '~> 3.0', :require => false 24 | end 25 | 26 | gem 'rake', :require => false 27 | gem 'facter', ENV['FACTER_GEM_VERSION'], :require => false, :groups => [:test] 28 | 29 | puppetversion = ENV['PUPPET_GEM_VERSION'] || [">= 7.24", "< 9"] 30 | gem 'puppet', puppetversion, :require => false, :groups => [:test] 31 | 32 | # vim: syntax=ruby 33 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | ## Maintenance 2 | 3 | Maintainers: 4 | - Puppet Forge Modules Team `forge-modules |at| puppet |dot| com` 5 | 6 | Tickets: https://tickets.puppet.com/browse/MODULES. Make sure to set component to `rabbitmq`. 7 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Puppet Module - puppetlabs-rabbitmq 2 | 3 | Copyright 2017 Puppet, Inc. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rabbitmq 2 | 3 | [![License](https://img.shields.io/github/license/voxpupuli/puppet-rabbitmq.svg)](https://github.com/voxpupuli/puppet-rabbitmq/blob/master/LICENSE) 4 | [![Build Status](https://github.com/voxpupuli/puppet-rabbitmq/actions/workflows/ci.yml/badge.svg)](https://github.com/voxpupuli/puppet-rabbitmq/actions) 5 | [![Puppet Forge](https://img.shields.io/puppetforge/v/puppet/rabbitmq.svg)](https://forge.puppetlabs.com/puppet/rabbitmq) 6 | [![Puppet Forge - downloads](https://img.shields.io/puppetforge/dt/puppet/rabbitmq.svg)](https://forge.puppetlabs.com/puppet/rabbitmq) 7 | [![Puppet Forge - endorsement](https://img.shields.io/puppetforge/e/puppet/rabbitmq.svg)](https://forge.puppetlabs.com/puppet/rabbitmq) 8 | [![Puppet Forge - scores](https://img.shields.io/puppetforge/f/puppet/rabbitmq.svg)](https://forge.puppetlabs.com/puppet/rabbitmq) 9 | 10 | #### Table of Contents 11 | 12 | 1. [Overview](#overview) 13 | 2. [Module Description - What the module does and why it is useful](#module-description) 14 | 3. [Setup - The basics of getting started with rabbitmq](#setup) 15 | * [What rabbitmq affects](#what-rabbitmq-affects) 16 | * [Setup requirements](#setup-requirements) 17 | 4. [Usage - Configuration options and additional functionality](#usage) 18 | 5. [Reference - An under-the-hood peek at what the module is doing and how](#reference) 19 | 5. [Limitations - OS compatibility, etc.](#limitations) 20 | * [RedHat module dependencies](#redhat-module-dependecies) 21 | 6. [Development - Guide for contributing to the module](#development) 22 | 23 | ## Overview 24 | 25 | This module manages RabbitMQ (www.rabbitmq.com) 26 | 27 | ## Module Description 28 | The rabbitmq module sets up rabbitmq and has a number of providers to manage 29 | everything from vhosts to exchanges after setup. 30 | 31 | This module has been tested against 3.5.x and 3.6.x (as well as earlier 32 | versions) and is known to not support all features against versions 33 | prior to 2.7.1. 34 | 35 | ## Setup 36 | 37 | ### What rabbitmq affects 38 | 39 | * rabbitmq repository files. 40 | * rabbitmq package. 41 | * rabbitmq configuration file. 42 | * rabbitmq service. 43 | 44 | ## Usage 45 | 46 | All options and configuration can be done through interacting with the parameters 47 | on the main rabbitmq class. 48 | These are now documented via [Puppet Strings](https://github.com/puppetlabs/puppet-strings) 49 | 50 | You can view example usage in [REFERENCE](REFERENCE.md). 51 | 52 | **[puppet/epel](https://forge.puppet.com/modules/puppet/epel) is a soft dependency. If you're on CentOS 7 and don't want to require it, set `$require_epel` to `false`** 53 | 54 | Version v13.2.0 and older also added an erlang repository on CentOS 7. That isn't used and can be safely removed. 55 | 56 | ## Reference 57 | 58 | See [REFERENCE](REFERENCE.md). 59 | 60 | ## Development 61 | 62 | This module is maintained by [Vox Pupuli](https://voxpupuli.org/). Voxpupuli 63 | welcomes new contributions to this module, especially those that include 64 | documentation and rspec tests. We are happy to provide guidance if necessary. 65 | 66 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for more details. 67 | 68 | ### Authors 69 | * Jeff McCune 70 | * Dan Bode 71 | * RPM/RHEL packages by Vincent Janelle 72 | * Puppetlabs Module Team 73 | * Voxpupuli Team 74 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | # Attempt to load voxpupuli-test (which pulls in puppetlabs_spec_helper), 5 | # otherwise attempt to load it directly. 6 | begin 7 | require 'voxpupuli/test/rake' 8 | rescue LoadError 9 | begin 10 | require 'puppetlabs_spec_helper/rake_tasks' 11 | rescue LoadError 12 | end 13 | end 14 | 15 | # load optional tasks for acceptance 16 | # only available if gem group releases is installed 17 | begin 18 | require 'voxpupuli/acceptance/rake' 19 | rescue LoadError 20 | end 21 | 22 | # load optional tasks for releases 23 | # only available if gem group releases is installed 24 | begin 25 | require 'voxpupuli/release/rake_tasks' 26 | rescue LoadError 27 | # voxpupuli-release not present 28 | else 29 | GCGConfig.user = 'voxpupuli' 30 | GCGConfig.project = 'puppet-rabbitmq' 31 | end 32 | 33 | desc "Run main 'test' task and report merged results to coveralls" 34 | task test_with_coveralls: [:test] do 35 | if Dir.exist?(File.expand_path('../lib', __FILE__)) 36 | require 'coveralls/rake/task' 37 | Coveralls::RakeTask.new 38 | Rake::Task['coveralls:push'].invoke 39 | else 40 | puts 'Skipping reporting to coveralls. Module has no lib dir' 41 | end 42 | end 43 | 44 | # vim: syntax=ruby 45 | -------------------------------------------------------------------------------- /data/common.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::admin_enable: true 3 | rabbitmq::management_enable: false 4 | rabbitmq::use_config_file_for_plugins: false 5 | rabbitmq::cluster: {} 6 | rabbitmq::cluster_node_type: 'disc' 7 | rabbitmq::cluster_nodes: [] 8 | rabbitmq::config: 'rabbitmq/rabbitmq.config.epp' 9 | rabbitmq::config_cluster: false 10 | rabbitmq::config_path: '/etc/rabbitmq/rabbitmq.config' 11 | rabbitmq::config_ranch: true 12 | rabbitmq::config_stomp: false 13 | rabbitmq::config_shovel: false 14 | rabbitmq::config_shovel_statics: {} 15 | rabbitmq::default_user: 'guest' 16 | rabbitmq::default_pass: 'guest' 17 | rabbitmq::delete_guest_user: false 18 | rabbitmq::env_config: 'rabbitmq/rabbitmq-env.conf.epp' 19 | rabbitmq::env_config_path: '/etc/rabbitmq/rabbitmq-env.conf' 20 | rabbitmq::erlang_cookie: ~ 21 | rabbitmq::interface: ~ 22 | rabbitmq::management_ip_address: ~ 23 | rabbitmq::management_port: 15672 24 | rabbitmq::management_ssl: true 25 | rabbitmq::management_hostname: ~ 26 | rabbitmq::node_ip_address: ~ 27 | rabbitmq::package_apt_pin: ~ 28 | rabbitmq::package_ensure: 'installed' 29 | rabbitmq::package_gpg_key: ~ 30 | rabbitmq::repo_gpg_key: ~ 31 | rabbitmq::package_name: 'rabbitmq' 32 | rabbitmq::package_source: ~ 33 | rabbitmq::package_provider: ~ 34 | rabbitmq::repos_ensure: false 35 | rabbitmq::manage_python: true 36 | rabbitmq::python_package: 'python' 37 | rabbitmq::rabbitmq_user: 'rabbitmq' 38 | rabbitmq::rabbitmq_group: 'rabbitmq' 39 | rabbitmq::rabbitmq_home: '/var/lib/rabbitmq' 40 | rabbitmq::port: 5672 41 | rabbitmq::tcp_keepalive: false 42 | rabbitmq::tcp_backlog: 128 43 | rabbitmq::tcp_sndbuf: ~ 44 | rabbitmq::tcp_recbuf: ~ 45 | rabbitmq::heartbeat: ~ 46 | rabbitmq::service_ensure: 'running' 47 | rabbitmq::service_manage: true 48 | rabbitmq::service_name: 'rabbitmq' 49 | rabbitmq::ssl: false 50 | rabbitmq::ssl_only: false 51 | rabbitmq::ssl_cacert: ~ 52 | rabbitmq::ssl_cert: ~ 53 | rabbitmq::ssl_key: ~ 54 | rabbitmq::ssl_depth: ~ 55 | rabbitmq::ssl_cert_password: ~ 56 | rabbitmq::ssl_port: 5671 57 | rabbitmq::ssl_interface: ~ 58 | rabbitmq::ssl_management_port: 15671 59 | rabbitmq::ssl_stomp_port: 6164 60 | rabbitmq::ssl_verify: 'verify_none' 61 | rabbitmq::ssl_fail_if_no_peer_cert: false 62 | rabbitmq::ssl_management_verify: 'verify_none' 63 | rabbitmq::ssl_management_fail_if_no_peer_cert: false 64 | rabbitmq::ssl_versions: ~ 65 | rabbitmq::ssl_secure_renegotiate: true 66 | rabbitmq::ssl_reuse_sessions: true 67 | rabbitmq::ssl_honor_cipher_order: true 68 | rabbitmq::ssl_dhfile: ~ 69 | rabbitmq::ssl_ciphers: [] 70 | rabbitmq::stomp_ensure: false 71 | rabbitmq::ldap_auth: false 72 | rabbitmq::ldap_server: 'ldap' 73 | rabbitmq::ldap_user_dn_pattern: ~ 74 | rabbitmq::ldap_other_bind: 'anon' 75 | rabbitmq::ldap_use_ssl: false 76 | rabbitmq::ldap_port: 389 77 | rabbitmq::ldap_log: false 78 | rabbitmq::ldap_config_variables: {} 79 | rabbitmq::stomp_port: 6163 80 | rabbitmq::stomp_ssl_only: false 81 | rabbitmq::wipe_db_on_cookie_change: false 82 | rabbitmq::cluster_partition_handling: 'ignore' 83 | rabbitmq::file_limit: 16384 84 | rabbitmq::environment_variables: 85 | 'LC_ALL': 'en_US.UTF-8' 86 | rabbitmq::config_variables: {} 87 | rabbitmq::config_kernel_variables: {} 88 | rabbitmq::config_management_variables: {} 89 | rabbitmq::config_additional_variables: {} 90 | rabbitmq::auth_backends: ~ 91 | rabbitmq::key_content: ~ 92 | rabbitmq::collect_statistics_interval: ~ 93 | rabbitmq::ipv6: false 94 | rabbitmq::inetrc_config: 'rabbitmq/inetrc.erb' 95 | rabbitmq::inetrc_config_path: '/etc/rabbitmq/inetrc' 96 | rabbitmq::ssl_erl_dist: false 97 | rabbitmq::rabbitmqadmin_package: ~ 98 | rabbitmq::archive_options: [] 99 | rabbitmq::loopback_users: 100 | - 'guest' 101 | rabbitmq::service_restart: true 102 | -------------------------------------------------------------------------------- /data/family/Archlinux.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::python_package: 'python' 3 | -------------------------------------------------------------------------------- /data/family/Debian.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::python_package: 'python3' 3 | rabbitmq::package_name: 'rabbitmq-server' 4 | rabbitmq::service_name: 'rabbitmq-server' 5 | rabbitmq::package_gpg_key: 'https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey' 6 | -------------------------------------------------------------------------------- /data/family/FreeBSD.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::python_package: 'python38' 3 | rabbitmq::rabbitmq_home: '/var/db/rabbitmq' 4 | rabbitmq::config_path: '/usr/local/etc/rabbitmq/rabbitmq.config' 5 | rabbitmq::env_config_path: '/usr/local/etc/rabbitmq/rabbitmq-env.conf' 6 | rabbitmq::inetrc_config_path: '/usr/local/etc/rabbitmq/inetrc' 7 | -------------------------------------------------------------------------------- /data/family/OpenBSD.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::python_package: 'python2' 3 | rabbitmq::rabbitmq_user: '_rabbitmq' 4 | rabbitmq::rabbitmq_group: '_rabbitmq' 5 | rabbitmq::rabbitmq_home: '/var/rabbitmq' 6 | -------------------------------------------------------------------------------- /data/family/RedHat.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::package_name: 'rabbitmq-server' 3 | rabbitmq::service_name: 'rabbitmq-server' 4 | rabbitmq::package_gpg_key: 'https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc' 5 | rabbitmq::repo_gpg_key: 'https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey' -------------------------------------------------------------------------------- /data/family/Suse.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rabbitmq::package_name: 3 | - 'rabbitmq-server' 4 | - 'rabbitmq-server-plugins' 5 | rabbitmq::service_name: 'rabbitmq-server' 6 | -------------------------------------------------------------------------------- /data/os/CentOS.yaml: -------------------------------------------------------------------------------- 1 | rabbitmq::enable_centos_release: true 2 | -------------------------------------------------------------------------------- /examples/cluster/join_cluster_and_change_name.pp: -------------------------------------------------------------------------------- 1 | # This sets the cluster name to `test_cluster` 2 | # If run on another host than host1, this will join the host1's cluster 3 | rabbitmq_cluster { 'test_cluster': 4 | init_node => 'host1', 5 | } 6 | -------------------------------------------------------------------------------- /examples/erlang_deps.pp: -------------------------------------------------------------------------------- 1 | # install first the garethr-erlang module. See README.md 2 | include erlang 3 | 4 | class { 'erlang': epel_enable => true } 5 | Class['erlang'] -> Class['rabbitmq'] 6 | -------------------------------------------------------------------------------- /examples/full.pp: -------------------------------------------------------------------------------- 1 | class { 'rabbitmq': 2 | delete_guest_user => true, 3 | repos_ensure => true, 4 | package_apt_pin => 900, 5 | } 6 | 7 | -> rabbitmq_user { 'dan': 8 | admin => true, 9 | password => 'pass', 10 | provider => 'rabbitmqctl', 11 | } 12 | 13 | -> rabbitmq_vhost { 'myhost': 14 | provider => 'rabbitmqctl', 15 | } 16 | 17 | rabbitmq_user_permissions { 'dan@myhost': 18 | configure_permission => '.*', 19 | read_permission => '.*', 20 | write_permission => '.*', 21 | provider => 'rabbitmqctl', 22 | } 23 | -------------------------------------------------------------------------------- /examples/permissions/add.pp: -------------------------------------------------------------------------------- 1 | rabbitmq_user { 'blah7': 2 | password => 'foo', 3 | } 4 | rabbitmq_vhost { 'test5': } 5 | rabbitmq_user_permissions { 'blah7@test5': 6 | configure_permission => 'config2', 7 | read_permission => 'ready', 8 | #write_permission => 'ready', 9 | } 10 | -------------------------------------------------------------------------------- /examples/plugin.pp: -------------------------------------------------------------------------------- 1 | $rabbitmq_plugins = ['amqp_client', 'rabbitmq_stomp'] 2 | 3 | class { 'rabbitmq': 4 | config_stomp => true, 5 | } 6 | 7 | rabbitmq_plugin { $rabbitmq_plugins: 8 | ensure => present, 9 | require => Class['rabbitmq'], 10 | provider => 'rabbitmqplugins', 11 | } 12 | -------------------------------------------------------------------------------- /examples/repo/apt.pp: -------------------------------------------------------------------------------- 1 | # requires pupetlabs-apt 2 | include rabbitmq::repo::apt 3 | -------------------------------------------------------------------------------- /examples/site.pp: -------------------------------------------------------------------------------- 1 | node default { 2 | $rabbitmq_plugins = ['amqp_client', 'rabbitmq_stomp'] 3 | 4 | class { 'rabbitmq': 5 | config => '[ {rabbit_stomp, [{tcp_listeners, [1234]} ]} ].', 6 | } 7 | 8 | # Required for MCollective 9 | rabbitmq_plugin { $rabbitmq_plugins: 10 | ensure => present, 11 | require => Class['rabbitmq'], 12 | provider => 'rabbitmqplugins', 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/user/add.pp: -------------------------------------------------------------------------------- 1 | rabbitmq_user { ['blah2', 'blah3', 'blah4']: 2 | password => 'phoey!', 3 | #provider => 'rabbitmqctl', 4 | } 5 | -------------------------------------------------------------------------------- /examples/vhosts/add.pp: -------------------------------------------------------------------------------- 1 | rabbitmq_vhost { ['fooey', 'blah']: } 2 | -------------------------------------------------------------------------------- /files/README.markdown: -------------------------------------------------------------------------------- 1 | Files 2 | ===== 3 | 4 | Puppet comes with both a client and server for copying files around. The file 5 | serving function is provided as part of the central Puppet daemon, 6 | puppetmasterd, and the client function is used through the source attribute of 7 | file objects. Learn more at 8 | http://projects.puppetlabs.com/projects/puppet/wiki/File_Serving_Configuration 9 | 10 | You can use managed files like this: 11 | 12 | class myclass { 13 | package { mypackage: ensure => latest } 14 | service { myservice: ensure => running } 15 | file { "/etc/myfile": 16 | source => "puppet://$servername/modules/mymodule/myfile" 17 | } 18 | } 19 | 20 | The files are searched for in: 21 | 22 | $modulepath/mymodule/files/myfile 23 | -------------------------------------------------------------------------------- /files/plugins/amqp_client-2.3.1.ez: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voxpupuli/puppet-rabbitmq/ae4ffea04b66fb624b2fd7775c56144adf0f0d60/files/plugins/amqp_client-2.3.1.ez -------------------------------------------------------------------------------- /files/plugins/rabbit_stomp-2.3.1.ez: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voxpupuli/puppet-rabbitmq/ae4ffea04b66fb624b2fd7775c56144adf0f0d60/files/plugins/rabbit_stomp-2.3.1.ez -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 5 3 | 4 | defaults: 5 | datadir: 'data' 6 | data_hash: 'yaml_data' 7 | 8 | hierarchy: 9 | - name: 'Major Version' 10 | path: "os/%{facts.os.name}-%{facts.os.release.major}.yaml" 11 | - name: 'Distribution Name' 12 | path: "os/%{facts.os.name}.yaml" 13 | - name: 'Operating System Family' 14 | path: "family/%{facts.os.family}.yaml" 15 | - name: 'Common' 16 | path: 'common.yaml' 17 | -------------------------------------------------------------------------------- /lib/facter/erl_ssl_path.rb: -------------------------------------------------------------------------------- 1 | # rubocop:disable Style/FrozenStringLiteralComment 2 | 3 | # Fact to get the ssl path for the erlang distribution in the current 4 | # system as described in the RabbitMQ docs [1]. 5 | # 6 | # [1] https://www.rabbitmq.com/clustering-ssl.html 7 | 8 | Facter.add(:erl_ssl_path) do 9 | setcode do 10 | if Facter::Util::Resolution.which('erl') 11 | data = Facter::Core::Execution.execute("erl -eval 'io:format(\"~p\", [code:lib_dir(ssl, ebin)]),halt().' -noshell") 12 | # erl returns the string with quotes, strip them off 13 | data.gsub!(%r{\A"|"\Z}, '') 14 | end 15 | end 16 | end 17 | # rubocop:enable Style/FrozenStringLiteralComment 18 | -------------------------------------------------------------------------------- /lib/facter/rabbitmq_clustername.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Facter.add(:rabbitmq_clustername) do 4 | setcode do 5 | if Facter::Util::Resolution.which('rabbitmqctl') 6 | ret = nil 7 | cluster_status = Facter::Core::Execution.execute('rabbitmqctl -q cluster_status 2>&1') 8 | [%r!{cluster_name,<<"(\S+)">>}!, %r{^Cluster name: (\S+)$}].each do |r| 9 | if (data = r.match(cluster_status)) 10 | ret = data[1] 11 | break 12 | end 13 | end 14 | end 15 | ret 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/facter/rabbitmq_nodename.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Facter.add(:rabbitmq_nodename) do 4 | setcode do 5 | if Facter::Util::Resolution.which('rabbitmqctl') 6 | rabbitmq_nodename = Facter::Core::Execution.execute('rabbitmqctl status 2>&1') 7 | begin 8 | %r{^Status of node '?([\w.-]+@[\w.-]+)'?}.match(rabbitmq_nodename)[1] 9 | rescue StandardError 10 | Facter.debug("Error: rabbitmq_nodename facter failed. Output was #{rabbitmq_nodename}") 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/facter/rabbitmq_plugins_dirs.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Facter.add(:rabbitmq_plugins_dirs) do 4 | setcode do 5 | if Facter::Util::Resolution.which('rabbitmqctl') 6 | rabbitmq_pluginsdirs_env = Facter::Core::Execution.execute("rabbitmqctl eval 'application:get_env(rabbit, plugins_dir).'") 7 | rabbitmq_plugins_dirs_match = %r{^\{ok,"(/.+/\w+)}.match(rabbitmq_pluginsdirs_env) 8 | rabbitmq_plugins_dirs_match[1].split(':') if rabbitmq_plugins_dirs_match 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/facter/rabbitmq_version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Facter.add(:rabbitmq_version) do 4 | setcode do 5 | if Facter::Util::Resolution.which('rabbitmqadmin') 6 | rabbitmq_version = Facter::Core::Execution.execute('rabbitmqadmin --version 2>&1') 7 | %r{^rabbitmqadmin ([\w.]+)}.match(rabbitmq_version).to_a[1] 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_binding/rabbitmqadmin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require 'puppet' 5 | require 'digest' 6 | 7 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 8 | Puppet::Type.type(:rabbitmq_binding).provide(:rabbitmqadmin, parent: Puppet::Provider::RabbitmqCli) do 9 | desc 'Rabbitmqadmin provider for rabbitmq binding' 10 | confine feature: :posix 11 | 12 | # Without this, the composite namevar stuff doesn't work properly. 13 | mk_resource_methods 14 | 15 | def should_vhost 16 | @should_vhost || @should_vhost = resource[:vhost] 17 | end 18 | 19 | def self.all_vhosts 20 | vhosts = [] 21 | rabbitmqctl_list('vhosts').split(%r{\n}).map do |vhost| 22 | vhosts.push(vhost) 23 | end 24 | vhosts 25 | end 26 | 27 | def self.all_bindings(vhost) 28 | rabbitmqctl_list('bindings', '-p', vhost, 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments').split(%r{\n}) 29 | end 30 | 31 | def self.instances 32 | resources = [] 33 | all_vhosts.each do |vhost| 34 | all_bindings(vhost).map do |line| 35 | source_name, destination_name, destination_type, routing_key, arguments = line.split(%r{\t}) 36 | # Convert output of arguments from the rabbitmqctl command to a json string. 37 | if arguments.nil? 38 | arguments = '{}' 39 | else 40 | arguments = arguments.gsub(%r{^\[(.*)\]$}, '').gsub(%r{\{("(?:.|\\")*?"),}, '{\1:').gsub(%r{\},\{}, ',') 41 | arguments = '{}' if arguments == '' 42 | end 43 | hashed_name = Digest::SHA256.hexdigest format('%s@%s@%s@%s', source_name, destination_name, vhost, routing_key) 44 | next if source_name.empty? 45 | 46 | binding = { 47 | source: source_name, 48 | destination: destination_name, 49 | vhost: vhost, 50 | destination_type: destination_type, 51 | routing_key: routing_key, 52 | arguments: JSON.parse(arguments), 53 | ensure: :present, 54 | name: hashed_name 55 | } 56 | resources << new(binding) if binding[:name] 57 | end 58 | end 59 | resources 60 | end 61 | 62 | # see 63 | # https://github.com/puppetlabs/puppetlabs-netapp/blob/d0a655665463c69c932f835ba8756be32417a4e9/lib/puppet/provider/netapp_qtree/sevenmode.rb#L66-L73 64 | def self.prefetch(resources) 65 | bindings = instances 66 | resources.each do |name, res| 67 | if (provider = bindings.find { |binding| binding.source == res[:source] && binding.destination == res[:destination] && binding.vhost == res[:vhost] && binding.routing_key == res[:routing_key] }) 68 | resources[name].provider = provider 69 | end 70 | end 71 | end 72 | 73 | def exists? 74 | @property_hash[:ensure] == :present 75 | end 76 | 77 | def create 78 | vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' 79 | arguments = resource[:arguments] 80 | arguments = {} if arguments.nil? 81 | rabbitmqadmin('declare', 82 | 'binding', 83 | vhost_opt, 84 | "--user=#{resource[:user]}", 85 | "--password=#{resource[:password]}", 86 | '-c', 87 | '/etc/rabbitmq/rabbitmqadmin.conf', 88 | "source=#{resource[:source]}", 89 | "destination=#{resource[:destination]}", 90 | "arguments=#{arguments.to_json}", 91 | "routing_key=#{resource[:routing_key]}", 92 | "destination_type=#{resource[:destination_type]}") 93 | @property_hash[:ensure] = :present 94 | end 95 | 96 | def destroy 97 | vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' 98 | rabbitmqadmin('delete', 'binding', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", '-c', '/etc/rabbitmq/rabbitmqadmin.conf', "source=#{resource[:source]}", "destination_type=#{resource[:destination_type]}", "destination=#{resource[:destination]}", "properties_key=#{resource[:routing_key]}") 99 | @property_hash[:ensure] = :absent 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_cli.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Puppet::Provider::RabbitmqCli < Puppet::Provider 4 | initvars 5 | 6 | def self.append_to_path(dir) 7 | path = get_env 'PATH' 8 | # Don't append to the PATH if the directory is already in it. Otherwise, if 9 | # multiple providers run in the same process it may result in the 10 | # environment being modified multiple times. 11 | return if path.split(File::PATH_SEPARATOR).include? dir 12 | 13 | set_env 'PATH', [path, dir].join(File::PATH_SEPARATOR) 14 | end 15 | private_class_method :append_to_path 16 | 17 | # On most platforms, the RabbitMQ CLI programs are available in the PATH under 18 | # /usr/sbin. On some older platforms (CentOS 6), they are only available at 19 | # /usr/lib/rabbitmq/bin. We can't detect which because at the time this file 20 | # is evaluated, RabbitMQ might not yet be installed. However, if a command is 21 | # specified by name (instead of absolute path), Puppet searches the PATH 22 | # before each execution of the command. Append /usr/lib/rabbitmq/bin to the 23 | # end of the PATH so that Puppet will look there last at the time a command is 24 | # executed. This is the best I can come up with short of fragile meta- 25 | # programming with Puppet internals. 26 | append_to_path '/usr/lib/rabbitmq/bin' 27 | 28 | def self.home_tmp_command(name, path) 29 | has_command name, path do 30 | environment HOME: '/tmp', LC_ALL: 'en_US.UTF-8' 31 | end 32 | end 33 | 34 | home_tmp_command :rabbitmqctl, 'rabbitmqctl' 35 | home_tmp_command :rabbitmqplugins, 'rabbitmq-plugins' 36 | 37 | home_tmp_command :rabbitmqadmin, '/usr/local/bin/rabbitmqadmin' 38 | 39 | def self.rabbitmq_version 40 | return @rabbitmq_version if defined? @rabbitmq_version 41 | 42 | output = rabbitmqctl('-q', 'status') 43 | version = output.match(%r{RabbitMQ.*?([\d.]+)}) 44 | @rabbitmq_version = version[1] if version 45 | @rabbitmq_version 46 | end 47 | 48 | def self.rabbitmqctl_list(resource, *opts) 49 | version = rabbitmq_version 50 | list_opts = 51 | if version && Puppet::Util::Package.versioncmp(version, '3.7.9') >= 0 52 | ['-q', '--no-table-headers'] 53 | else 54 | ['-q'] 55 | end 56 | rabbitmqctl("list_#{resource}", *list_opts, *opts) 57 | rescue Puppet::MissingCommand 58 | # rabbitmqctl is not present. Normally we would have installed a package 59 | # that provides rabbitmqctl by now, but if we're running under --noop or 60 | # with a restrictive set of tags, the package may not have been installed. 61 | # Return an empty string to avoid error. This may give false positives for 62 | # resources under --noop! 63 | Puppet.debug('rabbitmqctl command not found; assuming rabbitmq is not installed') 64 | '' 65 | end 66 | 67 | def self.rabbitmq_running 68 | rabbitmqctl('-q', 'status') 69 | true 70 | rescue Puppet::ExecutionFailure, Timeout::Error 71 | false 72 | end 73 | 74 | # Retry the given code block 'count' retries or until the 75 | # command succeeds. Use 'step' delay between retries. 76 | # Limit each query time by 'timeout'. 77 | # For example: 78 | # users = self.class.run_with_retries { rabbitmqctl 'list_users' } 79 | def self.run_with_retries(count = 30, step = 6, timeout = 10, &block) 80 | count.times do |_n| 81 | output = Timeout.timeout(timeout, &block) 82 | rescue Puppet::ExecutionFailure, Timeout::Error 83 | Puppet.debug 'Command failed, retrying' 84 | sleep step 85 | else 86 | Puppet.debug 'Command succeeded' 87 | return output 88 | end 89 | raise Puppet::Error, "Command is still failing after #{count * step} seconds expired!" 90 | end 91 | 92 | def self.define_instance_method(name) 93 | return if method_defined?(name) 94 | 95 | define_method(name) do |*args, &block| 96 | self.class.send(name, *args, &block) 97 | end 98 | end 99 | private_class_method :define_instance_method 100 | 101 | define_instance_method :rabbitmqctl_list 102 | define_instance_method :run_with_retries 103 | end 104 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_cluster/rabbitmqctl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 4 | Puppet::Type.type(:rabbitmq_cluster).provide( 5 | :rabbitmqctl, 6 | parent: Puppet::Provider::RabbitmqCli 7 | ) do 8 | desc 'Rabbitmqctl provider for rabbitmq cluster' 9 | confine feature: :posix 10 | 11 | def exists? 12 | cluster_name == @resource[:name].to_s 13 | end 14 | 15 | def create 16 | storage_type = @resource[:node_disc_type].to_s 17 | 18 | init_node = @resource[:init_node].to_s.gsub(%r{^.*@}, '') 19 | local_node = @resource[:local_node].to_s.gsub(%r{^.*@}, '') 20 | 21 | if local_node == init_node || [Facter.value(:networking)['hostname'], Facter.value(:networking)['fqdn']].include?(init_node) 22 | return rabbitmqctl('set_cluster_name', @resource[:name]) unless cluster_name == resource[:name].to_s 23 | else 24 | rabbitmqctl('stop_app') 25 | rabbitmqctl('join_cluster', "rabbit@#{init_node}", "--#{storage_type}") 26 | rabbitmqctl('start_app') 27 | end 28 | end 29 | 30 | def destroy 31 | rabbitmqctl('stop_app') 32 | rabbitmqctl('reset') 33 | rabbitmqctl('start_app') 34 | end 35 | 36 | def cluster_name 37 | cluster_status = rabbitmqctl('-q', 'cluster_status') 38 | [%r!{cluster_name,<<"(\S+)">>}!, %r{^Cluster name: (\S+)$}].each do |r| 39 | if (data = r.match(cluster_status)) 40 | return data[1] 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_erlang_cookie/ruby.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet' 4 | require 'set' 5 | Puppet::Type.type(:rabbitmq_erlang_cookie).provide(:ruby) do 6 | desc 'Ruby provider for rabbitmq erlang cookie' 7 | confine feature: :posix 8 | 9 | def exists? 10 | # Hack to prevent the create method from being called. 11 | # We never need to create or destroy this resource, only change its value 12 | true 13 | end 14 | 15 | def content=(value) 16 | raise('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.') unless resource[:force] == :true # Danger! 17 | 18 | Puppet::Type.type(:service).new(name: resource[:service_name]).provider.stop 19 | FileUtils.rm_rf("#{resource[:rabbitmq_home]}#{File::SEPARATOR}mnesia") 20 | File.open(resource[:path], 'w') do |cookie| 21 | cookie.chmod(0o400) 22 | cookie.write(value) 23 | end 24 | FileUtils.chown(resource[:rabbitmq_user], resource[:rabbitmq_group], resource[:path]) 25 | end 26 | 27 | def content 28 | if File.exist?(resource[:path]) 29 | File.read(resource[:path]) 30 | else 31 | '' 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_exchange/rabbitmqadmin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet' 4 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 5 | Puppet::Type.type(:rabbitmq_exchange).provide(:rabbitmqadmin, parent: Puppet::Provider::RabbitmqCli) do 6 | desc 'Rabbitmqadmin provider for rabbitmq exchange' 7 | confine feature: :posix 8 | 9 | def should_vhost 10 | @should_vhost || @should_vhost = resource[:name].split('@')[1] 11 | end 12 | 13 | def self.all_vhosts 14 | run_with_retries { rabbitmqctl_list('vhosts') }.split(%r{\n}) 15 | end 16 | 17 | def self.all_exchanges(vhost) 18 | exchange_list = run_with_retries do 19 | rabbitmqctl_list('exchanges', '-p', vhost, 'name', 'type', 'internal', 'durable', 'auto_delete', 'arguments') 20 | end 21 | exchange_list.split(%r{\n}).grep_v(%r{^federation:}) 22 | end 23 | 24 | def self.instances 25 | resources = [] 26 | all_vhosts.each do |vhost| 27 | all_exchanges(vhost).each do |line| 28 | name, type, internal, durable, auto_delete, arguments = line.split 29 | if type.nil? 30 | # if name is empty, it will wrongly get the type's value. 31 | # This way type will get the correct value 32 | type = name 33 | name = '' 34 | end 35 | # Convert output of arguments from the rabbitmqctl command to a json string. 36 | if arguments.nil? 37 | arguments = '{}' 38 | else 39 | arguments = arguments.gsub(%r{^\[(.*)\]$}, '').gsub(%r{\{("(?:.|\\")*?"),}, '{\1:').gsub(%r{\},\{}, ',') 40 | arguments = '{}' if arguments == '' 41 | end 42 | exchange = { 43 | type: type, 44 | ensure: :present, 45 | internal: internal, 46 | durable: durable, 47 | auto_delete: auto_delete, 48 | name: format('%s@%s', name, vhost), 49 | arguments: JSON.parse(arguments) 50 | } 51 | resources << new(exchange) if exchange[:type] 52 | end 53 | end 54 | resources 55 | end 56 | 57 | def self.prefetch(resources) 58 | packages = instances 59 | resources.each_key do |name| 60 | if (provider = packages.find { |pkg| pkg.name == name }) 61 | resources[name].provider = provider 62 | end 63 | end 64 | end 65 | 66 | def exists? 67 | @property_hash[:ensure] == :present 68 | end 69 | 70 | def create 71 | vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' 72 | name = resource[:name].split('@')[0] 73 | arguments = resource[:arguments] 74 | arguments = {} if arguments.nil? 75 | cmd = ['declare', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}", "type=#{resource[:type]}"] 76 | cmd << "internal=#{resource[:internal]}" 77 | cmd << "durable=#{resource[:durable]}" 78 | cmd << "auto_delete=#{resource[:auto_delete]}" 79 | cmd += ["arguments=#{arguments.to_json}", '-c', '/etc/rabbitmq/rabbitmqadmin.conf'] 80 | rabbitmqadmin(*cmd) 81 | @property_hash[:ensure] = :present 82 | end 83 | 84 | def destroy 85 | vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' 86 | name = resource[:name].split('@')[0] 87 | rabbitmqadmin('delete', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}", '-c', '/etc/rabbitmq/rabbitmqadmin.conf') 88 | @property_hash[:ensure] = :absent 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_parameter/rabbitmqctl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require 'puppet/util/package' 5 | 6 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 7 | Puppet::Type.type(:rabbitmq_parameter).provide(:rabbitmqctl, parent: Puppet::Provider::RabbitmqCli) do 8 | desc 'Rabbitmqctl provider for rabbitmq parameter' 9 | confine feature: :posix 10 | 11 | mk_resource_methods 12 | 13 | def initialize(value = {}) 14 | super(value) 15 | @property_flush = {} 16 | end 17 | 18 | def self.all_vhosts 19 | rabbitmqctl_list('vhosts').split(%r{\n}) 20 | end 21 | 22 | def self.all_parameters(vhost) 23 | rabbitmqctl_list('parameters', '-p', vhost).split(%r{\n}) 24 | end 25 | 26 | def self.instances 27 | resources = [] 28 | all_vhosts.each do |vhost| 29 | all_parameters(vhost).map do |line| 30 | raise Puppet::Error, "cannot parse line from list_parameter:#{line}" unless line =~ %r{^(\S+)\s+(\S+)\s+(\S+)$} 31 | 32 | parameter = { 33 | ensure: :present, 34 | component_name: Regexp.last_match(1), 35 | name: format('%s@%s', Regexp.last_match(2), vhost), 36 | value: JSON.parse(Regexp.last_match(3)) 37 | } 38 | resources << new(parameter) 39 | end 40 | end 41 | resources 42 | end 43 | 44 | def self.prefetch(resources) 45 | packages = instances 46 | resources.each_key do |name| 47 | Puppet.info "Calling prefetch: #{name}" 48 | if (provider = packages.find { |pkg| pkg.name == name }) 49 | resources[name].provider = provider 50 | end 51 | end 52 | end 53 | 54 | def exists? 55 | @property_hash[:ensure] == :present 56 | end 57 | 58 | def create 59 | @property_flush[:ensure] = :present 60 | set_parameter 61 | end 62 | 63 | def destroy 64 | @property_flush[:ensure] = :absent 65 | set_parameter 66 | end 67 | 68 | def set_parameter 69 | vhost = resource[:name].rpartition('@').last 70 | key = resource[:name].rpartition('@').first 71 | 72 | if @property_flush[:ensure] == :absent 73 | rabbitmqctl('clear_parameter', '-p', vhost, resource[:component_name] || component_name, key) 74 | else 75 | rabbitmqctl('set_parameter', '-p', vhost, resource[:component_name], key, resource[:value].to_json) 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_plugin/rabbitmqplugins.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet/util/package' 4 | 5 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 6 | Puppet::Type.type(:rabbitmq_plugin).provide(:rabbitmqplugins, parent: Puppet::Provider::RabbitmqCli) do 7 | desc 'Rabbitmqplugins provider for rabbitmq plugin' 8 | confine feature: :posix 9 | 10 | def self.plugin_list 11 | list_str = run_with_retries do 12 | # Pass in -e to list both implicitly and explicitly enabled plugins. 13 | # If you pass in -E instead, then only explicitly enabled plugins are listed. 14 | # Implicitly enabled plugins are those that were enabled as a dependency of another plugin/ 15 | # If we do not pass in -e then the order if plugin installation matters within the puppet 16 | # code. Example, if Plugin A depends on Plugin B and we install Plugin B first it will 17 | # implicitly enable Plugin A. Then when we go to run Puppet a second time without the 18 | # -e parameter, we won't see Plugin A as being enabled so we'll try to install it again. 19 | # To preserve idempotency we should get all enabled plugins regardless of implicitly or 20 | # explicitly enabled. 21 | rabbitmqplugins('list', '-e', '-m') 22 | rescue Puppet::MissingCommand 23 | # See note about Puppet::MissingCommand in: 24 | # lib/puppet/provider/rabbitmq_cli.rb 25 | Puppet.debug('rabbitmqplugins command not found; assuming rabbitmq is not installed') 26 | '' 27 | end 28 | # Split by newline. 29 | lines = list_str.split(%r{\n}) 30 | # Return only lines that are single words because sometimes RabbitMQ likes to output 31 | # information messages. Suppressing those messages via CLI flags is inconsistent between 32 | # versions, so this this regex removes those message without having to use painful 33 | # version switches. 34 | lines.grep(%r{^(\S+)$}) 35 | end 36 | 37 | def self.instances 38 | plugin_list.map do |line| 39 | raise Puppet::Error, "Cannot parse invalid plugins line: #{line}" unless line =~ %r{^(\S+)$} 40 | 41 | new(name: Regexp.last_match(1)) 42 | end 43 | end 44 | 45 | def create 46 | cmd = ['enable', resource[:name]] 47 | # rabbitmq>=3.4.0 - check if node running, if not, ignore this option 48 | cmd << "--#{resource[:mode]}" if self.class.rabbitmq_running && Puppet::Util::Package.versioncmp(self.class.rabbitmq_version, '3.4') >= 0 && resource[:mode] != :best 49 | 50 | if resource[:umask].nil? 51 | rabbitmqplugins(*cmd) 52 | else 53 | Puppet::Util.withumask(resource[:umask]) { rabbitmqplugins(*cmd) } 54 | end 55 | end 56 | 57 | def destroy 58 | rabbitmqplugins('disable', resource[:name]) 59 | end 60 | 61 | def exists? 62 | self.class.plugin_list.include? resource[:name] 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_policy/rabbitmqctl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require 'puppet/util/package' 5 | 6 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 7 | Puppet::Type.type(:rabbitmq_policy).provide(:rabbitmqctl, parent: Puppet::Provider::RabbitmqCli) do 8 | desc 'Rabbitmqctl provider for rabbitmq policy' 9 | confine feature: :posix 10 | 11 | # cache policies 12 | def self.policies(vhost, name) 13 | @policies ||= {} 14 | unless @policies[vhost] 15 | @policies[vhost] = {} 16 | policy_list = run_with_retries do 17 | rabbitmqctl_list('policies', '-p', vhost) 18 | end 19 | 20 | # rabbitmq<3.2 does not support the applyto field 21 | # 1 2 3? 4 5 6 22 | # / ha-all all .* {"ha-mode":"all","ha-sync-mode":"automatic"} 0 << This is for RabbitMQ v < 3.7.0 23 | # / ha-all .* all {"ha-mode":"all","ha-sync-mode":"automatic"} 0 << This is for RabbitMQ v >= 3.7.0 24 | if Puppet::Util::Package.versioncmp(rabbitmq_version, '3.7') >= 0 25 | regex = %r{^(\S+)\s+(\S+)\s+(\S+)\s+(all|exchanges|(?:classic_|quorum_)?queues|streams)?\s+(\S+)\s+(\d+)$} 26 | applyto_index = 4 27 | pattern_index = 3 28 | else 29 | regex = %r{^(\S+)\s+(\S+)\s+(all|exchanges|queues)?\s*(\S+)\s+(\S+)\s+(\d+)$} 30 | applyto_index = 3 31 | pattern_index = 4 32 | end 33 | 34 | policy_list.split(%r{\n}).each do |line| 35 | raise Puppet::Error, "cannot parse line from list_policies:#{line}" unless line =~ regex 36 | 37 | n = Regexp.last_match(2) 38 | applyto = Regexp.last_match(applyto_index) || 'all' 39 | priority = Regexp.last_match(6) 40 | definition = JSON.parse(Regexp.last_match(5)) 41 | # be aware that the gsub will reset the captures 42 | # from the regexp above 43 | pattern = Regexp.last_match(pattern_index).to_s.gsub(%r{\\\\}, '\\') 44 | 45 | @policies[vhost][n] = { 46 | applyto: applyto, 47 | pattern: pattern, 48 | definition: definition, 49 | priority: priority 50 | } 51 | end 52 | end 53 | @policies[vhost][name] 54 | end 55 | 56 | def policies(vhost, name) 57 | self.class.policies(vhost, name) 58 | end 59 | 60 | def should_policy 61 | @should_policy ||= resource[:name].rpartition('@').first 62 | end 63 | 64 | def should_vhost 65 | @should_vhost ||= resource[:name].rpartition('@').last 66 | end 67 | 68 | def create 69 | set_policy 70 | end 71 | 72 | def destroy 73 | rabbitmqctl('clear_policy', '-p', should_vhost, should_policy) 74 | end 75 | 76 | def exists? 77 | policies(should_vhost, should_policy) 78 | end 79 | 80 | def pattern 81 | policies(should_vhost, should_policy)[:pattern] 82 | end 83 | 84 | def pattern=(_pattern) 85 | set_policy 86 | end 87 | 88 | def applyto 89 | policies(should_vhost, should_policy)[:applyto] 90 | end 91 | 92 | def applyto=(_applyto) 93 | set_policy 94 | end 95 | 96 | def definition 97 | policies(should_vhost, should_policy)[:definition] 98 | end 99 | 100 | def definition=(_definition) 101 | set_policy 102 | end 103 | 104 | def priority 105 | policies(should_vhost, should_policy)[:priority] 106 | end 107 | 108 | def priority=(_priority) 109 | set_policy 110 | end 111 | 112 | def set_policy 113 | return if @set_policy 114 | 115 | @set_policy = true 116 | resource[:applyto] ||= applyto 117 | resource[:definition] ||= definition 118 | resource[:pattern] ||= pattern 119 | resource[:priority] ||= priority 120 | # rabbitmq>=3.2.0 121 | if Puppet::Util::Package.versioncmp(self.class.rabbitmq_version, '3.2.0') >= 0 122 | rabbitmqctl( 123 | 'set_policy', 124 | '-p', should_vhost, 125 | '--priority', resource[:priority], 126 | '--apply-to', resource[:applyto].to_s, 127 | should_policy, 128 | resource[:pattern], 129 | resource[:definition].to_json 130 | ) 131 | else 132 | rabbitmqctl( 133 | 'set_policy', 134 | '-p', should_vhost, 135 | should_policy, 136 | resource[:pattern], 137 | resource[:definition].to_json, 138 | resource[:priority] 139 | ) 140 | end 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_queue/rabbitmqadmin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require 'puppet' 5 | 6 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 7 | Puppet::Type.type(:rabbitmq_queue).provide(:rabbitmqadmin, parent: Puppet::Provider::RabbitmqCli) do 8 | desc 'Rabbitmqadmin provider for rabbitmq queue' 9 | confine feature: :posix 10 | 11 | def should_vhost 12 | @should_vhost || @should_vhost = resource[:name].rpartition('@').last 13 | end 14 | 15 | def self.all_vhosts 16 | rabbitmqctl_list('vhosts').split(%r{\n}) 17 | end 18 | 19 | def self.all_queues(vhost) 20 | rabbitmqctl_list('queues', '-p', vhost, 'name', 'durable', 'auto_delete', 'arguments').split(%r{\n}) 21 | end 22 | 23 | def self.instances 24 | resources = [] 25 | all_vhosts.each do |vhost| 26 | all_queues(vhost).map do |line| 27 | next if line =~ %r{^federation:} 28 | 29 | name, durable, auto_delete, arguments = line.split("\t") 30 | # Convert output of arguments from the rabbitmqctl command to a json string. 31 | if arguments.nil? 32 | arguments = '{}' 33 | else 34 | arguments = arguments.gsub(%r{^\[(.*)\]$}, '').gsub(%r{\{("(?:.|\\")*?"),}, '{\1:').gsub(%r{\},\{}, ',') 35 | arguments = '{}' if arguments == '' 36 | end 37 | queue = { 38 | durable: durable, 39 | auto_delete: auto_delete, 40 | arguments: JSON.parse(arguments), 41 | ensure: :present, 42 | name: format('%s@%s', name, vhost) 43 | } 44 | resources << new(queue) if queue[:name] 45 | end 46 | end 47 | resources 48 | end 49 | 50 | def self.prefetch(resources) 51 | packages = instances 52 | resources.each_key do |name| 53 | if (provider = packages.find { |pkg| pkg.name == name }) 54 | resources[name].provider = provider 55 | end 56 | end 57 | end 58 | 59 | def exists? 60 | @property_hash[:ensure] == :present 61 | end 62 | 63 | def create 64 | vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' 65 | name = resource[:name].rpartition('@').first 66 | arguments = resource[:arguments] 67 | arguments = {} if arguments.nil? 68 | rabbitmqadmin('declare', 69 | 'queue', 70 | vhost_opt, 71 | "--user=#{resource[:user]}", 72 | "--password=#{resource[:password]}", 73 | '-c', 74 | '/etc/rabbitmq/rabbitmqadmin.conf', 75 | "name=#{name}", 76 | "durable=#{resource[:durable]}", 77 | "auto_delete=#{resource[:auto_delete]}", 78 | "arguments=#{arguments.to_json}") 79 | @property_hash[:ensure] = :present 80 | end 81 | 82 | def destroy 83 | vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : '' 84 | name = resource[:name].rpartition('@').first 85 | rabbitmqadmin('delete', 'queue', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", '-c', '/etc/rabbitmq/rabbitmqadmin.conf', "name=#{name}") 86 | @property_hash[:ensure] = :absent 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_user/rabbitmqctl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 4 | Puppet::Type.type(:rabbitmq_user).provide( 5 | :rabbitmqctl, 6 | parent: Puppet::Provider::RabbitmqCli 7 | ) do 8 | desc 'Rabbitmqctl provider for rabbitmq user' 9 | confine feature: :posix 10 | 11 | def initialize(value = {}) 12 | super(value) 13 | @property_flush = {} 14 | end 15 | 16 | def self.instances 17 | user_list = run_with_retries do 18 | rabbitmqctl_list('users') 19 | end 20 | 21 | user_list.split(%r{\n}).map do |line| 22 | raise Puppet::Error, "Cannot parse invalid user line: #{line}" unless line =~ %r{^(\S+)\s+\[(.*?)\]$} 23 | 24 | user = Regexp.last_match(1) 25 | tags = Regexp.last_match(2).split(%r{,\s*}) 26 | new( 27 | ensure: :present, 28 | name: user, 29 | tags: tags 30 | ) 31 | end 32 | end 33 | 34 | def self.prefetch(resources) 35 | users = instances 36 | resources.each_key do |user| 37 | if (provider = users.find { |u| u.name == user }) 38 | resources[user].provider = provider 39 | end 40 | end 41 | end 42 | 43 | def exists? 44 | @property_hash[:ensure] == :present 45 | end 46 | 47 | def create 48 | # Fail here (rather than a validate block in the type) if password is not 49 | # set, so that "puppet resource" still works. 50 | raise Puppet::Error, "Password is a required parameter for rabbitmq_user (user: #{name})" if @resource[:password].nil? 51 | 52 | rabbitmqctl('add_user', @resource[:name], @resource[:password]) 53 | 54 | tags = @resource[:tags] 55 | tags << admin_tag if @resource[:admin] == :true 56 | rabbitmqctl('set_user_tags', @resource[:name], tags) unless tags.empty? 57 | 58 | @property_hash[:ensure] = :present 59 | end 60 | 61 | def destroy 62 | rabbitmqctl('delete_user', @resource[:name]) 63 | @property_hash[:ensure] = :absent 64 | end 65 | 66 | def password=(password) 67 | rabbitmqctl('change_password', @resource[:name], password) 68 | end 69 | 70 | def password; end 71 | 72 | def check_password(password) 73 | check_access_control = [ 74 | 'rabbit_access_control:check_user_pass_login(', 75 | %[list_to_binary("#{@resource[:name]}"), ], 76 | %[list_to_binary("#{password.to_s.gsub('"', '\\"')}")).] 77 | ] 78 | 79 | response = rabbitmqctl('eval', check_access_control.join) 80 | !response.include? 'refused' 81 | end 82 | 83 | def tags 84 | # do not expose the administrator tag for admins 85 | @property_hash[:tags].reject { |tag| tag == admin_tag } 86 | end 87 | 88 | def tags=(tags) 89 | @property_flush[:tags] = tags 90 | end 91 | 92 | def admin 93 | usertags = get_user_tags 94 | raise Puppet::Error, "Could not match line '#{resource[:name]} (true|false)' from list_users (perhaps you are running on an older version of rabbitmq that does not support admin users?)" unless usertags 95 | 96 | (:true if usertags.include?('administrator')) || :false 97 | end 98 | 99 | def admin=(state) 100 | if state == :true 101 | make_user_admin 102 | else 103 | usertags = get_user_tags 104 | usertags.delete('administrator') 105 | rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort) 106 | end 107 | end 108 | 109 | def admin 110 | @property_hash[:tags].include?(admin_tag) ? :true : :false 111 | end 112 | 113 | def admin=(state) 114 | @property_flush[:admin] = state 115 | end 116 | 117 | def flush 118 | return if @property_flush.empty? 119 | 120 | tags = @property_flush[:tags] || @resource[:tags] 121 | tags << admin_tag if @resource[:admin] == :true 122 | rabbitmqctl('set_user_tags', @resource[:name], tags) 123 | @property_flush.clear 124 | end 125 | 126 | private 127 | 128 | def admin_tag 129 | 'administrator' 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_user_permissions/rabbitmqctl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 4 | Puppet::Type.type(:rabbitmq_user_permissions).provide(:rabbitmqctl, parent: Puppet::Provider::RabbitmqCli) do 5 | desc 'Rabbitmqctl provider for rabbitmq user permissions' 6 | confine feature: :posix 7 | 8 | # cache users permissions 9 | def self.users(name, vhost) 10 | @users ||= {} 11 | unless @users[name] 12 | @users[name] = {} 13 | user_permission_list = run_with_retries do 14 | rabbitmqctl_list('user_permissions', name) 15 | end 16 | user_permission_list.split(%r{\n}).each do |line| 17 | line = strip_backslashes(line) 18 | raise Puppet::Error, "cannot parse line from list_user_permissions:#{line}" unless line =~ %r{^(\S+)\s+(\S*)\s+(\S*)\s+(\S*)$} 19 | 20 | @users[name][Regexp.last_match(1)] = 21 | { configure: Regexp.last_match(2), read: Regexp.last_match(4), write: Regexp.last_match(3) } 22 | end 23 | end 24 | @users[name][vhost] 25 | end 26 | 27 | def users(name, vhost) 28 | self.class.users(name, vhost) 29 | end 30 | 31 | def should_user 32 | @should_user || @should_user = resource[:name].split('@')[0] 33 | end 34 | 35 | def should_vhost 36 | @should_vhost || @should_vhost = resource[:name].split('@')[1] 37 | end 38 | 39 | def create 40 | resource[:configure_permission] ||= "''" 41 | resource[:read_permission] ||= "''" 42 | resource[:write_permission] ||= "''" 43 | rabbitmqctl('set_permissions', '-p', should_vhost, should_user, resource[:configure_permission], resource[:write_permission], resource[:read_permission]) 44 | end 45 | 46 | def destroy 47 | rabbitmqctl('clear_permissions', '-p', should_vhost, should_user) 48 | end 49 | 50 | # I am implementing prefetching in exists b/c I need to be sure 51 | # that the rabbitmq package is installed before I make this call. 52 | def exists? 53 | users(should_user, should_vhost) 54 | end 55 | 56 | def configure_permission 57 | users(should_user, should_vhost)[:configure] 58 | end 59 | 60 | def configure_permission=(_perm) 61 | set_permissions 62 | end 63 | 64 | def read_permission 65 | users(should_user, should_vhost)[:read] 66 | end 67 | 68 | def read_permission=(_perm) 69 | set_permissions 70 | end 71 | 72 | def write_permission 73 | users(should_user, should_vhost)[:write] 74 | end 75 | 76 | def write_permission=(_perm) 77 | set_permissions 78 | end 79 | 80 | # implement memoization so that we only call set_permissions once 81 | def set_permissions 82 | return if @permissions_set 83 | 84 | @permissions_set = true 85 | resource[:configure_permission] ||= configure_permission 86 | resource[:read_permission] ||= read_permission 87 | resource[:write_permission] ||= write_permission 88 | rabbitmqctl( 89 | 'set_permissions', 90 | '-p', should_vhost, 91 | should_user, 92 | resource[:configure_permission], 93 | resource[:write_permission], 94 | resource[:read_permission] 95 | ) 96 | end 97 | 98 | def self.strip_backslashes(string) 99 | # See: https://github.com/rabbitmq/rabbitmq-server/blob/v1_7/docs/rabbitmqctl.1.pod#output-escaping 100 | string.gsub(%r{\\\\}, '\\') 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /lib/puppet/provider/rabbitmq_vhost/rabbitmqctl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rabbitmq_cli')) 4 | Puppet::Type.type(:rabbitmq_vhost).provide( 5 | :rabbitmqctl, 6 | parent: Puppet::Provider::RabbitmqCli 7 | ) do 8 | desc 'Rabbitmqctl provider for rabbitmq vhost' 9 | confine feature: :posix 10 | 11 | def self.prefetch(resources) 12 | instances.each do |prov| 13 | if (resource = resources[prov.name]) 14 | resource.provider = prov 15 | end 16 | end 17 | end 18 | 19 | # To maintain compatibility with older versions of RabbitMQ, 20 | # we only deal with vhost metadata >= version 3.11.0 21 | def self.supports_metadata? 22 | Puppet::Util::Package.versioncmp(rabbitmq_version, '3.11') >= 0 23 | rescue Puppet::MissingCommand 24 | # See comment on the definition of rabbitmqctl_list in rabbitmqctl_cli.rb; 25 | # the same rationale applies here. 26 | Puppet.debug('supports_metadata?: rabbitmqctl command not found; assuming rabbitmq is not installed') 27 | false 28 | end 29 | 30 | def supports_metadata? 31 | self.class.supports_metadata? 32 | end 33 | 34 | def self.vhost_list 35 | run_with_retries do 36 | if supports_metadata? 37 | rabbitmqctl_list('vhosts', 'name,description,default_queue_type,tags', '-s') 38 | else 39 | rabbitmqctl_list('vhosts') 40 | end 41 | end 42 | end 43 | 44 | def self.instances 45 | vhost_list.split(%r{\n}).map do |line| 46 | if supports_metadata? 47 | raise Puppet::Error, "Cannot parse invalid vhost line: #{line}" unless \ 48 | (matches = line.match(%r{^(\S+)\t+(.*?)\t+(undefined|quorum|classic|stream)?\t+\[(.*?)\]$}i)) 49 | 50 | name, description, default_queue_type, tags = matches.captures 51 | # RMQ returns 'undefined' as default_queue_type if it has never been set 52 | default_queue_type = nil if default_queue_type == 'undefined' 53 | new(ensure: :present, name: name, description: description, default_queue_type: default_queue_type, tags: tags.split(%r{,\s*})) 54 | else 55 | raise Puppet::Error, "Cannot parse invalid vhost line: #{line}" unless line =~ %r{^(\S+)$} 56 | 57 | new(ensure: :present, name: Regexp.last_match(1)) 58 | end 59 | end 60 | end 61 | 62 | def create 63 | rabbitmqctl('add_vhost', *params) 64 | end 65 | 66 | def params 67 | params = [resource[:name]] 68 | if supports_metadata? 69 | params << ['--description', resource[:description]] if resource[:description] 70 | params << ['--default-queue-type', resource[:default_queue_type]] if resource[:default_queue_type] && resource[:default_queue_type] != 'undefined' 71 | params << ['--tags', resource[:tags].join(',')] if resource[:tags] 72 | end 73 | params 74 | end 75 | 76 | def description 77 | @property_hash[:description] 78 | end 79 | 80 | def tags 81 | @property_hash[:tags] 82 | end 83 | 84 | def default_queue_type 85 | @property_hash[:default_queue_type] 86 | end 87 | 88 | def tags=(tags) 89 | @property_hash[:tags] = tags 90 | end 91 | 92 | def description=(value) 93 | @property_hash[:description] = value 94 | end 95 | 96 | def default_queue_type=(value) 97 | @property_hash[:default_queue_type] = value 98 | end 99 | 100 | def flush 101 | return if @property_hash.empty? || !supports_metadata? || !exists? 102 | 103 | params = [resource[:name]] 104 | params << ['--description', @property_hash[:description]] if @property_hash[:description] 105 | params << ['--default-queue-type', @property_hash[:default_queue_type]] if @property_hash[:default_queue_type] 106 | params << ['--tags', @property_hash[:tags].join(',')] if @property_hash[:tags] 107 | rabbitmqctl('update_vhost_metadata', *params) 108 | end 109 | 110 | def destroy 111 | rabbitmqctl('delete_vhost', resource[:name]) 112 | end 113 | 114 | def exists? 115 | run_with_retries { rabbitmqctl_list('vhosts') }.split(%r{\n}).include? resource[:name] 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_binding) do 4 | desc <<~DESC 5 | Native type for managing rabbitmq bindings 6 | 7 | @example Create a rabbitmq_binding 8 | rabbitmq_binding { 'myexchange@myqueue@myvhost': 9 | user => 'dan', 10 | password => 'bar', 11 | destination_type => 'queue', 12 | routing_key => '#', 13 | arguments => {}, 14 | ensure => present, 15 | } 16 | 17 | @example Create bindings with same source / destination / vhost but different routing key using individual parameters 18 | rabbitmq_binding { 'binding 1': 19 | ensure => present, 20 | source => 'myexchange', 21 | destination => 'myqueue', 22 | vhost => 'myvhost', 23 | user => 'dan', 24 | password => 'bar', 25 | destination_type => 'queue', 26 | routing_key => 'key1', 27 | arguments => {}, 28 | } 29 | 30 | rabbitmq_binding { 'binding 2': 31 | ensure => present, 32 | source => 'myexchange', 33 | destination => 'myqueue', 34 | vhost => 'myvhost', 35 | user => 'dan', 36 | password => 'bar', 37 | destination_type => 'queue', 38 | routing_key => 'key2', 39 | arguments => {}, 40 | } 41 | DESC 42 | 43 | ensurable do 44 | desc 'Whether the resource should be present or absent' 45 | defaultto(:present) 46 | newvalue(:present) do 47 | provider.create 48 | end 49 | newvalue(:absent) do 50 | provider.destroy 51 | end 52 | end 53 | 54 | # Match patterns without '@' as arbitrary names; match patterns with 55 | # src@destination@vhost to their named params for backwards compatibility. 56 | def self.title_patterns 57 | [ 58 | [ 59 | %r{(^([^@]*)$)}m, 60 | [ 61 | [:name] 62 | ] 63 | ], 64 | [ 65 | %r{^((\S+)@(\S+)@(\S+))$}m, 66 | [ 67 | [:name], 68 | [:source], 69 | [:destination], 70 | [:vhost] 71 | ] 72 | ] 73 | ] 74 | end 75 | 76 | newparam(:name) do 77 | desc 'resource name, either source@destination@vhost or arbitrary name with params' 78 | 79 | isnamevar 80 | end 81 | 82 | newproperty(:source) do 83 | desc 'source of binding' 84 | 85 | newvalues(%r{^\S+$}) 86 | isnamevar 87 | end 88 | 89 | newproperty(:destination) do 90 | desc 'destination of binding' 91 | 92 | newvalues(%r{^\S+$}) 93 | isnamevar 94 | end 95 | 96 | newproperty(:vhost) do 97 | desc 'vhost' 98 | 99 | newvalues(%r{^\S+$}) 100 | defaultto('/') 101 | isnamevar 102 | end 103 | 104 | newproperty(:routing_key) do 105 | desc 'binding routing_key' 106 | 107 | newvalues(%r{^\S*$}) 108 | isnamevar 109 | end 110 | 111 | newproperty(:destination_type) do 112 | desc 'binding destination_type' 113 | newvalues(%r{queue|exchange}) 114 | defaultto('queue') 115 | end 116 | 117 | newproperty(:arguments) do 118 | desc 'binding arguments' 119 | defaultto({}) 120 | validate do |value| 121 | resource.validate_argument(value) 122 | end 123 | end 124 | 125 | newparam(:user) do 126 | desc 'The user to use to connect to rabbitmq' 127 | defaultto('guest') 128 | newvalues(%r{^\S+$}) 129 | end 130 | 131 | newparam(:password) do 132 | desc 'The password to use to connect to rabbitmq' 133 | defaultto('guest') 134 | newvalues(%r{\S+}) 135 | end 136 | 137 | autorequire(:rabbitmq_vhost) do 138 | setup_autorequire('vhost') 139 | end 140 | 141 | autorequire(:rabbitmq_exchange) do 142 | setup_autorequire('exchange') 143 | end 144 | 145 | autorequire(:rabbitmq_queue) do 146 | setup_autorequire('queue') 147 | end 148 | 149 | autorequire(:rabbitmq_user) do 150 | [self[:user]] 151 | end 152 | 153 | autorequire(:rabbitmq_user_permissions) do 154 | [ 155 | "#{self[:user]}@#{self[:source]}", 156 | "#{self[:user]}@#{self[:destination]}" 157 | ] 158 | end 159 | 160 | def setup_autorequire(type) 161 | destination_type = value(:destination_type) 162 | if type == 'exchange' 163 | rval = ["#{self[:source]}@#{self[:vhost]}"] 164 | rval.push("#{self[:destination]}@#{self[:vhost]}") if destination_type == type 165 | else 166 | rval = if destination_type == type 167 | ["#{self[:destination]}@#{self[:vhost]}"] 168 | else 169 | [] 170 | end 171 | end 172 | rval 173 | end 174 | 175 | def validate_argument(argument) 176 | raise ArgumentError, 'Invalid argument' unless [Hash].include?(argument.class) 177 | end 178 | 179 | # Validate that we have both source and destination now that these are not 180 | # necessarily only coming from the resource title. 181 | validate do 182 | raise ArgumentError, '`source` must be defined' if !self[:source] && provider.source == :absent 183 | 184 | raise ArgumentError, '`destination` must be defined' if !self[:destination] && provider.destination == :absent 185 | end 186 | end 187 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_cluster.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_cluster) do 4 | desc <<~DESC 5 | Native type for managing rabbitmq cluster 6 | 7 | @example Configure a cluster, rabbit_cluster 8 | rabbitmq_cluster { 'rabbit_cluster': 9 | init_node => 'host1' 10 | } 11 | 12 | @example Optional parameter tags will set further rabbitmq tags like monitoring, policymaker, etc. 13 | To set the cluster name use cluster_name. 14 | rabbitmq_cluster { 'rabbit_cluster': 15 | init_node => 'host1', 16 | node_disc_type => 'ram', 17 | } 18 | DESC 19 | 20 | ensurable do 21 | desc 'Whether the resource should be present or absent' 22 | defaultto(:present) 23 | newvalue(:present) do 24 | provider.create 25 | end 26 | newvalue(:absent) do 27 | provider.destroy 28 | end 29 | end 30 | 31 | autorequire(:service) { 'rabbitmq-server' } 32 | 33 | newparam(:name, namevar: true) do 34 | desc 'The cluster name' 35 | end 36 | 37 | newparam(:init_node) do 38 | desc 'Name of which cluster node to join.' 39 | validate do |value| 40 | resource.validate_init_node(value) 41 | end 42 | end 43 | 44 | newparam(:local_node) do 45 | desc 'Name of the local node' 46 | defaultto(:undef) 47 | end 48 | 49 | newparam(:node_disc_type) do 50 | desc 'Storage type of node, default disc.' 51 | newvalues(%r{disc|ram}) 52 | defaultto('disc') 53 | end 54 | 55 | def validate_init_node(value) 56 | raise ArgumentError, 'init_node must be defined' if value.empty? 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_erlang_cookie.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_erlang_cookie) do 4 | desc <<~DESC 5 | Type to manage the rabbitmq erlang cookie securely 6 | 7 | This is essentially a private type used by the rabbitmq::config class 8 | to manage the erlang cookie. It replaces the rabbitmq_erlang_cookie fact 9 | from earlier versions of this module. It manages the content of the cookie 10 | usually located at "${rabbitmq_home}/.erlang.cookie", which includes 11 | stopping the rabbitmq service and wiping out the database at 12 | "${rabbitmq_home}/mnesia" if the user agrees to it. We don't recommend using 13 | this type directly. 14 | DESC 15 | 16 | newparam(:path, namevar: true) do 17 | desc 'Path of the erlang cookie' 18 | end 19 | 20 | newproperty(:content) do 21 | desc 'Content of cookie' 22 | newvalues(%r{^\S+$}) 23 | 24 | def change_to_s(_current, _desired) 25 | 'The rabbitmq erlang cookie was changed' 26 | end 27 | 28 | def is_to_s(_value) 29 | '[old content redacted]' 30 | end 31 | 32 | def should_to_s(_value) 33 | '[new content redacted]' 34 | end 35 | end 36 | 37 | newparam(:force) do 38 | desc 'Force parameter' 39 | defaultto(:false) 40 | newvalues(:true, :false) 41 | end 42 | 43 | newparam(:rabbitmq_user) do 44 | desc 'Rabbitmq User' 45 | defaultto('rabbitmq') 46 | end 47 | 48 | newparam(:rabbitmq_group) do 49 | desc 'Rabbitmq Group' 50 | defaultto('rabbitmq') 51 | end 52 | 53 | newparam(:rabbitmq_home) do 54 | desc 'Path to the rabbitmq home directory' 55 | defaultto('/var/lib/rabbitmq') 56 | end 57 | 58 | newparam(:service_name) do 59 | desc 'Name of the service' 60 | newvalues(%r{^\S+$}) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_exchange.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_exchange) do 4 | desc <<~DESC 5 | Native type for managing rabbitmq exchanges 6 | 7 | @example Create a rabbitmq_exchange 8 | rabbitmq_exchange { 'myexchange@myvhost': 9 | user => 'dan', 10 | password => 'bar', 11 | type => 'topic', 12 | ensure => present, 13 | internal => false, 14 | auto_delete => false, 15 | durable => true, 16 | arguments => { 17 | hash-header => 'message-distribution-hash' 18 | } 19 | } 20 | DESC 21 | 22 | ensurable do 23 | desc 'Whether the resource should be present or absent' 24 | defaultto(:present) 25 | newvalue(:present) do 26 | provider.create 27 | end 28 | newvalue(:absent) do 29 | provider.destroy 30 | end 31 | end 32 | 33 | newparam(:name, namevar: true) do 34 | desc 'Name of exchange' 35 | newvalues(%r{^\S*@\S+$}) 36 | end 37 | 38 | newparam(:type) do 39 | desc 'Exchange type to be set *on creation*' 40 | newvalues(%r{^\S+$}) 41 | end 42 | 43 | newparam(:durable) do 44 | desc 'Exchange durability to be set *on creation*' 45 | newvalues(%r{^\S+$}) 46 | defaultto 'false' 47 | end 48 | 49 | newparam(:auto_delete) do 50 | desc 'Exchange auto delete option to be set *on creation*' 51 | newvalues(%r{^\S+$}) 52 | defaultto 'false' 53 | end 54 | 55 | newparam(:internal) do 56 | desc 'Exchange internal option to be set *on creation*' 57 | newvalues(%r{^\S+$}) 58 | defaultto 'false' 59 | end 60 | 61 | newparam(:arguments) do 62 | desc 'Exchange arguments example: {"hash-header": "message-distribution-hash"}' 63 | defaultto({}) 64 | end 65 | 66 | newparam(:user) do 67 | desc 'The user to use to connect to rabbitmq' 68 | defaultto('guest') 69 | newvalues(%r{^\S+$}) 70 | end 71 | 72 | newparam(:password) do 73 | desc 'The password to use to connect to rabbitmq' 74 | defaultto('guest') 75 | newvalues(%r{\S+}) 76 | end 77 | 78 | validate do 79 | raise ArgumentError, "must set type when creating exchange for #{self[:name]} whose type is #{self[:type]}" if self[:ensure] == :present && self[:type].nil? 80 | end 81 | 82 | autorequire(:rabbitmq_vhost) do 83 | [self[:name].split('@')[1]] 84 | end 85 | 86 | autorequire(:rabbitmq_user) do 87 | [self[:user]] 88 | end 89 | 90 | autorequire(:rabbitmq_user_permissions) do 91 | ["#{self[:user]}@#{self[:name].split('@')[1]}"] 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_parameter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_parameter) do 4 | desc <<~DESC 5 | Type for managing rabbitmq parameters 6 | 7 | @example Create some rabbitmq_parameter resources 8 | rabbitmq_parameter { 'documentumShovel@/': 9 | component_name => '', 10 | value => { 11 | 'src-uri' => 'amqp://', 12 | 'src-queue' => 'my-queue', 13 | 'dest-uri' => 'amqp://remote-server', 14 | 'dest-queue' => 'another-queue', 15 | }, 16 | } 17 | rabbitmq_parameter { 'documentumFed@/': 18 | component_name => 'federation-upstream', 19 | value => { 20 | 'uri' => 'amqp://myserver', 21 | 'expires' => '360000', 22 | }, 23 | } 24 | rabbitmq_parameter { 'documentumShovelNoMunging@/': 25 | component_name => '', 26 | value => { 27 | 'src-uri' => 'amqp://', 28 | 'src-exchange' => 'my-exchange', 29 | 'src-exchange-key' => '6', 30 | 'src-queue' => 'my-queue', 31 | 'dest-uri' => 'amqp://remote-server', 32 | 'dest-exchange' => 'another-exchange', 33 | }, 34 | autoconvert => false, 35 | } 36 | DESC 37 | 38 | ensurable do 39 | desc 'Whether the resource should be present or absent' 40 | defaultto(:present) 41 | newvalue(:present) do 42 | provider.create 43 | end 44 | newvalue(:absent) do 45 | provider.destroy 46 | end 47 | end 48 | 49 | autorequire(:service) { 'rabbitmq-server' } 50 | 51 | validate do 52 | raise('component_name parameter is required.') if self[:ensure] == :present && provider.component_name.nil? 53 | raise('value parameter is required.') if self[:ensure] == :present && provider.value.nil? 54 | end 55 | 56 | newparam(:name, namevar: true) do 57 | desc 'combination of name@vhost to set parameter for' 58 | newvalues(%r{^\S+@\S+$}) 59 | end 60 | 61 | newproperty(:component_name) do 62 | desc 'The component_name to use when setting parameter, eg: shovel or federation' 63 | validate do |value| 64 | resource.validate_component_name(value) 65 | end 66 | end 67 | 68 | newparam(:autoconvert) do 69 | desc 'whether numeric strings from `value` should be converted to int automatically' 70 | newvalues(:true, :false) 71 | defaultto(:true) 72 | end 73 | 74 | newproperty(:value) do 75 | desc 'A hash of values to use with the component name you are setting' 76 | validate do |value| 77 | resource.validate_value(value) 78 | end 79 | munge do |value| 80 | resource.munge_value(value) 81 | end 82 | end 83 | 84 | autorequire(:rabbitmq_vhost) do 85 | [self[:name].split('@')[1]] 86 | end 87 | 88 | def set_parameters(hash) # rubocop:disable Naming/AccessorMethodName 89 | # Hack to ensure :autoconvert is initialized before :value 90 | self[:autoconvert] = hash[:autoconvert] if hash.key?(:autoconvert) 91 | super 92 | end 93 | 94 | def validate_component_name(value) 95 | raise ArgumentError, 'component_name must be defined' if value.empty? 96 | end 97 | 98 | def validate_value(value) 99 | raise ArgumentError, 'Invalid value' unless [Hash].include?(value.class) 100 | 101 | value.each do |_k, v| 102 | raise ArgumentError, 'Invalid value' unless [String, TrueClass, FalseClass, Array].include?(v.class) 103 | end 104 | end 105 | 106 | def munge_value(value) 107 | return value if value(:autoconvert) == :false 108 | 109 | value.transform_values do |v| 110 | if v.is_a?(String) && v.match?(%r{\A[-+]?[0-9]+\z}) 111 | v.to_i 112 | else 113 | v 114 | end 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_plugin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_plugin) do 4 | desc <<~DESC 5 | manages rabbitmq plugins 6 | 7 | @example query all currently enabled plugins 8 | $ puppet resource rabbitmq_plugin 9 | 10 | @example Ensure a rabbitmq_plugin resource 11 | rabbitmq_plugin {'rabbitmq_stomp': 12 | ensure => present, 13 | } 14 | 15 | @example Ensure a rabbitmq_plugin offline resource (with RabbitMQ version >=3.4.0) 16 | rabbitmq_plugin {'rabbitmq_stomp': 17 | ensure => present, 18 | mode => 'offline', 19 | } 20 | DESC 21 | 22 | ensurable do 23 | desc 'Whether the resource should be present or absent' 24 | defaultto(:present) 25 | newvalue(:present) do 26 | provider.create 27 | end 28 | newvalue(:absent) do 29 | provider.destroy 30 | end 31 | end 32 | 33 | newparam(:name, namevar: true) do 34 | desc 'The name of the plugin to enable' 35 | newvalues(%r{^\S+$}) 36 | end 37 | 38 | newparam(:mode) do 39 | desc 'Define how the plugin should be enabled regarding node status.' 40 | newvalues(:online, :offline, :best) 41 | defaultto(:best) 42 | end 43 | 44 | newparam(:umask) do 45 | desc 'Sets the octal umask to be used while creating this resource' 46 | defaultto '0022' 47 | munge do |value| 48 | raise Puppet::Error, "The umask specification is invalid: #{value.inspect}" unless value =~ %r{^0?[0-7]{1,3}$} 49 | 50 | return value.to_i(8) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # See below; these are variables that we want to auto-convert to integer 4 | # values 5 | CONVERT_TO_INT_VARS = %w[ 6 | consumer-timeout 7 | delivery-limit 8 | expires 9 | ha-sync-batch-size 10 | initial-cluster-size 11 | max-length 12 | max-length-bytes 13 | message-ttl 14 | queue-version 15 | shards-per-node 16 | target-group-size 17 | ].freeze 18 | 19 | Puppet::Type.newtype(:rabbitmq_policy) do 20 | desc <<~DESC 21 | Type for managing rabbitmq policies 22 | 23 | @example Create a rabbitmq_policy 24 | rabbitmq_policy { 'ha-all@myvhost': 25 | pattern => '.*', 26 | priority => 0, 27 | applyto => 'all', 28 | definition => { 29 | 'ha-mode' => 'all', 30 | 'ha-sync-mode' => 'automatic', 31 | }, 32 | } 33 | DESC 34 | 35 | ensurable do 36 | desc 'Whether the resource should be present or absent' 37 | defaultto(:present) 38 | newvalue(:present) do 39 | provider.create 40 | end 41 | newvalue(:absent) do 42 | provider.destroy 43 | end 44 | end 45 | 46 | autorequire(:service) { 'rabbitmq-server' } 47 | 48 | validate do 49 | raise('pattern parameter is required.') if self[:ensure] == :present && self[:pattern].nil? 50 | raise('definition parameter is required.') if self[:ensure] == :present && self[:definition].nil? 51 | end 52 | 53 | newparam(:name, namevar: true) do 54 | desc 'combination of policy@vhost to create policy for' 55 | newvalues(%r{^\S+@\S+$}) 56 | end 57 | 58 | newproperty(:pattern) do 59 | desc 'policy pattern' 60 | validate do |value| 61 | resource.validate_pattern(value) 62 | end 63 | end 64 | 65 | newproperty(:applyto) do 66 | desc 'policy apply to' 67 | newvalue(:all) 68 | newvalue(:classic_queues) 69 | newvalue(:exchanges) 70 | newvalue(:queues) 71 | newvalue(:quorum_queues) 72 | newvalue(:streams) 73 | defaultto :all 74 | end 75 | 76 | newproperty(:definition) do 77 | desc 'policy definition' 78 | validate do |value| 79 | resource.validate_definition(value) 80 | end 81 | munge do |value| 82 | resource.munge_definition(value) 83 | end 84 | end 85 | 86 | newproperty(:priority) do 87 | desc 'policy priority' 88 | newvalues(%r{^\d+$}) 89 | defaultto 0 90 | end 91 | 92 | autorequire(:rabbitmq_vhost) do 93 | [self[:name].split('@')[1]] 94 | end 95 | 96 | def validate_pattern(value) 97 | Regexp.new(value) 98 | rescue RegexpError 99 | raise ArgumentError, "Invalid regexp #{value}" 100 | end 101 | 102 | def validate_definition(definition) 103 | raise ArgumentError, 'Invalid definition' unless [Hash].include?(definition.class) 104 | 105 | definition.each do |k, v| 106 | if k == 'ha-params' && definition['ha-mode'] == 'nodes' 107 | raise ArgumentError, "Invalid definition, value #{v} for key #{k} is not an array" unless [Array].include?(v.class) 108 | else 109 | raise ArgumentError, "Invalid definition, value #{v} is not a string" unless [String].include?(v.class) 110 | end 111 | end 112 | if definition['ha-mode'] == 'exactly' 113 | ha_params = definition['ha-params'] 114 | raise ArgumentError, "Invalid ha-params '#{ha_params}' for ha-mode 'exactly'" unless ha_params.to_i.to_s == ha_params 115 | end 116 | 117 | # Since this pattern is repeated, use a constant to track all the types 118 | # where we need to convert a string value to an unquoted integer explicitly 119 | definition.each do |k, v| 120 | raise ArgumentError, "Invalid #{k} value '#{v}'" if CONVERT_TO_INT_VARS.include?(k) && v.to_i.to_s != v 121 | end 122 | end 123 | 124 | def munge_definition(definition) 125 | definition['ha-params'] = definition['ha-params'].to_i if definition['ha-mode'] == 'exactly' 126 | 127 | # Again, use a list of types to convert vs. hard-coding each one 128 | definition.each do |k, v| 129 | definition[k] = v.to_i if CONVERT_TO_INT_VARS.include? k 130 | end 131 | 132 | definition 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_queue.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_queue) do 4 | desc <<~DESC 5 | Native type for managing rabbitmq queue 6 | 7 | @example Create a rabbitmq_queue 8 | rabbitmq_queue { 'myqueue@myvhost': 9 | ensure => present, 10 | user => 'dan', 11 | password => 'bar', 12 | durable => true, 13 | auto_delete => false, 14 | arguments => { 15 | x-message-ttl => 123, 16 | x-dead-letter-exchange => 'other' 17 | }, 18 | } 19 | DESC 20 | 21 | ensurable do 22 | desc 'Whether the resource should be present or absent' 23 | defaultto(:present) 24 | newvalue(:present) do 25 | provider.create 26 | end 27 | newvalue(:absent) do 28 | provider.destroy 29 | end 30 | end 31 | 32 | newparam(:name, namevar: true) do 33 | desc 'Name of queue' 34 | newvalues(%r{^\S*@\S+$}) 35 | end 36 | 37 | newparam(:durable) do 38 | desc 'Queue is durable' 39 | newvalues(%r{true|false}) 40 | defaultto('true') 41 | end 42 | 43 | newparam(:auto_delete) do 44 | desc 'Queue will be auto deleted' 45 | newvalues(%r{true|false}) 46 | defaultto('false') 47 | end 48 | 49 | newparam(:arguments) do 50 | desc 'Queue arguments example: {x-message-ttl => 60, x-expires => 10}' 51 | defaultto({}) 52 | validate do |value| 53 | resource.validate_argument(value) 54 | end 55 | end 56 | 57 | newparam(:user) do 58 | desc 'The user to use to connect to rabbitmq' 59 | defaultto('guest') 60 | newvalues(%r{^\S+$}) 61 | end 62 | 63 | newparam(:password) do 64 | desc 'The password to use to connect to rabbitmq' 65 | defaultto('guest') 66 | newvalues(%r{\S+}) 67 | end 68 | 69 | autorequire(:rabbitmq_vhost) do 70 | [self[:name].split('@')[1]] 71 | end 72 | 73 | autorequire(:rabbitmq_user) do 74 | [self[:user]] 75 | end 76 | 77 | autorequire(:rabbitmq_user_permissions) do 78 | ["#{self[:user]}@#{self[:name].split('@')[1]}"] 79 | end 80 | 81 | def validate_argument(argument) 82 | raise ArgumentError, 'Invalid argument' unless [Hash].include?(argument.class) 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_user) do 4 | desc <<~DESC 5 | Native type for managing rabbitmq users 6 | 7 | @example query all current users 8 | $ puppet resource rabbitmq_user 9 | 10 | @example Configure a user, dan 11 | rabbitmq_user { 'dan': 12 | admin => true, 13 | password => 'bar', 14 | } 15 | 16 | @example Optional parameter tags will set further rabbitmq tags like monitoring, policymaker, etc. 17 | To set the administrator tag use admin-flag. 18 | rabbitmq_user { 'dan': 19 | admin => true, 20 | password => 'bar', 21 | tags => ['monitoring', 'tag1'], 22 | } 23 | DESC 24 | 25 | ensurable do 26 | desc 'Whether the resource should be present or absent' 27 | defaultto(:present) 28 | newvalue(:present) do 29 | provider.create 30 | end 31 | newvalue(:absent) do 32 | provider.destroy 33 | end 34 | end 35 | 36 | autorequire(:service) { 'rabbitmq-server' } 37 | 38 | newparam(:name, namevar: true) do 39 | desc 'Name of user' 40 | newvalues(%r{^\S+$}) 41 | end 42 | 43 | newproperty(:password) do 44 | desc 'User password to be set *on creation* and validated each run' 45 | def insync?(_is) 46 | provider.check_password(should) 47 | end 48 | 49 | def change_to_s(_current, _desired) 50 | 'password has been changed' 51 | end 52 | 53 | def is_to_s(_value) 54 | '[old password redacted]' 55 | end 56 | 57 | def should_to_s(_value) 58 | '[new password redacted]' 59 | end 60 | end 61 | 62 | newproperty(:admin) do 63 | desc 'whether or not user should be an admin' 64 | newvalues(%r{true|false}) 65 | munge do |value| 66 | # converting to_s in case its a boolean 67 | value.to_s.to_sym 68 | end 69 | defaultto :false 70 | end 71 | 72 | newproperty(:tags, array_matching: :all) do 73 | desc 'additional tags for the user' 74 | validate do |value| 75 | raise ArgumentError, "Invalid tag: #{value.inspect}" unless value =~ %r{^\S+$} 76 | 77 | raise ArgumentError, 'must use admin property instead of administrator tag' if value == 'administrator' 78 | end 79 | defaultto [] 80 | 81 | def insync?(is) 82 | is.sort == should.sort 83 | end 84 | 85 | def should_to_s(value) 86 | Array(value) 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_user_permissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_user_permissions) do 4 | desc <<~DESC 5 | Type for managing rabbitmq user permissions 6 | 7 | @example Define some rabbitmq_user_permissions 8 | rabbitmq_user_permissions { 'dan@myvhost': 9 | configure_permission => '.*', 10 | read_permission => '.*', 11 | write_permission => '.*', 12 | } 13 | DESC 14 | 15 | ensurable do 16 | desc 'Whether the resource should be present or absent' 17 | defaultto(:present) 18 | newvalue(:present) do 19 | provider.create 20 | end 21 | newvalue(:absent) do 22 | provider.destroy 23 | end 24 | end 25 | 26 | autorequire(:service) { 'rabbitmq-server' } 27 | 28 | newparam(:name, namevar: true) do 29 | desc 'combination of user@vhost to grant privileges to' 30 | newvalues(%r{^\S+@\S+$}) 31 | end 32 | 33 | newproperty(:configure_permission) do 34 | desc 'regexp representing configuration permissions' 35 | validate do |value| 36 | resource.validate_permissions(value) 37 | end 38 | end 39 | 40 | newproperty(:read_permission) do 41 | desc 'regexp representing read permissions' 42 | validate do |value| 43 | resource.validate_permissions(value) 44 | end 45 | end 46 | 47 | newproperty(:write_permission) do 48 | desc 'regexp representing write permissions' 49 | validate do |value| 50 | resource.validate_permissions(value) 51 | end 52 | end 53 | 54 | autorequire(:rabbitmq_vhost) do 55 | [self[:name].split('@')[1]] 56 | end 57 | 58 | autorequire(:rabbitmq_user) do 59 | [self[:name].split('@')[0]] 60 | end 61 | 62 | def validate_permissions(value) 63 | Regexp.new(value) 64 | rescue RegexpError 65 | raise ArgumentError, "Invalid regexp #{value}" 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/puppet/type/rabbitmq_vhost.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:rabbitmq_vhost) do 4 | desc <<~DESC 5 | Native type for managing rabbitmq vhosts 6 | 7 | @example query all current vhosts 8 | $ puppet resource rabbitmq_vhost` 9 | 10 | @example Create a rabbitmq_vhost 11 | rabbitmq_vhost { 'myvhost': 12 | ensure => present, 13 | description => 'myvhost description', 14 | tags => ['tag1', 'tag2'], 15 | default_queue_type => 'quorum', 16 | } 17 | DESC 18 | 19 | ensurable do 20 | desc 'Whether the resource should be present or absent' 21 | defaultto(:present) 22 | newvalue(:present) do 23 | provider.create 24 | end 25 | newvalue(:absent) do 26 | provider.destroy 27 | end 28 | end 29 | 30 | autorequire(:service) { 'rabbitmq-server' } 31 | 32 | newparam(:name, namevar: true) do 33 | desc 'The name of the vhost to add' 34 | newvalues(%r{^\S+$}) 35 | end 36 | 37 | newproperty(:description) do 38 | desc 'A description of the vhost' 39 | end 40 | 41 | newproperty(:default_queue_type) do 42 | desc 'The default queue type for queues in this vhost' 43 | newvalues(:classic, :quorum, :stream) 44 | munge(&:to_s) 45 | end 46 | 47 | newproperty(:tags, array_matching: :all) do 48 | desc 'additional tags for the vhost' 49 | validate do |value| 50 | raise ArgumentError, "Invalid tag: #{value.inspect}" unless value =~ %r{^\S+$} 51 | end 52 | defaultto [] 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /locales/config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is the project-specific configuration file for setting up 3 | # fast_gettext for your project. 4 | gettext: 5 | # This is used for the name of the .pot and .po files; they will be 6 | # called .pot? 7 | project_name: puppetlabs-rabbitmq 8 | # This is used in comments in the .pot and .po files to indicate what 9 | # project the files belong to and should bea little more desctiptive than 10 | # 11 | package_name: puppetlabs-rabbitmq 12 | # The locale that the default messages in the .pot file are in 13 | default_locale: en 14 | # The email used for sending bug reports. 15 | bugs_address: docs@puppet.com 16 | # The holder of the copyright. 17 | copyright_holder: Puppet, Inc. 18 | # This determines which comments in code should be eligible for translation. 19 | # Any comments that start with this string will be externalized. (Leave 20 | # empty to include all.) 21 | comments_tag: TRANSLATOR 22 | # Patterns for +Dir.glob+ used to find all files that might contain 23 | # translatable content, relative to the project root directory 24 | source_files: 25 | 26 | -------------------------------------------------------------------------------- /manifests/install.pp: -------------------------------------------------------------------------------- 1 | # Ensures that rabbitmq-server exists 2 | # 3 | # @api private 4 | class rabbitmq::install { 5 | $package_ensure = $rabbitmq::package_ensure 6 | $package_name = $rabbitmq::package_name 7 | $rabbitmq_group = $rabbitmq::rabbitmq_group 8 | 9 | package { $package_name: 10 | ensure => $package_ensure, 11 | notify => Class['rabbitmq::service'], 12 | } 13 | 14 | if $rabbitmq::environment_variables['MNESIA_BASE'] { 15 | file { $rabbitmq::environment_variables['MNESIA_BASE']: 16 | ensure => 'directory', 17 | owner => 'root', 18 | group => $rabbitmq_group, 19 | mode => '0775', 20 | require => Package[$package_name], 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /manifests/install/rabbitmqadmin.pp: -------------------------------------------------------------------------------- 1 | # Install rabbitmq admin 2 | # 3 | # @api private 4 | class rabbitmq::install::rabbitmqadmin { 5 | if $rabbitmq::rabbitmqadmin_package { 6 | package { 'rabbitmqadmin': 7 | ensure => 'present', 8 | name => $rabbitmq::rabbitmqadmin_package, 9 | } 10 | } else { 11 | $python_package = $rabbitmq::python_package 12 | # Some systems (e.g., Ubuntu 16.04) don't ship Python 2 by default 13 | if $rabbitmq::manage_python { 14 | stdlib::ensure_packages([$python_package]) 15 | $rabbitmqadmin_require = [Archive['rabbitmqadmin'], Package[$python_package]] 16 | } else { 17 | $rabbitmqadmin_require = Archive['rabbitmqadmin'] 18 | } 19 | 20 | if($rabbitmq::ssl and $rabbitmq::management_ssl) { 21 | $management_port = $rabbitmq::ssl_management_port 22 | $protocol = 'https' 23 | } else { 24 | $management_port = $rabbitmq::management_port 25 | $protocol = 'http' 26 | } 27 | 28 | $default_user = $rabbitmq::default_user 29 | $default_pass = $rabbitmq::default_pass 30 | $archive_options = $rabbitmq::archive_options 31 | 32 | # This should be consistent with rabbitmq::config 33 | if $rabbitmq::management_ip_address { 34 | $management_ip_address = $rabbitmq::management_ip_address 35 | } else { 36 | $management_ip_address = $rabbitmq::node_ip_address 37 | } 38 | 39 | if !($management_ip_address) { 40 | # Pull from localhost if we don't have an explicit bind address 41 | $sanitized_ip = '127.0.0.1' 42 | } elsif $management_ip_address =~ Stdlib::IP::Address::V6::Nosubnet { 43 | $sanitized_ip = join(enclose_ipv6(any2array($management_ip_address)), ',') 44 | } else { 45 | $sanitized_ip = $management_ip_address 46 | } 47 | 48 | if !($rabbitmq::use_config_file_for_plugins) { 49 | $rabbitmqadmin_archive_require = [ 50 | Class['rabbitmq::service'], 51 | Rabbitmq_plugin['rabbitmq_management'], 52 | Exec['remove_old_rabbitmqadmin_on_upgrade'] 53 | ] 54 | } else { 55 | $rabbitmqadmin_archive_require = [ 56 | Class['rabbitmq::service'], 57 | File['enabled_plugins'], 58 | Exec['remove_old_rabbitmqadmin_on_upgrade'] 59 | ] 60 | } 61 | 62 | Exec { 'remove_old_rabbitmqadmin_on_upgrade': 63 | path => ['/bin','/usr/bin','/sbin','/usr/sbin'], 64 | command => "rm ${rabbitmq::rabbitmq_home}/rabbitmqadmin", 65 | onlyif => ["test -f ${rabbitmq::rabbitmq_home}/rabbitmqadmin"], 66 | refreshonly => true, 67 | } 68 | 69 | archive { 'rabbitmqadmin': 70 | path => "${rabbitmq::rabbitmq_home}/rabbitmqadmin", 71 | source => "${protocol}://${sanitized_ip}:${management_port}/cli/rabbitmqadmin", 72 | username => $default_user, 73 | password => $default_pass, 74 | allow_insecure => true, 75 | download_options => $archive_options, 76 | cleanup => false, 77 | require => $rabbitmqadmin_archive_require, 78 | } 79 | 80 | file { '/usr/local/bin/rabbitmqadmin': 81 | owner => 'root', 82 | group => '0', 83 | source => "${rabbitmq::rabbitmq_home}/rabbitmqadmin", 84 | mode => '0755', 85 | require => $rabbitmqadmin_require, 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /manifests/management.pp: -------------------------------------------------------------------------------- 1 | # Manage presence / absence of user resource for guest management user. 2 | # 3 | # @api private 4 | class rabbitmq::management { 5 | $delete_guest_user = $rabbitmq::delete_guest_user 6 | 7 | if $delete_guest_user { 8 | rabbitmq_user { 'guest': 9 | ensure => absent, 10 | provider => 'rabbitmqctl', 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /manifests/repo/apt.pp: -------------------------------------------------------------------------------- 1 | # requires 2 | # puppetlabs-apt 3 | # puppetlabs-stdlib 4 | # 5 | # @api private 6 | # 7 | # @param location 8 | # @param repos 9 | # @param include_src 10 | # @param key 11 | # @param key_source 12 | # @param key_content 13 | # @param architecture 14 | # 15 | class rabbitmq::repo::apt ( 16 | String[1] $location = 'https://packagecloud.io/rabbitmq/rabbitmq-server', 17 | String[1] $repos = 'main', 18 | Boolean $include_src = false, 19 | String[1] $key = '8C695B0219AFDEB04A058ED8F4E789204D206F89', 20 | String[1] $key_source = $rabbitmq::package_gpg_key, 21 | Optional[String[1]] $key_content = $rabbitmq::key_content, 22 | Optional[String[1]] $architecture = undef, 23 | ) { 24 | $osname = downcase($facts['os']['name']) 25 | $pin = $rabbitmq::package_apt_pin 26 | 27 | apt::source { 'rabbitmq': 28 | ensure => present, 29 | location => "${location}/${osname}", 30 | repos => $repos, 31 | include => { 'src' => $include_src }, 32 | key => { 33 | 'id' => $key, 34 | 'source' => $key_source, 35 | 'content' => $key_content, 36 | }, 37 | architecture => $architecture, 38 | } 39 | 40 | if $pin { 41 | apt::pin { 'rabbitmq': 42 | packages => '*', 43 | priority => $pin, 44 | origin => inline_template('<%= require \'uri\'; URI(@location).host %>'), 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /manifests/repo/rhel.pp: -------------------------------------------------------------------------------- 1 | # Makes sure that the Packagecloud repo is installed 2 | # 3 | # @api private 4 | # 5 | # @param location 6 | # @param repo_key_source 7 | # @param package_key_source 8 | # 9 | class rabbitmq::repo::rhel ( 10 | String[1] $location = "https://packagecloud.io/rabbitmq/rabbitmq-server/el/${facts['os'][release][major]}/\$basearch", 11 | String[1] $repo_key_source = $rabbitmq::repo_gpg_key, 12 | String[1] $package_key_source = $rabbitmq::package_gpg_key, 13 | ) { 14 | # Import package key from rabbitmq to be able to 15 | # sign the package and the repo. 16 | # rabbitmq key is gpg-pubkey-6026dfca-573adfde 17 | exec { "rpm --import ${package_key_source}": 18 | path => ['/bin','/usr/bin','/sbin','/usr/sbin'], 19 | unless => 'rpm -q gpg-pubkey-6026dfca-573adfde 2>/dev/null', 20 | before => YumRepo['rabbitmq'], 21 | } 22 | 23 | yumrepo { 'rabbitmq': 24 | ensure => present, 25 | name => 'rabbitmq_rabbitmq-server', 26 | baseurl => $location, 27 | gpgkey => $repo_key_source, 28 | enabled => 1, 29 | gpgcheck => 1, 30 | repo_gpgcheck => 1, 31 | } 32 | 33 | # This may still be needed to prevent warnings 34 | # packagecloud key is gpg-pubkey-4d206f89-5bbb8d59 35 | exec { "rpm --import ${repo_key_source}": 36 | path => ['/bin','/usr/bin','/sbin','/usr/sbin'], 37 | unless => 'rpm -q gpg-pubkey-4d206f89-5bbb8d59 2>/dev/null', 38 | require => YumRepo['rabbitmq'], 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /manifests/service.pp: -------------------------------------------------------------------------------- 1 | # This class manages the rabbitmq server service itself. 2 | # 3 | # @api private 4 | # 5 | # @param service_ensure 6 | # @param service_manage 7 | # @param service_name 8 | # 9 | class rabbitmq::service ( 10 | Enum['running', 'stopped'] $service_ensure = $rabbitmq::service_ensure, 11 | Boolean $service_manage = $rabbitmq::service_manage, 12 | String[1] $service_name = $rabbitmq::service_name, 13 | ) inherits rabbitmq { 14 | if ($service_manage) { 15 | if $service_ensure == 'running' { 16 | $ensure_real = 'running' 17 | $enable_real = true 18 | } else { 19 | $ensure_real = 'stopped' 20 | $enable_real = false 21 | } 22 | 23 | service { 'rabbitmq-server': 24 | ensure => $ensure_real, 25 | enable => $enable_real, 26 | hasstatus => true, 27 | hasrestart => true, 28 | name => $service_name, 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppet-rabbitmq", 3 | "version": "14.4.0", 4 | "author": "Vox Pupuli", 5 | "summary": "Installs, configures, and manages RabbitMQ.", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/voxpupuli/puppet-rabbitmq", 8 | "project_page": "https://github.com/voxpupuli/puppet-rabbitmq", 9 | "issues_url": "https://github.com/voxpupuli/puppet-rabbitmq/issues", 10 | "operatingsystem_support": [ 11 | { 12 | "operatingsystem": "RedHat", 13 | "operatingsystemrelease": [ 14 | "9" 15 | ] 16 | }, 17 | { 18 | "operatingsystem": "CentOS", 19 | "operatingsystemrelease": [ 20 | "9" 21 | ] 22 | }, 23 | { 24 | "operatingsystem": "Debian", 25 | "operatingsystemrelease": [ 26 | "11" 27 | ] 28 | }, 29 | { 30 | "operatingsystem": "Ubuntu", 31 | "operatingsystemrelease": [ 32 | "20.04", 33 | "22.04" 34 | ] 35 | }, 36 | { 37 | "operatingsystem": "SLES", 38 | "operatingsystemrelease": [ 39 | "11" 40 | ] 41 | }, 42 | { 43 | "operatingsystem": "FreeBSD", 44 | "operatingsystemrelease": [ 45 | "13", 46 | "14" 47 | ] 48 | }, 49 | { 50 | "operatingsystem": "OpenBSD" 51 | } 52 | ], 53 | "requirements": [ 54 | { 55 | "name": "puppet", 56 | "version_requirement": ">= 7.0.0 < 9.0.0" 57 | }, 58 | { 59 | "name": "openvox", 60 | "version_requirement": ">= 7.0.0 < 9.0.0" 61 | } 62 | ], 63 | "dependencies": [ 64 | { 65 | "name": "puppetlabs/stdlib", 66 | "version_requirement": ">= 4.25.0 < 10.0.0" 67 | }, 68 | { 69 | "name": "puppet/archive", 70 | "version_requirement": ">= 2.0.0 < 8.0.0" 71 | }, 72 | { 73 | "name": "puppet/systemd", 74 | "version_requirement": ">= 6.0.0 < 9.0.0" 75 | } 76 | ], 77 | "tags": [ 78 | "rabbitmq", 79 | "ampq", 80 | "messaging", 81 | "stomp", 82 | "queue" 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /spec/README.markdown: -------------------------------------------------------------------------------- 1 | Specs 2 | ===== 3 | 4 | The Puppet project uses RSpec for testing. 5 | 6 | For more information on RSpec, see http://rspec.info/ 7 | 8 | -------------------------------------------------------------------------------- /spec/acceptance/class_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq class:' do 6 | case fact('os.family') 7 | when 'RedHat', 'SUSE', 'Debian' 8 | package_name = 'rabbitmq-server' 9 | service_name = 'rabbitmq-server' 10 | when 'Archlinux' 11 | package_name = 'rabbitmq' 12 | service_name = 'rabbitmq' 13 | end 14 | 15 | context 'default class inclusion' do 16 | let(:pp) do 17 | <<-EOS 18 | include rabbitmq 19 | EOS 20 | end 21 | 22 | it_behaves_like 'an idempotent resource' 23 | 24 | describe package(package_name) do 25 | it { is_expected.to be_installed } 26 | end 27 | 28 | describe service(service_name) do 29 | it { is_expected.to be_enabled } 30 | it { is_expected.to be_running } 31 | end 32 | 33 | describe file('/etc/rabbitmq') do 34 | it { is_expected.to be_directory } 35 | it { is_expected.to be_owned_by 'rabbitmq' } 36 | it { is_expected.to be_grouped_into 'rabbitmq' } 37 | end 38 | 39 | describe file('/etc/rabbitmq/ssl') do 40 | it { is_expected.to be_directory } 41 | it { is_expected.to be_owned_by 'rabbitmq' } 42 | it { is_expected.to be_grouped_into 'rabbitmq' } 43 | it { is_expected.not_to be_readable.by('others') } 44 | end 45 | end 46 | 47 | context 'disable and stop service' do 48 | let(:pp) do 49 | <<-EOS 50 | class { 'rabbitmq': 51 | service_ensure => 'stopped', 52 | } 53 | EOS 54 | end 55 | 56 | it_behaves_like 'an idempotent resource' 57 | 58 | describe service(service_name) do 59 | it { is_expected.not_to be_enabled } 60 | it { is_expected.not_to be_running } 61 | end 62 | end 63 | 64 | context 'service is unmanaged' do 65 | it 'runs successfully' do 66 | pp_pre = <<-EOS 67 | include rabbitmq 68 | EOS 69 | 70 | pp = <<-EOS 71 | class { 'rabbitmq': 72 | service_manage => false, 73 | service_ensure => 'stopped', 74 | } 75 | EOS 76 | 77 | apply_manifest(pp_pre, catch_failures: true) 78 | apply_manifest(pp, catch_failures: true) 79 | end 80 | 81 | describe service(service_name) do 82 | it { is_expected.to be_enabled } 83 | it { is_expected.to be_running } 84 | end 85 | end 86 | 87 | context 'binding on all interfaces' do 88 | let(:pp) do 89 | <<-EOS 90 | class { 'rabbitmq': 91 | service_manage => true, 92 | port => 5672, 93 | admin_enable => true, 94 | node_ip_address => '0.0.0.0' 95 | } 96 | EOS 97 | end 98 | 99 | it_behaves_like 'an idempotent resource' 100 | 101 | describe service(service_name) do 102 | it { is_expected.to be_running } 103 | end 104 | 105 | describe port(5672), :port5672 do 106 | it { is_expected.to be_listening.on('0.0.0.0').with('tcp') } 107 | end 108 | 109 | describe port(15_672) do 110 | it { is_expected.to be_listening.on('0.0.0.0').with('tcp') } 111 | end 112 | 113 | describe port(25_672) do 114 | xit 'Is on 55672 instead on older rmq versions' do 115 | is_expected.to be_listening.on('0.0.0.0').with('tcp') 116 | end 117 | end 118 | end 119 | 120 | context 'binding to localhost only' do 121 | let(:pp) do 122 | <<-EOS 123 | class { 'rabbitmq': 124 | service_manage => true, 125 | port => 5672, 126 | admin_enable => true, 127 | node_ip_address => '127.0.0.1' 128 | } 129 | EOS 130 | end 131 | 132 | it_behaves_like 'an idempotent resource' 133 | 134 | describe service(service_name) do 135 | it { is_expected.to be_running } 136 | end 137 | 138 | describe port(5672), :port5671 do 139 | it { is_expected.to be_listening.on('127.0.0.1').with('tcp') } 140 | end 141 | 142 | describe port(15_672) do 143 | it { is_expected.to be_listening.on('127.0.0.1').with('tcp') } 144 | end 145 | 146 | # This listens on all interfaces regardless of these settings 147 | 148 | describe port(25_672) do 149 | xit 'Is on 55672 instead on older rmq versions' do 150 | is_expected.to be_listening.on('0.0.0.0').with('tcp') 151 | end 152 | end 153 | end 154 | 155 | context 'ssl enabled' do 156 | let(:pp) do 157 | <<-EOS 158 | class { 'rabbitmq': 159 | service_manage => true, 160 | admin_enable => true, 161 | node_ip_address => '0.0.0.0', 162 | ssl_interface => '0.0.0.0', 163 | ssl => true, 164 | ssl_cacert => '/tmp/cacert.crt', 165 | ssl_cert => '/tmp/rabbitmq.crt', 166 | ssl_key => '/tmp/rabbitmq.key', 167 | } 168 | EOS 169 | end 170 | 171 | it_behaves_like 'an idempotent resource' 172 | 173 | describe service(service_name) do 174 | it { is_expected.to be_running } 175 | end 176 | 177 | describe port(5671), :port5671 do 178 | it { is_expected.to be_listening.on('0.0.0.0').with('tcp') } 179 | end 180 | 181 | describe port(15_671) do 182 | it { is_expected.to be_listening.on('0.0.0.0').with('tcp') } 183 | end 184 | end 185 | 186 | context 'different management_ip_address and node_ip_address' do 187 | let(:pp) do 188 | <<-EOS 189 | class { 'rabbitmq': 190 | service_manage => true, 191 | port => 5672, 192 | admin_enable => true, 193 | node_ip_address => '0.0.0.0', 194 | management_ip_address => '127.0.0.1' 195 | } 196 | EOS 197 | end 198 | 199 | it_behaves_like 'an idempotent resource' 200 | 201 | describe service(service_name) do 202 | it { is_expected.to be_running } 203 | end 204 | 205 | describe port(5672), :port5672 do 206 | it { is_expected.to be_listening.on('0.0.0.0').with('tcp') } 207 | end 208 | 209 | describe port(15_672) do 210 | it { is_expected.to be_listening.on('127.0.0.1').with('tcp') } 211 | end 212 | 213 | describe port(25_672) do 214 | xit 'Is on 55672 instead on older rmq versions' do 215 | is_expected.to be_listening.on('0.0.0.0').with('tcp') 216 | end 217 | end 218 | end 219 | end 220 | -------------------------------------------------------------------------------- /spec/acceptance/clustering_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq clustering' do 6 | context 'rabbitmq::wipe_db_on_cookie_change => false' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | cluster => { 'name' => 'rabbit_cluster', 'init_node' => $facts['networking']['fqdn'] }, 11 | config_cluster => true, 12 | cluster_nodes => ['rabbit1', 'rabbit2'], 13 | cluster_node_type => 'ram', 14 | erlang_cookie => 'TESTCOOKIE', 15 | wipe_db_on_cookie_change => false, 16 | } 17 | EOS 18 | 19 | apply_manifest(pp, expect_failures: true) 20 | end 21 | 22 | describe file('/var/lib/rabbitmq/.erlang.cookie') do 23 | it { is_expected.not_to contain 'TESTCOOKIE' } 24 | end 25 | end 26 | 27 | context 'rabbitmq::wipe_db_on_cookie_change => true' do 28 | it 'runs successfully' do 29 | pp = <<-EOS 30 | class { 'rabbitmq': 31 | cluster => { 'name' => 'rabbit_cluster', 'init_node' => $facts['networking']['fqdn'] }, 32 | config_cluster => true, 33 | cluster_nodes => ['rabbit1', 'rabbit2'], 34 | cluster_node_type => 'ram', 35 | erlang_cookie => 'TESTCOOKIE', 36 | wipe_db_on_cookie_change => true, 37 | } 38 | EOS 39 | 40 | apply_manifest(pp, catch_failures: true) 41 | end 42 | 43 | describe file('/etc/rabbitmq/rabbitmq.config') do 44 | it { is_expected.to be_file } 45 | it { is_expected.to contain 'cluster_nodes' } 46 | it { is_expected.to contain 'rabbit@rabbit1' } 47 | it { is_expected.to contain 'rabbit@rabbit2' } 48 | it { is_expected.to contain 'ram' } 49 | end 50 | 51 | describe file('/var/lib/rabbitmq/.erlang.cookie') do 52 | it { is_expected.to be_file } 53 | it { is_expected.to contain 'TESTCOOKIE' } 54 | end 55 | 56 | describe 'rabbitmq_cluster' do 57 | context 'cluster_name => rabbit_cluster' do 58 | it 'cluster has name' do 59 | shell('rabbitmqctl -q cluster_status') do |r| 60 | expect(r.stdout).to match(%r!({cluster_name,<<"rabbit_cluster">>}|^Cluster name: rabbit_cluster$)!) 61 | expect(r.exit_code).to be_zero 62 | end 63 | end 64 | end 65 | end 66 | end 67 | 68 | context 'rabbitmq::cluster[:local_node] = foobar' do 69 | it 'runs successfully' do 70 | pp = <<-EOS 71 | # Needed to avoid nxdomain error 72 | host { 'foobar': 73 | ip => '127.0.0.1', 74 | } 75 | class { 'rabbitmq': 76 | cluster => { 'name' => 'rabbit_cluster', 'init_node' => 'foobar', 'local_node' => 'foobar' }, 77 | config_cluster => true, 78 | cluster_nodes => ['foobar', 'rabbit2'], 79 | cluster_node_type => 'ram', 80 | environment_variables => { 'NODENAME' => 'rabbit@foobar' }, 81 | erlang_cookie => 'TESTCOOKIE', 82 | } 83 | EOS 84 | 85 | apply_manifest(pp, catch_failures: true) 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /spec/acceptance/delete_guest_user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq with delete_guest_user' do 6 | context 'delete_guest_user' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | port => 5672, 11 | delete_guest_user => true, 12 | } 13 | EOS 14 | 15 | apply_manifest(pp, catch_failures: true) 16 | shell('rabbitmqctl list_users > /tmp/rabbitmqctl_users') 17 | end 18 | 19 | describe file('/tmp/rabbitmqctl_users') do 20 | it { is_expected.to be_file } 21 | it { is_expected.not_to contain 'guest' } 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/acceptance/parameter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq parameter on a vhost:' do 6 | context 'create parameter resource' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | service_manage => true, 11 | port => 5672, 12 | delete_guest_user => true, 13 | admin_enable => true, 14 | } 15 | 16 | rabbitmq_plugin { [ 'rabbitmq_federation_management', 'rabbitmq_federation' ]: 17 | ensure => present 18 | } ~> Service['rabbitmq-server'] 19 | 20 | rabbitmq_vhost { 'fedhost': 21 | ensure => present, 22 | } -> 23 | 24 | rabbitmq_parameter { 'documentumFed@fedhost': 25 | component_name => 'federation-upstream', 26 | value => { 27 | 'uri' => 'amqp://server', 28 | 'expires' => '3600000', 29 | }, 30 | } 31 | EOS 32 | 33 | apply_manifest(pp, catch_failures: true) 34 | apply_manifest(pp, catch_changes: true) 35 | end 36 | 37 | it 'has the parameter' do 38 | shell('rabbitmqctl list_parameters -p fedhost') do |r| 39 | expect(r.stdout).to match(%r{federation-upstream.*documentumFed.*expires.*3600000}) 40 | expect(r.exit_code).to be_zero 41 | end 42 | end 43 | end 44 | 45 | context 'destroy parameter resource' do 46 | it 'runs successfully' do 47 | pp = <<-EOS 48 | rabbitmq_parameter { 'documentumFed@fedhost': 49 | ensure => absent, 50 | } 51 | EOS 52 | 53 | apply_manifest(pp, catch_failures: true) 54 | apply_manifest(pp, catch_changes: true) 55 | end 56 | 57 | it 'does not have the parameter' do 58 | shell('rabbitmqctl list_parameters -q') do |r| 59 | expect(r.stdout).not_to match(%r{documentumFed\s+}) 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/acceptance/policy_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq policy on a vhost:' do 6 | context 'create policy resource' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | service_manage => true, 11 | port => 5672, 12 | delete_guest_user => true, 13 | admin_enable => true, 14 | } -> 15 | 16 | rabbitmq_vhost { 'myhost': 17 | ensure => present, 18 | } -> 19 | 20 | rabbitmq_policy { 'ha-all@myhost': 21 | pattern => '.*', 22 | priority => 0, 23 | applyto => 'all', 24 | definition => { 25 | 'ha-mode' => 'all', 26 | 'ha-sync-mode' => 'automatic', 27 | }, 28 | } 29 | 30 | rabbitmq_policy { 'eu-federation@myhost': 31 | pattern => '^eu\\.', 32 | priority => 0, 33 | applyto => 'all', 34 | definition => { 35 | 'federation-upstream-set' => 'all', 36 | }, 37 | } 38 | EOS 39 | 40 | apply_manifest(pp, catch_failures: true) 41 | apply_manifest(pp, catch_changes: true) 42 | 43 | # Apply twice to ensure no changes the second time. 44 | apply_manifest(pp, catch_failures: true) 45 | expect(apply_manifest(pp, catch_changes: true).exit_code).to be_zero 46 | end 47 | 48 | it 'has the policy' do 49 | shell('rabbitmqctl list_policies -p myhost') do |r| 50 | expect(r.stdout).to match(%r{myhost.*ha-all.*ha-sync-mode}) 51 | expect(r.stdout).to match(%r{myhost.*eu-federation}) 52 | expect(r.exit_code).to be_zero 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/acceptance/rabbitmqadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq::install::rabbitmqadmin class' do 6 | context 'downloads the cli tools' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | admin_enable => true, 11 | service_manage => true, 12 | } 13 | EOS 14 | 15 | apply_manifest(pp, catch_failures: true) 16 | end 17 | 18 | describe file('/var/lib/rabbitmq/rabbitmqadmin') do 19 | it { is_expected.to be_file } 20 | end 21 | end 22 | 23 | context 'does nothing if service is unmanaged' do 24 | it 'runs successfully' do 25 | pp = <<-EOS 26 | class { 'rabbitmq': 27 | admin_enable => true, 28 | service_manage => false, 29 | } 30 | EOS 31 | 32 | shell('rm -f /var/lib/rabbitmq/rabbitmqadmin') 33 | apply_manifest(pp, catch_failures: true) 34 | end 35 | 36 | describe file('/var/lib/rabbitmq/rabbitmqadmin') do 37 | it { is_expected.not_to be_file } 38 | end 39 | end 40 | 41 | context 'works with specified default credentials' do 42 | it 'runs successfully' do 43 | # make sure credential change takes effect before admin_enable 44 | pp_pre = <<-EOS 45 | class { 'rabbitmq': 46 | service_manage => true, 47 | default_user => 'foobar', 48 | default_pass => 'bazblam', 49 | } 50 | EOS 51 | 52 | pp = <<-EOS 53 | class { 'rabbitmq': 54 | admin_enable => true, 55 | service_manage => true, 56 | default_user => 'foobar', 57 | default_pass => 'bazblam', 58 | } 59 | EOS 60 | 61 | shell('rm -f /var/lib/rabbitmq/rabbitmqadmin') 62 | apply_manifest(pp_pre, catch_failures: true) 63 | apply_manifest(pp, catch_failures: true) 64 | end 65 | 66 | describe file('/var/lib/rabbitmq/rabbitmqadmin') do 67 | it { is_expected.to be_file } 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/acceptance/user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq user:' do 6 | context 'create user resource' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | service_manage => true, 11 | port => 5672, 12 | delete_guest_user => true, 13 | admin_enable => true, 14 | } -> 15 | 16 | rabbitmq_user { 'dan': 17 | admin => true, 18 | password => 'bar', 19 | } 20 | EOS 21 | 22 | apply_manifest(pp, catch_failures: true) 23 | apply_manifest(pp, catch_changes: true) 24 | end 25 | 26 | it 'has the user' do 27 | shell('rabbitmqctl list_users -q') do |r| 28 | expect(r.stdout).to match(%r{dan.*administrator}) 29 | expect(r.exit_code).to be_zero 30 | end 31 | end 32 | end 33 | 34 | context 'destroy user resource' do 35 | it 'runs successfully' do 36 | pp = <<-EOS 37 | rabbitmq_user { 'dan': 38 | ensure => absent, 39 | } 40 | EOS 41 | 42 | apply_manifest(pp, catch_failures: true) 43 | apply_manifest(pp, catch_changes: true) 44 | end 45 | 46 | it 'does not have the user' do 47 | shell('rabbitmqctl list_users -q') do |r| 48 | expect(r.stdout).not_to match(%r{dan\s+}) 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/acceptance/vhost_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'rabbitmq vhost:' do 6 | context 'create vhost resource' do 7 | it 'runs successfully' do 8 | pp = <<-EOS 9 | class { 'rabbitmq': 10 | service_manage => true, 11 | port => 5672, 12 | delete_guest_user => true, 13 | admin_enable => true, 14 | } 15 | 16 | -> rabbitmq_vhost { 'myhost': 17 | ensure => present, 18 | } 19 | EOS 20 | 21 | apply_manifest(pp, catch_failures: true) 22 | apply_manifest(pp, catch_changes: true) 23 | end 24 | 25 | it 'has the vhost' do 26 | shell('rabbitmqctl list_vhosts') do |r| 27 | expect(r.stdout).to match(%r{myhost}) 28 | expect(r.exit_code).to be_zero 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | # puppetlabs_spec_helper will set up coverage if the env variable is set. 7 | # We want to do this if lib exists and it hasn't been explicitly set. 8 | ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../lib', __dir__)) 9 | 10 | require 'voxpupuli/test/spec_helper' 11 | 12 | RSpec.configure do |c| 13 | c.facterdb_string_keys = true 14 | c.mock_with :mocha 15 | end 16 | 17 | add_mocked_facts! 18 | 19 | if File.exist?(File.join(__dir__, 'default_module_facts.yml')) 20 | facts = YAML.safe_load(File.read(File.join(__dir__, 'default_module_facts.yml'))) 21 | facts&.each do |name, value| 22 | add_custom_fact name.to_sym, value 23 | end 24 | end 25 | 26 | require 'spec_helper_local' 27 | Dir['./spec/support/spec/**/*.rb'].sort.each { |f| require f } 28 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'voxpupuli/acceptance/spec_helper_acceptance' 4 | 5 | configure_beaker do |host| 6 | case fact_on(host, 'os.family') 7 | when 'Debian' 8 | install_puppet_module_via_pmt_on(host, 'puppetlabs-apt', '>= 9.0.0 < 10.0.0') 9 | when 'RedHat' 10 | if fact_on(host, 'os.selinux.enabled') 11 | # Make sure selinux is disabled so the tests work. 12 | on host, puppet('resource', 'exec', 'setenforce 0', 'path=/bin:/sbin:/usr/bin:/usr/sbin', 'onlyif=which setenforce && getenforce | grep Enforcing') 13 | end 14 | end 15 | 16 | # Fake certs 17 | on host, 'echo "-----BEGIN RSA PRIVATE KEY----- 18 | MIICXAIBAAKBgQDw1uXI+EAgxk4dOxArPqMNnnCQqmXeQ61XQQXoAgWWjRvY4LAJ 19 | 4ALoACYWFlWVKQkLLQfQ2YYM3vNDG/eYfL2tjhp9APeJrJYJEcbmr5COURtuIh/Z 20 | fVKRgV5vtOMdlAHS0HFpk/DP1g520Da9wKwv2nDbfRui0y0ImPWz1uqK8wIDAQAB 21 | AoGBAJ/cNMgyJ/bZSk5SvwfFWtuWWGdeA6IF0BBDo9T9SpJE9b/+XDshyywNtToh 22 | 9wq8Izmc2TxCtpzifBwGe1FnM0qvioQhwQwJsGa4JJFzSkIt/MgPmojzutnP59RJ 23 | ozjCgAahX6xEkB6Kn/b2S6D7jgixyMTQ3FdPKq6lJVhXz6Q5AkEA+tSgg/xhrcTs 24 | 5W//hYZP/xjrE27xXzfkNrr/cAtVH5ZM2j2qqKFv3wEn9tAKrUvM+KNDhEjgLUSd 25 | MjvvH5DYZQJBAPXNjsg4AG09KqWbvcbB2Cgaf6RRTAe+Hx6A7aB01OQohc5uF0ws 26 | cPxZ8CE/KDbHtNSlx1MAvn8IOoitA06s5HcCQErP/mw/a3bjxHCOXh0aOWPxr7Ol 27 | JHLs/bFhRuzJRINeVd/GAs+3DuHpu1y/ImAbuq/yKiIbhlmaHHSuMZ0tm40CQHHi 28 | FzE0oR37pPKtwbOAxEFwZYsgD3XW5Fwhp/cbqjc7fyMxZqHoRUDl+pesx1j6FhIf 29 | 7MXMJnZ8vYHthwbAm+kCQHFH0HULyNcki4zEYSqiLaVMcbB7QybQmBBDA0mJR2HO 30 | KYdYDeFG3kfeBOReFM9jOt39OBS/nNP0GXFBJU2ahpQ= 31 | -----END RSA PRIVATE KEY-----" > /tmp/rabbitmq.key' 32 | on host, 'echo "-----BEGIN CERTIFICATE----- 33 | MIIEYTCCAkmgAwIBAgIQVAIiKvJ6YmTSszWEfassuDANBgkqhkiG9w0BAQUFADCB 34 | qjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFDASBgNVBAcMC0xv 35 | cyBBbmdlbGVzMRUwEwYDVQQKDAxBY21lIFdpZGdldHMxETAPBgNVBAsMCFNlY3Vy 36 | aXR5MR0wGwYDVQQDDBRyYWJiaXRtcS5leGFtcGxlLmNvbTEnMCUGCSqGSIb3DQEJ 37 | ARYYcm9nZXIucmFiYml0QGV4YW1wbGUuY29tMB4XDTE3MDkxMzAzMzExMloXDTI3 38 | MDkxMTAzMzExMlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEQMA4GA1UE 39 | BwwHQ2hpY2FnbzENMAsGA1UECgwEQWNtZTEQMA4GA1UECwwHV2lkZ2V0czEdMBsG 40 | A1UEAwwUcmFiYml0bXEuZXhhbXBsZS5jb20xJzAlBgkqhkiG9w0BCQEWGHJvZ2Vy 41 | LnJhYmJpdEBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA 42 | 8NblyPhAIMZOHTsQKz6jDZ5wkKpl3kOtV0EF6AIFlo0b2OCwCeAC6AAmFhZVlSkJ 43 | Cy0H0NmGDN7zQxv3mHy9rY4afQD3iayWCRHG5q+QjlEbbiIf2X1SkYFeb7TjHZQB 44 | 0tBxaZPwz9YOdtA2vcCsL9pw230botMtCJj1s9bqivMCAwEAAaMaMBgwCQYDVR0T 45 | BAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEFBQADggIBAIPXqHlxbo+BpBWz 46 | H+E7lFDYZkUQD8c34jybxZbwya7od/f9x5jU3F/+6g1Y7A8NAPPxbs+m3Sye0/sz 47 | WmEz+smKFseGVPWQJ6NgvYJjr8P/MpBUfA7zkkaKs2uuTbPx0tgU1+XGluC1hsZ+ 48 | KQCI0LIEGQlSuT3miPSYL6MPR9o/PTp6TPlYGbL+LLNQedriZRLuiUpOWJzsFyz/ 49 | CcdayANtlWxhuy50A9qUwAa5RzgIJnqfxk5OYuJHq7+p1oCKk+XhgHccHHq7t97M 50 | Ye/xC18NDTMKkAiggCad0+kYTUgUYnuwvYg4eRpQytsncp7Ck83JChb56eJKlsj1 51 | HnEkQDyi1B/cKxRKwG81fzkSgw7+0nFY6GAIaGz1GdYBkoxlzN9JNd3/MmS+xAtm 52 | HXtCqkTWUJQ5ZBinszauPtG4Inu6H28blstlqGjzKTzwo1w8N27shii14IhEHhEV 53 | tVRxA+ORIt14fZrl04AROsYLqJxqBHy8vJEX4OMm2JTzaO2KdPwEi2gmQK0SkfR8 54 | TCQc43SF2rqpYs3ZE4fPNlyQR3ZCUcYwjv99s6Nz0Ue4vD9+PuT0McE8NtMgiAMf 55 | DQqmYIMEiYNm15qKW6jJaY7VMUPGNohfEvubsWPlXPQ6/I7e9bNyk5OnA6OGi4qz 56 | M2Fcgn+pqLU7M+epynzgz4bsPsEw 57 | -----END CERTIFICATE-----" > /tmp/rabbitmq.crt' 58 | on host, 'echo "-----BEGIN CERTIFICATE----- 59 | MIIGKTCCBBGgAwIBAgIJAMCISMDHjBJpMA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD 60 | VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEUMBIGA1UEBwwLTG9zIEFuZ2Vs 61 | ZXMxFTATBgNVBAoMDEFjbWUgV2lkZ2V0czERMA8GA1UECwwIU2VjdXJpdHkxHTAb 62 | BgNVBAMMFHJhYmJpdG1xLmV4YW1wbGUuY29tMScwJQYJKoZIhvcNAQkBFhhyb2dl 63 | ci5yYWJiaXRAZXhhbXBsZS5jb20wHhcNMTcwOTEzMDMzMTAyWhcNMjcwOTExMDMz 64 | MTAyWjCBqjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFDASBgNV 65 | BAcMC0xvcyBBbmdlbGVzMRUwEwYDVQQKDAxBY21lIFdpZGdldHMxETAPBgNVBAsM 66 | CFNlY3VyaXR5MR0wGwYDVQQDDBRyYWJiaXRtcS5leGFtcGxlLmNvbTEnMCUGCSqG 67 | SIb3DQEJARYYcm9nZXIucmFiYml0QGV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0B 68 | AQEFAAOCAg8AMIICCgKCAgEA2WBjjypMwd4QU2m2K3ChuviDjY/4/c/cwcJBiM2l 69 | ibQdTO77is5Ub017/z+/Y9kZ4BMO86G97nkafG+mqyuWQj7kaOOAtaZ72Vz4Z2wl 70 | 3eij08OZO4rr3WvYP1VPqgM0FuGxA3iIuP1wl+IhaHLLH+HW5wsnl74pdBC+q7lv 71 | FKgd1xtCR0bWXVPbiYUi70rL2VA5j+Tp7gJy2XL0/tr3j+KSmqm6zKPrrl4xSLKW 72 | AZ0o8PFxO9eev5qxf9YYa8LGj7nNLpaqD77ituD27AYdQ4nIaRia4WXyJpyUQ6RS 73 | z87JsKZELZnQkd6EOXL5C/H0AZHz6KGbU7f4Zpxg0dj0vArunSxoMZRICfuGespi 74 | KGRCENL12HP7kAM+kdoWXcN5xd+NF+IJqoKORX/P9a8VNA3xn5EGMX/b+gcVOpB3 75 | 0H/gWMYI8M2rnFSDWw+1+qgJfV1meRM6+bj4Fab9mFxMPuqPCsd4YUQdSEOlV7L+ 76 | FpixpbOUEUIGSGCkE0tBdJ2zpStAnB3TsrjYhSU1GsevrdKEa5msfkHTDpZV/9EY 77 | AXo6WMWHWQe+joxnQzr9r8dlmdsyH0mN+cDxUmlQIwwvHqEtf7CVkN0cx7qKPhQ0 78 | vHX2NmlfmpgTf5LKnC4xrz8M8OsMfMV5efck0lLYuGKe4wFiBdCoTQvHRuCBncP+ 79 | npMCAwEAAaNQME4wHQYDVR0OBBYEFCkQ7/iSfDsHVL0UcA9vuEB5mqL5MB8GA1Ud 80 | IwQYMBaAFCkQ7/iSfDsHVL0UcA9vuEB5mqL5MAwGA1UdEwQFMAMBAf8wDQYJKoZI 81 | hvcNAQEFBQADggIBAEpHP9B7YbsykJ0mMDgXtUog7ZgY5qMf7YFnNrF7Gj0RRRsa 82 | O9oMSyQbOH6hEgr4b89Vval0ojKg0nWjP/KO73IRwb/eXewWV2THJaKW8Nj0T3mP 83 | Zai2OHEKIk33qBlAOMbgjL5GTwAbWuwPg8hQYySscOGblknQEdCLweRoCCU9m0dA 84 | EgQpemsELJoY0i2HkrAVK9+FCmxr0N4ApEckw/+KZxL/Yb0Sz3R3+0FM3JGkbdgi 85 | 2zP5xBEpJszHZqpwsxSwrLbnACrwv7xdxso/ojiW2MWPGqB/g3hHY9PexV732ZNK 86 | sRN2WJmRQ1G1RzKs8pi352hbra3WDmeEb0AQEuda6sqx6mu0EiomKN5JOq+pltyK 87 | PvQuBvJV04HwFqpTm7wAJprF1F+9y1B4PDt8c+/CnMBKMOJ9nv84qZEq2ihp65LK 88 | valeoetcimRCEJ5xnqGCza/sSDHjUMUvMhwMJdq56t0zKMk5pFH6lHxzgAKzX3Gt 89 | pct+50AzBHUSn0zpB6QRBow2MddivGmTs1IOFdWaSj+Mfdb6phln1Hkv+KW2Wizv 90 | I28L690yK+Bnk1ezGs+ln6yxiWOdnurckaLkTj6/JFw2x5q/uaTXOxjG/YKKpMQE 91 | Fq8uI2+DbX/zW18ZIEv6UloGEEWbLO1427+Yyb/THMczWYyH20PTyzT8zFOt 92 | -----END CERTIFICATE-----" > /tmp/cacert.crt' 93 | end 94 | 95 | shared_examples 'an idempotent resource' do 96 | it 'applies with no errors' do 97 | apply_manifest(pp, catch_failures: true) 98 | end 99 | 100 | it 'applies a second time without changes' do 101 | apply_manifest(pp, catch_changes: true) 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /spec/spec_helper_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | add_custom_fact :rabbitmq_version, '3.6.1' # puppet-rabbitmq 4 | add_custom_fact :erl_ssl_path, '/usr/lib64/erlang/lib/ssl-7.3.3.1/ebin' # puppet-rabbitmq 5 | -------------------------------------------------------------------------------- /spec/unit/facter/util/fact_erl_ssl_path_spec.rb: -------------------------------------------------------------------------------- 1 | # rubocop:disable Style/FrozenStringLiteralComment 2 | 3 | require 'spec_helper' 4 | 5 | describe Facter::Util::Fact do 6 | before { Facter.clear } 7 | 8 | describe 'erl_ssl_path' do 9 | context 'with valid value' do 10 | it do 11 | Facter::Util::Resolution.expects(:which).with('erl').returns(true) 12 | Facter::Core::Execution.expects(:execute).with("erl -eval 'io:format(\"~p\", [code:lib_dir(ssl, ebin)]),halt().' -noshell").returns('"/usr/lib64/erlang/lib/ssl-5.3.3/ebin"') 13 | expect(Facter.fact(:erl_ssl_path).value).to eq('/usr/lib64/erlang/lib/ssl-5.3.3/ebin') 14 | end 15 | end 16 | 17 | context 'with error message' do 18 | it do 19 | Facter::Util::Resolution.expects(:which).with('erl').returns(true) 20 | Facter::Core::Execution.expects(:execute).with("erl -eval 'io:format(\"~p\", [code:lib_dir(ssl, ebin)]),halt().' -noshell").returns('{error,bad_name}') 21 | expect(Facter.fact(:erl_ssl_path).value).to be_nil 22 | end 23 | end 24 | 25 | context 'with erl not present' do 26 | it do 27 | Facter::Util::Resolution.expects(:which).with('erl').returns(false) 28 | expect(Facter.fact(:erl_ssl_path).value).to be_nil 29 | end 30 | end 31 | end 32 | end 33 | 34 | # rubocop:enable Style/FrozenStringLiteralComment 35 | -------------------------------------------------------------------------------- /spec/unit/facter/util/fact_rabbitmq_clustername_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Facter::Util::Fact do 6 | before do 7 | Facter.clear 8 | end 9 | 10 | describe 'rabbitmq_clusternam' do 11 | context 'with value' do 12 | it do 13 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 14 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl -q cluster_status 2>&1').returns(' {cluster_name,<<"monty">>},') 15 | expect(Facter.fact(:rabbitmq_clustername).value).to eq('monty') 16 | end 17 | end 18 | 19 | context 'with dashes in hostname' do 20 | it do 21 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 22 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl -q cluster_status 2>&1').returns('Cluster name: rabbit-1') 23 | expect(Facter.fact(:rabbitmq_clustername).value).to eq('rabbit-1') 24 | end 25 | end 26 | 27 | context 'with dashes in clustername/hostname' do 28 | it do 29 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 30 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl -q cluster_status 2>&1').returns(' {cluster_name,<<"monty-python@rabbit-1">>},') 31 | expect(Facter.fact(:rabbitmq_clustername).value).to eq('monty-python@rabbit-1') 32 | end 33 | end 34 | 35 | context 'with quotes around node name' do 36 | it do 37 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 38 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl -q cluster_status 2>&1').returns("monty\npython\nCluster name: 'monty@rabbit-1'\nend\nof\nfile") 39 | expect(Facter.fact(:rabbitmq_clustername).value).to eq("'monty@rabbit-1'") 40 | end 41 | end 42 | 43 | context 'rabbitmq is not running' do 44 | it do 45 | error_string = <<~EOS 46 | Status of node 'monty@rabbit-1' ... 47 | Error: unable to connect to node 'monty@rabbit-1': nodedown 48 | 49 | DIAGNOSTICS 50 | =========== 51 | 52 | attempted to contact: ['monty@rabbit-1'] 53 | 54 | monty@rabbit-1: 55 | * connected to epmd (port 4369) on centos-7-x64 56 | * epmd reports: node 'rabbit' not running at all 57 | no other nodes on centos-7-x64 58 | * suggestion: start the node 59 | 60 | current node details: 61 | - node name: 'rabbitmq-cli-73@centos-7-x64' 62 | - home dir: /var/lib/rabbitmq 63 | - cookie hash: 6WdP0nl6d3HYqA5vTKMkIg== 64 | 65 | EOS 66 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 67 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl -q cluster_status 2>&1').returns(error_string) 68 | expect(Facter.fact(:rabbitmq_clustername).value).to be_nil 69 | end 70 | end 71 | 72 | context 'rabbitmqctl is not in path' do 73 | it do 74 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(false) 75 | expect(Facter.fact(:rabbitmq_clustername).value).to be_nil 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /spec/unit/facter/util/fact_rabbitmq_nodename_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Facter::Util::Fact do 6 | before { Facter.clear } 7 | 8 | describe 'rabbitmq_nodename' do 9 | context 'with value' do 10 | it do 11 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 12 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl status 2>&1').returns('Status of node monty@rabbit1 ...') 13 | expect(Facter.fact(:rabbitmq_nodename).value).to eq('monty@rabbit1') 14 | end 15 | end 16 | 17 | context 'with dashes in hostname' do 18 | it do 19 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 20 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl status 2>&1').returns('Status of node monty@rabbit-1 ...') 21 | expect(Facter.fact(:rabbitmq_nodename).value).to eq('monty@rabbit-1') 22 | end 23 | end 24 | 25 | context 'with dashes in nodename/hostname' do 26 | it do 27 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 28 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl status 2>&1').returns('Status of node monty-python@rabbit-1 ...') 29 | expect(Facter.fact(:rabbitmq_nodename).value).to eq('monty-python@rabbit-1') 30 | end 31 | end 32 | 33 | context 'with quotes around node name' do 34 | it do 35 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 36 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl status 2>&1').returns('Status of node \'monty@rabbit-1\' ...') 37 | expect(Facter.fact(:rabbitmq_nodename).value).to eq('monty@rabbit-1') 38 | end 39 | end 40 | 41 | context 'without trailing points' do 42 | it do 43 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 44 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl status 2>&1').returns('Status of node monty@rabbit-1') 45 | expect(Facter.fact(:rabbitmq_nodename).value).to eq('monty@rabbit-1') 46 | end 47 | end 48 | 49 | context 'rabbitmq is not running' do 50 | it do 51 | error_string = <<~EOS 52 | Status of node 'monty@rabbit-1' ... 53 | Error: unable to connect to node 'monty@rabbit-1': nodedown 54 | 55 | DIAGNOSTICS 56 | =========== 57 | 58 | attempted to contact: ['monty@rabbit-1'] 59 | 60 | monty@rabbit-1: 61 | * connected to epmd (port 4369) on centos-7-x64 62 | * epmd reports: node 'rabbit' not running at all 63 | no other nodes on centos-7-x64 64 | * suggestion: start the node 65 | 66 | current node details: 67 | - node name: 'rabbitmq-cli-73@centos-7-x64' 68 | - home dir: /var/lib/rabbitmq 69 | - cookie hash: 6WdP0nl6d3HYqA5vTKMkIg== 70 | 71 | EOS 72 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 73 | Facter::Core::Execution.expects(:execute).with('rabbitmqctl status 2>&1').returns(error_string) 74 | expect(Facter.fact(:rabbitmq_nodename).value).to eq('monty@rabbit-1') 75 | end 76 | end 77 | 78 | context 'rabbitmqctl is not in path' do 79 | it do 80 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(false) 81 | expect(Facter.fact(:rabbitmq_nodename).value).to be_nil 82 | end 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/unit/facter/util/fact_rabbitmq_plugins_dirs_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Facter::Util::Fact do 6 | before { Facter.clear } 7 | 8 | describe 'rabbitmq_plugins_dirs' do 9 | context 'with multiple plugins dirs' do 10 | it do 11 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 12 | Facter::Core::Execution.expects(:execute).with("rabbitmqctl eval 'application:get_env(rabbit, plugins_dir).'").returns('{ok,"/usr/lib/rabbitmq/plugins:/usr/lib/rabbitmq/lib/rabbitmq_server-3.7.10/plugins"}') 13 | expect(Facter.fact(:rabbitmq_plugins_dirs).value).to contain_exactly('/usr/lib/rabbitmq/plugins', '/usr/lib/rabbitmq/lib/rabbitmq_server-3.7.10/plugins') 14 | end 15 | end 16 | 17 | context 'with only 1 plugins dir' do 18 | it do 19 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(true) 20 | Facter::Core::Execution.expects(:execute).with("rabbitmqctl eval 'application:get_env(rabbit, plugins_dir).'").returns('{ok,"/usr/lib/rabbitmq/lib/rabbitmq_server-0.0.0/plugins"}') 21 | expect(Facter.fact(:rabbitmq_plugins_dirs).value).to contain_exactly('/usr/lib/rabbitmq/lib/rabbitmq_server-0.0.0/plugins') 22 | end 23 | end 24 | 25 | context 'rabbitmqctl is not in path' do 26 | it do 27 | Facter::Util::Resolution.expects(:which).with('rabbitmqctl').returns(false) 28 | expect(Facter.fact(:rabbitmq_plugins_dirs).value).to be_nil 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/unit/facter/util/fact_rabbitmq_version_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Facter::Util::Fact do 6 | before do 7 | Facter.clear 8 | end 9 | 10 | describe 'rabbitmq_version' do 11 | context 'with value' do 12 | it do 13 | Facter::Util::Resolution.expects(:which).with('rabbitmqadmin').returns(true) 14 | Facter::Core::Execution.expects(:execute).with('rabbitmqadmin --version 2>&1').returns('rabbitmqadmin 3.6.0') 15 | expect(Facter.fact(:rabbitmq_version).value).to eq('3.6.0') 16 | end 17 | end 18 | 19 | context 'with invalid value' do 20 | it do 21 | Facter::Util::Resolution.expects(:which).with('rabbitmqadmin').returns(true) 22 | Facter::Core::Execution.expects(:execute).with('rabbitmqadmin --version 2>&1').returns('rabbitmqadmin %%VSN%%') 23 | expect(Facter.fact(:rabbitmq_version).value).to be_nil 24 | end 25 | end 26 | 27 | context 'rabbitmqadmin is not in path' do 28 | it do 29 | Facter::Util::Resolution.expects(:which).with('rabbitmqadmin').returns(false) 30 | expect(Facter.fact(:rabbitmq_version).value).to be_nil 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_binding/rabbitmqadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_binding).provider(:rabbitmqadmin) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type::Rabbitmq_binding.new( 9 | name: 'source@target@/', 10 | destination_type: :queue, 11 | routing_key: 'blablub', 12 | arguments: {} 13 | ) 14 | end 15 | let(:provider) { provider_class.new(resource) } 16 | 17 | describe '#instances' do 18 | it 'returns instances' do 19 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 20 | / 21 | EOT 22 | provider_class.expects(:rabbitmqctl_list).with( 23 | 'bindings', '-p', '/', 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments' 24 | ).returns <<~EOT 25 | exchange\tdst_queue\tqueue\t*\t[] 26 | EOT 27 | instances = provider_class.instances 28 | expect(instances.size).to eq(1) 29 | expect(instances.map do |prov| 30 | { 31 | source: prov.get(:source), 32 | destination: prov.get(:destination), 33 | vhost: prov.get(:vhost), 34 | routing_key: prov.get(:routing_key) 35 | } 36 | end).to eq([ 37 | { 38 | source: 'exchange', 39 | destination: 'dst_queue', 40 | vhost: '/', 41 | routing_key: '*' 42 | } 43 | ]) 44 | end 45 | 46 | it 'returns multiple instances' do 47 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 48 | / 49 | EOT 50 | provider_class.expects(:rabbitmqctl_list).with( 51 | 'bindings', '-p', '/', 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments' 52 | ).returns <<~EOT 53 | exchange\tdst_queue\tqueue\trouting_one\t[] 54 | exchange\tdst_queue\tqueue\trouting_two\t[] 55 | EOT 56 | instances = provider_class.instances 57 | expect(instances.size).to eq(2) 58 | expect(instances.map do |prov| 59 | { 60 | source: prov.get(:source), 61 | destination: prov.get(:destination), 62 | vhost: prov.get(:vhost), 63 | routing_key: prov.get(:routing_key) 64 | } 65 | end).to eq([ 66 | { 67 | source: 'exchange', 68 | destination: 'dst_queue', 69 | vhost: '/', 70 | routing_key: 'routing_one' 71 | }, 72 | { 73 | source: 'exchange', 74 | destination: 'dst_queue', 75 | vhost: '/', 76 | routing_key: 'routing_two' 77 | } 78 | ]) 79 | end 80 | end 81 | 82 | describe 'Test for prefetch error' do 83 | let(:resource) do 84 | Puppet::Type::Rabbitmq_binding.new( 85 | name: 'binding1', 86 | source: 'exchange1', 87 | destination: 'destqueue', 88 | destination_type: :queue, 89 | routing_key: 'blablubd', 90 | arguments: {} 91 | ) 92 | end 93 | 94 | it 'exists' do 95 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 96 | / 97 | EOT 98 | provider_class.expects(:rabbitmqctl_list).with( 99 | 'bindings', '-p', '/', 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments' 100 | ).returns <<~EOT 101 | exchange\tdst_queue\tqueue\t*\t[] 102 | EOT 103 | 104 | provider_class.prefetch({}) 105 | end 106 | 107 | it 'matches' do 108 | # Test resource to match against 109 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 110 | / 111 | EOT 112 | provider_class.expects(:rabbitmqctl_list).with( 113 | 'bindings', '-p', '/', 'source_name', 'destination_name', 'destination_kind', 'routing_key', 'arguments' 114 | ).returns <<~EOT 115 | exchange\tdst_queue\tqueue\t*\t[] 116 | EOT 117 | 118 | provider_class.prefetch('binding1' => resource) 119 | end 120 | end 121 | 122 | describe '#create' do 123 | it 'calls rabbitmqadmin to create' do 124 | provider.expects(:rabbitmqadmin).with( 125 | 'declare', 'binding', '--vhost=/', '--user=guest', '--password=guest', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 126 | 'source=source', 'destination=target', 'arguments={}', 'routing_key=blablub', 'destination_type=queue' 127 | ) 128 | provider.create 129 | end 130 | 131 | context 'specifying credentials' do 132 | let(:resource) do 133 | Puppet::Type::Rabbitmq_binding.new( 134 | name: 'source@test2@/', 135 | destination_type: :queue, 136 | routing_key: 'blablubd', 137 | arguments: {}, 138 | user: 'colin', 139 | password: 'secret' 140 | ) 141 | end 142 | let(:provider) { provider_class.new(resource) } 143 | 144 | it 'calls rabbitmqadmin to create' do 145 | provider.expects(:rabbitmqadmin).with( 146 | 'declare', 'binding', '--vhost=/', '--user=colin', '--password=secret', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 147 | 'source=source', 'destination=test2', 'arguments={}', 'routing_key=blablubd', 'destination_type=queue' 148 | ) 149 | provider.create 150 | end 151 | end 152 | 153 | context 'new queue_bindings' do 154 | let(:resource) do 155 | Puppet::Type::Rabbitmq_binding.new( 156 | name: 'binding1', 157 | source: 'exchange1', 158 | destination: 'destqueue', 159 | destination_type: :queue, 160 | routing_key: 'blablubd', 161 | arguments: {} 162 | ) 163 | end 164 | let(:provider) { provider_class.new(resource) } 165 | 166 | it 'calls rabbitmqadmin to create' do 167 | provider.expects(:rabbitmqadmin).with( 168 | 'declare', 'binding', '--vhost=/', '--user=guest', '--password=guest', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 169 | 'source=exchange1', 'destination=destqueue', 'arguments={}', 'routing_key=blablubd', 'destination_type=queue' 170 | ) 171 | provider.create 172 | end 173 | end 174 | end 175 | 176 | describe '#destroy' do 177 | it 'calls rabbitmqadmin to destroy' do 178 | provider.expects(:rabbitmqadmin).with( 179 | 'delete', 'binding', '--vhost=/', '--user=guest', '--password=guest', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 180 | 'source=source', 'destination_type=queue', 'destination=target', 'properties_key=blablub' 181 | ) 182 | provider.destroy 183 | end 184 | end 185 | end 186 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_cli_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | require 'puppet/provider/rabbitmq_cli' 6 | 7 | provider_class = Puppet::Provider::RabbitmqCli 8 | describe provider_class do 9 | before do 10 | # Clear the cached version before each test 11 | provider_class.remove_instance_variable(:@rabbitmq_version) \ 12 | if provider_class.instance_variable_defined?(:@rabbitmq_version) 13 | end 14 | 15 | it 'gets the RabbitMQ version' do 16 | provider_class.expects(:rabbitmqctl).with('-q', 'status').returns ' [{rabbit,"RabbitMQ","3.7.28"},' 17 | expect(provider_class.rabbitmq_version).to eq('3.7.28') 18 | end 19 | 20 | it 'caches the RabbitMQ version' do 21 | provider_class.expects(:rabbitmqctl).with('-q', 'status').returns ' [{rabbit,"RabbitMQ","3.7.28"},' 22 | v1 = provider_class.rabbitmq_version 23 | 24 | # No second expects for rabbitmqctl as it shouldn't be called again 25 | expect(provider_class.rabbitmq_version).to eq(v1) 26 | end 27 | 28 | it 'gets the RabbitMQ version with version >= 3.8' do 29 | provider_class.expects(:rabbitmqctl).with('-q', 'status').returns 'RabbitMQ version: 3.10.6' 30 | expect(provider_class.rabbitmq_version).to eq('3.10.6') 31 | end 32 | 33 | it 'uses correct list options with RabbitMQ < 3.7.9' do 34 | provider_class.expects(:rabbitmq_version).returns '3.7.8' 35 | provider_class.expects(:rabbitmqctl).with('list_vhost', '-q').returns '' 36 | expect(provider_class.rabbitmqctl_list('vhost')).to eq('') 37 | end 38 | 39 | it 'uses correct list options with RabbitMQ >= 3.7.9' do 40 | provider_class.expects(:rabbitmq_version).returns '3.7.10' 41 | provider_class.expects(:rabbitmqctl).with('list_vhost', '-q', '--no-table-headers').returns '' 42 | expect(provider_class.rabbitmqctl_list('vhost')).to eq('') 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_cluster/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_cluster).provider(:rabbitmqctl) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type::Rabbitmq_cluster.new( 9 | name: 'test_cluster', 10 | init_node: 'host1' 11 | ) 12 | end 13 | let(:provider) { provider_class.new(resource) } 14 | 15 | describe '#exists?' do 16 | it { 17 | provider.expects(:rabbitmqctl).with('-q', 'cluster_status').returns( 18 | 'Cluster name: test_cluster' 19 | ) 20 | expect(provider.exists?).to be true 21 | } 22 | end 23 | 24 | describe '#create on every other node' do 25 | it 'joins a cluster or changes the cluster name' do 26 | provider.expects(:rabbitmqctl).with('stop_app') 27 | provider.expects(:rabbitmqctl).with('join_cluster', 'rabbit@host1', '--disc') 28 | provider.expects(:rabbitmqctl).with('start_app') 29 | provider.create 30 | end 31 | end 32 | 33 | describe '#destroy' do 34 | it 'remove cluster setup' do 35 | provider.expects(:rabbitmqctl).with('stop_app') 36 | provider.expects(:rabbitmqctl).with('reset') 37 | provider.expects(:rabbitmqctl).with('start_app') 38 | provider.destroy 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_exchange/rabbitmqadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_exchange).provider(:rabbitmqadmin) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type::Rabbitmq_exchange.new( 9 | name: 'test.headers@/', 10 | type: :headers, 11 | internal: :false, 12 | durable: :true, 13 | auto_delete: :false, 14 | arguments: { 15 | 'hash-headers' => 'message-distribution-hash' 16 | } 17 | ) 18 | end 19 | let(:provider) { provider_class.new(resource) } 20 | 21 | it 'returns instances' do 22 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 23 | / 24 | EOT 25 | provider_class.expects(:rabbitmqctl_list).with('exchanges', '-p', '/', 'name', 'type', 'internal', 'durable', 'auto_delete', 'arguments').returns <<~EOT 26 | direct false true false [] 27 | amq.direct direct false true false [] 28 | amq.fanout fanout false true false [] 29 | amq.headers headers false true false [] 30 | amq.match headers false true false [] 31 | amq.rabbitmq.log topic true true false [] 32 | amq.rabbitmq.trace topic true true false [] 33 | amq.topic topic false true false [] 34 | test.headers x-consistent-hash false true false [{"hash-header","message-distribution-hash"}] 35 | EOT 36 | instances = provider_class.instances 37 | expect(instances.size).to eq(9) 38 | end 39 | 40 | it 'calls rabbitmqadmin to create as guest' do 41 | provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=test.headers', 'type=headers', 'internal=false', 'durable=true', 'auto_delete=false', 'arguments={"hash-headers":"message-distribution-hash"}', '-c', '/etc/rabbitmq/rabbitmqadmin.conf') 42 | provider.create 43 | end 44 | 45 | it 'calls rabbitmqadmin to destroy' do 46 | provider.expects(:rabbitmqadmin).with('delete', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=test.headers', '-c', '/etc/rabbitmq/rabbitmqadmin.conf') 47 | provider.destroy 48 | end 49 | 50 | context 'specifying credentials' do 51 | let(:resource) do 52 | Puppet::Type::Rabbitmq_exchange.new( 53 | name: 'test.headers@/', 54 | type: :headers, 55 | internal: 'false', 56 | durable: 'true', 57 | auto_delete: 'false', 58 | user: 'colin', 59 | password: 'secret', 60 | arguments: { 61 | 'hash-header' => 'message-distribution-hash' 62 | } 63 | ) 64 | end 65 | let(:provider) { provider_class.new(resource) } 66 | 67 | it 'calls rabbitmqadmin to create with credentials' do 68 | provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=colin', '--password=secret', 'name=test.headers', 'type=headers', 'internal=false', 'durable=true', 'auto_delete=false', 'arguments={"hash-header":"message-distribution-hash"}', '-c', '/etc/rabbitmq/rabbitmqadmin.conf') 69 | provider.create 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_parameter/rabbitmqctl_federation_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_parameter).provider(:rabbitmqctl) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type.type(:rabbitmq_parameter).new( 9 | name: 'documentumFederation@/', 10 | component_name: 'federation', 11 | value: { 12 | 'uri' => 'amqp://', 13 | 'expires' => '360000' 14 | } 15 | ) 16 | end 17 | let(:provider) { provider_class.new(resource) } 18 | 19 | after do 20 | described_class.instance_variable_set(:@parameters, nil) 21 | end 22 | 23 | describe '#prefetch' do 24 | it 'exists' do 25 | expect(described_class).to respond_to :prefetch 26 | end 27 | 28 | it 'matches' do 29 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 30 | / 31 | EOT 32 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns <<~EOT 33 | federation documentumFederation {"uri":"amqp://","expires":360000} 34 | EOT 35 | provider_class.prefetch('documentumFederation@/' => resource) 36 | end 37 | end 38 | 39 | describe '#instances' do 40 | it 'exists' do 41 | expect(described_class).to respond_to :instances 42 | end 43 | 44 | it 'fail with invalid output from list' do 45 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 46 | / 47 | EOT 48 | provider.class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns 'foobar' 49 | expect { provider_class.instances }.to raise_error Puppet::Error, %r{cannot parse line from list_parameter} 50 | end 51 | 52 | it 'return no instance' do 53 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 54 | / 55 | EOT 56 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns '' 57 | instances = provider_class.instances 58 | expect(instances.size).to eq(0) 59 | end 60 | end 61 | 62 | describe '#create' do 63 | it 'create parameter' do 64 | provider.expects(:rabbitmqctl).with('set_parameter', '-p', '/', 'federation', 'documentumFederation', 65 | '{"uri":"amqp://","expires":360000}') 66 | provider.create 67 | end 68 | end 69 | 70 | describe '#destroy' do 71 | it 'destroy parameter' do 72 | provider.expects(:rabbitmqctl).with('clear_parameter', '-p', '/', 'federation', 'documentumFederation') 73 | provider.destroy 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_parameter/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_parameter).provider(:rabbitmqctl) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type.type(:rabbitmq_parameter).new( 9 | name: 'documentumShovel@/', 10 | component_name: 'shovel', 11 | value: { 12 | 'src-uri' => 'amqp://', 13 | 'src-queue' => 'my-queue', 14 | 'dest-uri' => 'amqp://remote-server', 15 | 'dest-queue' => 'another-queue' 16 | } 17 | ) 18 | end 19 | let(:provider) { provider_class.new(resource) } 20 | 21 | after do 22 | described_class.instance_variable_set(:@parameters, nil) 23 | end 24 | 25 | describe '#prefetch' do 26 | it 'exists' do 27 | expect(described_class).to respond_to :prefetch 28 | end 29 | 30 | it 'matches' do 31 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 32 | / 33 | EOT 34 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns <<~EOT 35 | shovel documentumShovel {"src-uri":"amqp://","src-queue":"my-queue","dest-uri":"amqp://remote-server","dest-queue":"another-queue"} 36 | EOT 37 | provider_class.prefetch('documentumShovel@/' => resource) 38 | end 39 | end 40 | 41 | describe '#instances' do 42 | it 'exists' do 43 | expect(described_class).to respond_to :instances 44 | end 45 | 46 | it 'fail with invalid output from list' do 47 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 48 | / 49 | EOT 50 | provider.class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns 'foobar' 51 | expect { provider_class.instances }.to raise_error Puppet::Error, %r{cannot parse line from list_parameter} 52 | end 53 | 54 | it 'return no instance' do 55 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 56 | / 57 | EOT 58 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns '' 59 | instances = provider_class.instances 60 | expect(instances.size).to eq(0) 61 | end 62 | 63 | it 'return one instance' do 64 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 65 | / 66 | EOT 67 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns <<~EOT 68 | shovel documentumShovel {"src-uri":"amqp://","src-queue":"my-queue","dest-uri":"amqp://remote-server","dest-queue":"another-queue"} 69 | EOT 70 | instances = provider_class.instances 71 | expect(instances.size).to eq(1) 72 | expect(instances.map do |prov| 73 | { 74 | name: prov.get(:name), 75 | component_name: prov.get(:component_name), 76 | value: prov.get(:value) 77 | } 78 | end).to eq( 79 | [ 80 | { 81 | name: 'documentumShovel@/', 82 | component_name: 'shovel', 83 | value: { 84 | 'src-uri' => 'amqp://', 85 | 'src-queue' => 'my-queue', 86 | 'dest-uri' => 'amqp://remote-server', 87 | 'dest-queue' => 'another-queue' 88 | } 89 | } 90 | ] 91 | ) 92 | end 93 | 94 | it 'return multiple instances' do 95 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 96 | / 97 | EOT 98 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns <<~EOT 99 | shovel documentumShovel1 {"src-uri":"amqp://","src-queue":"my-queue","dest-uri":"amqp://remote-server","dest-queue":"another-queue"} 100 | shovel documentumShovel2 {"src-uri":["amqp://cl1","amqp://cl2"],"src-queue":"my-queue","dest-uri":"amqp://remote-server","dest-queue":"another-queue"} 101 | EOT 102 | instances = provider_class.instances 103 | expect(instances.size).to eq(2) 104 | expect(instances.map do |prov| 105 | { 106 | name: prov.get(:name), 107 | component_name: prov.get(:component_name), 108 | value: prov.get(:value) 109 | } 110 | end).to eq( 111 | [ 112 | { 113 | name: 'documentumShovel1@/', 114 | component_name: 'shovel', 115 | value: { 116 | 'src-uri' => 'amqp://', 117 | 'src-queue' => 'my-queue', 118 | 'dest-uri' => 'amqp://remote-server', 119 | 'dest-queue' => 'another-queue' 120 | } 121 | }, 122 | { 123 | name: 'documentumShovel2@/', 124 | component_name: 'shovel', 125 | value: { 126 | 'src-uri' => ['amqp://cl1', 'amqp://cl2'], 127 | 'src-queue' => 'my-queue', 128 | 'dest-uri' => 'amqp://remote-server', 129 | 'dest-queue' => 'another-queue' 130 | } 131 | } 132 | ] 133 | ) 134 | end 135 | 136 | it 'return different instances' do 137 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 138 | / 139 | EOT 140 | provider_class.expects(:rabbitmqctl_list).with('parameters', '-p', '/').returns <<~EOT 141 | shovel documentumShovel1 {"src-uri":"amqp://","src-queue":"my-queue","dest-uri":"amqp://remote-server","dest-queue":"another-queue"} 142 | federation documentumFederation2 {"uri":"amqp://","expires":"360000"} 143 | EOT 144 | instances = provider_class.instances 145 | expect(instances.size).to eq(2) 146 | expect(instances.map do |prov| 147 | { 148 | name: prov.get(:name), 149 | component_name: prov.get(:component_name), 150 | value: prov.get(:value) 151 | } 152 | end).to eq( 153 | [ 154 | { 155 | name: 'documentumShovel1@/', 156 | component_name: 'shovel', 157 | value: { 158 | 'src-uri' => 'amqp://', 159 | 'src-queue' => 'my-queue', 160 | 'dest-uri' => 'amqp://remote-server', 161 | 'dest-queue' => 'another-queue' 162 | } 163 | }, 164 | { 165 | name: 'documentumFederation2@/', 166 | component_name: 'federation', 167 | value: { 168 | 'uri' => 'amqp://', 169 | 'expires' => '360000' 170 | } 171 | } 172 | ] 173 | ) 174 | end 175 | end 176 | 177 | describe '#create' do 178 | it 'create parameter' do 179 | provider.expects(:rabbitmqctl).with('set_parameter', '-p', '/', 'shovel', 'documentumShovel', 180 | '{"src-uri":"amqp://","src-queue":"my-queue","dest-uri":"amqp://remote-server","dest-queue":"another-queue"}') 181 | provider.create 182 | end 183 | end 184 | 185 | describe '#destroy' do 186 | it 'destroy parameter' do 187 | provider.expects(:rabbitmqctl).with('clear_parameter', '-p', '/', 'shovel', 'documentumShovel') 188 | provider.destroy 189 | end 190 | end 191 | end 192 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_plugin/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_plugin).provider(:rabbitmqplugins) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type::Rabbitmq_plugin.new( 9 | name: 'foo' 10 | ) 11 | end 12 | let(:provider) { provider_class.new(resource) } 13 | 14 | it 'calls rabbitmqplugins to enable when node not running' do 15 | provider.class.expects(:rabbitmq_running).returns false 16 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 17 | provider.create 18 | end 19 | 20 | describe '#instances' do 21 | it 'exists' do 22 | expect(provider_class).to respond_to :instances 23 | end 24 | 25 | it 'retrieves instances' do 26 | provider.class.expects(:plugin_list).returns(%w[foo bar]) 27 | instances = provider_class.instances 28 | instances_cmp = instances.map { |prov| { name: prov.get(:name) } } 29 | expect(instances_cmp).to eq( 30 | [ 31 | { name: 'foo' }, 32 | { name: 'bar' } 33 | ] 34 | ) 35 | end 36 | 37 | it 'raises error on invalid line' do 38 | provider_class.expects(:plugin_list).returns([' ']) 39 | expect { provider_class.instances }.to raise_error Puppet::Error, %r{Cannot parse invalid plugins line} 40 | end 41 | end 42 | 43 | describe '#plugin_list' do 44 | it 'exists' do 45 | expect(provider_class).to respond_to :instances 46 | end 47 | 48 | it 'returns a list of plugins' do 49 | provider.class.expects(:rabbitmqplugins).with('list', '-e', '-m').returns("foo\nbar\nbaz\n") 50 | expect(provider.class.plugin_list).to eq(%w[foo bar baz]) 51 | end 52 | 53 | it 'handles no training newline properly' do 54 | provider.class.expects(:rabbitmqplugins).with('list', '-e', '-m').returns("foo\nbar") 55 | expect(provider.class.plugin_list).to eq(%w[foo bar]) 56 | end 57 | 58 | it 'handles lines that are not plugins' do 59 | provider.class.expects(:rabbitmqplugins).with('list', '-e', '-m').returns("Listing plugins with pattern \".*\" ...\nfoo\nbar") 60 | expect(provider.class.plugin_list).to eq(%w[foo bar]) 61 | end 62 | end 63 | 64 | describe '#exists?' do 65 | it 'matches existing plugins' do 66 | provider_class.expects(:plugin_list).returns(%w[foo]) 67 | expect(provider.exists?).to eq(true) 68 | end 69 | 70 | it 'returns false for missing plugins' do 71 | provider_class.expects(:plugin_list).returns(%w[bar]) 72 | expect(provider.exists?).to eq(false) 73 | end 74 | end 75 | 76 | context 'with RabbitMQ version >=3.4.0' do 77 | it 'calls rabbitmqplugins to enable' do 78 | provider.class.expects(:rabbitmq_version).returns '3.4.0' 79 | provider.class.expects(:rabbitmq_running).returns true 80 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 81 | provider.create 82 | end 83 | 84 | it 'calls rabbitmqplugins to enable with offline' do 85 | provider.resource[:mode] = :offline 86 | provider.class.expects(:rabbitmq_version).returns '3.4.0' 87 | provider.class.expects(:rabbitmq_running).returns true 88 | provider.expects(:rabbitmqplugins).with('enable', 'foo', '--offline') 89 | provider.create 90 | end 91 | 92 | it 'calls rabbitmqplugins to enable with online' do 93 | provider.resource[:mode] = :online 94 | provider.class.expects(:rabbitmq_version).returns '3.4.0' 95 | provider.class.expects(:rabbitmq_running).returns true 96 | provider.expects(:rabbitmqplugins).with('enable', 'foo', '--online') 97 | provider.create 98 | end 99 | 100 | it 'calls rabbitmqplugins to enable with best' do 101 | provider.resource[:mode] = :best 102 | provider.class.expects(:rabbitmq_version).returns '3.4.0' 103 | provider.class.expects(:rabbitmq_running).returns true 104 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 105 | provider.create 106 | end 107 | end 108 | 109 | context 'with RabbitMQ version < 3.4.0' do 110 | it 'calls rabbitmqplugins to enable' do 111 | provider.class.expects(:rabbitmq_version).returns '3.3.9' 112 | provider.class.expects(:rabbitmq_running).returns true 113 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 114 | provider.create 115 | end 116 | 117 | it 'calls rabbitmqplugins to enable with offline' do 118 | provider.resource[:mode] = :offline 119 | provider.class.expects(:rabbitmq_version).returns '3.3.9' 120 | provider.class.expects(:rabbitmq_running).returns true 121 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 122 | provider.create 123 | end 124 | 125 | it 'calls rabbitmqplugins to enable with online' do 126 | provider.resource[:mode] = :online 127 | provider.class.expects(:rabbitmq_version).returns '3.3.9' 128 | provider.class.expects(:rabbitmq_running).returns true 129 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 130 | provider.create 131 | end 132 | 133 | it 'calls rabbitmqplugins to enable with best' do 134 | provider.resource[:mode] = :best 135 | provider.class.expects(:rabbitmq_version).returns '3.3.9' 136 | provider.class.expects(:rabbitmq_running).returns true 137 | provider.expects(:rabbitmqplugins).with('enable', 'foo') 138 | provider.create 139 | end 140 | end 141 | 142 | it 'calls rabbitmqplugins to disable' do 143 | provider.expects(:rabbitmqplugins).with('disable', 'foo') 144 | provider.destroy 145 | end 146 | end 147 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_policy/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Puppet::Type.type(:rabbitmq_policy).provider(:rabbitmqctl) do 6 | let(:resource) do 7 | Puppet::Type.type(:rabbitmq_policy).new( 8 | name: 'ha-all@/', 9 | pattern: '.*', 10 | definition: { 11 | 'ha-mode' => 'all' 12 | } 13 | ) 14 | end 15 | let(:provider) { described_class.new(resource) } 16 | 17 | after do 18 | described_class.instance_variable_set(:@policies, nil) 19 | end 20 | 21 | context 'has "@" in policy name' do 22 | let(:resource) do 23 | Puppet::Type.type(:rabbitmq_policy).new( 24 | name: 'ha@home@/', 25 | pattern: '.*', 26 | definition: { 27 | 'ha-mode' => 'all' 28 | }, 29 | provider: described_class.name 30 | ) 31 | end 32 | let(:provider) { described_class.new(resource) } 33 | 34 | it do 35 | expect(provider.should_policy).to eq('ha@home') 36 | end 37 | 38 | it do 39 | expect(provider.should_vhost).to eq('/') 40 | end 41 | end 42 | 43 | it 'fails with invalid output from list' do 44 | provider.class.expects(:rabbitmqctl_list).with('policies', '-p', '/').returns 'foobar' 45 | provider.class.expects(:rabbitmq_version).returns '3.1.5' 46 | expect { provider.exists? }.to raise_error(Puppet::Error, %r{cannot parse line from list_policies}) 47 | end 48 | 49 | context 'with RabbitMQ version >=3.7.0' do 50 | it 'matches policies from list' do 51 | provider.class.expects(:rabbitmq_version).returns '3.7.0' 52 | provider.class.expects(:rabbitmqctl_list).with('policies', '-p', '/').returns <<~EOT 53 | / ha-all .* all {"ha-mode":"all","ha-sync-mode":"automatic"} 0 54 | / test .* exchanges {"ha-mode":"all"} 0 55 | EOT 56 | expect(provider.exists?).to eq(applyto: 'all', 57 | pattern: '.*', 58 | priority: '0', 59 | definition: { 60 | 'ha-mode' => 'all', 61 | 'ha-sync-mode' => 'automatic' 62 | }) 63 | end 64 | 65 | it 'matches policies from list targeting quorum queues' do 66 | provider.class.expects(:rabbitmq_version).returns '3.7.0' 67 | provider.class.expects(:rabbitmqctl_list).with('policies', '-p', '/').returns <<~EOT 68 | / ha-all ^.*$ quorum_queues {"delivery-limit":10,"initial-cluster-size":3,"max-length":100000000,"overflow":"reject-publish-dlx"} 0 69 | / test .* exchanges {"ha-mode":"all"} 0 70 | EOT 71 | expect(provider.exists?).to eq(applyto: 'quorum_queues', 72 | pattern: '^.*$', 73 | priority: '0', 74 | definition: { 75 | 'delivery-limit' => 10, 76 | 'initial-cluster-size' => 3, 77 | 'max-length' => 100_000_000, 78 | 'overflow' => 'reject-publish-dlx' 79 | }) 80 | end 81 | end 82 | 83 | context 'with RabbitMQ version >=3.2.0 and < 3.7.0' do 84 | it 'matches policies from list' do 85 | provider.class.expects(:rabbitmq_version).returns '3.6.9' 86 | provider.class.expects(:rabbitmqctl_list).with('policies', '-p', '/').returns <<~EOT 87 | / ha-all all .* {"ha-mode":"all","ha-sync-mode":"automatic"} 0 88 | / test exchanges .* {"ha-mode":"all"} 0 89 | EOT 90 | expect(provider.exists?).to eq(applyto: 'all', 91 | pattern: '.*', 92 | priority: '0', 93 | definition: { 94 | 'ha-mode' => 'all', 95 | 'ha-sync-mode' => 'automatic' 96 | }) 97 | end 98 | end 99 | 100 | context 'with RabbitMQ version <3.2.0' do 101 | it 'matches policies from list (<3.2.0)' do 102 | provider.class.expects(:rabbitmq_version).returns '3.1.5' 103 | provider.class.expects(:rabbitmqctl_list).with('policies', '-p', '/').returns <<~EOT 104 | / ha-all .* {"ha-mode":"all","ha-sync-mode":"automatic"} 0 105 | / test .* {"ha-mode":"all"} 0 106 | EOT 107 | expect(provider.exists?).to eq(applyto: 'all', 108 | pattern: '.*', 109 | priority: '0', 110 | definition: { 111 | 'ha-mode' => 'all', 112 | 'ha-sync-mode' => 'automatic' 113 | }) 114 | end 115 | end 116 | 117 | it 'does not match an empty list' do 118 | provider.class.expects(:rabbitmqctl_list).with('policies', '-p', '/').returns '' 119 | provider.class.expects(:rabbitmq_version).returns '3.1.5' 120 | expect(provider.exists?).to eq(nil) 121 | end 122 | 123 | it 'destroys policy' do 124 | provider.expects(:rabbitmqctl).with('clear_policy', '-p', '/', 'ha-all') 125 | provider.destroy 126 | end 127 | 128 | it 'onlies call set_policy once (<3.2.0)' do 129 | provider.class.expects(:rabbitmq_version).returns '3.1.0' 130 | provider.resource[:priority] = '10' 131 | provider.resource[:applyto] = 'exchanges' 132 | provider.expects(:rabbitmqctl).with('set_policy', 133 | '-p', '/', 134 | 'ha-all', 135 | '.*', 136 | '{"ha-mode":"all"}', 137 | '10').once 138 | provider.priority = '10' 139 | provider.applyto = 'exchanges' 140 | end 141 | 142 | it 'onlies call set_policy once (>=3.2.0)' do 143 | provider.class.expects(:rabbitmq_version).returns '3.2.0' 144 | provider.resource[:priority] = '10' 145 | provider.resource[:applyto] = 'exchanges' 146 | provider.expects(:rabbitmqctl).with('set_policy', 147 | '-p', '/', 148 | '--priority', '10', 149 | '--apply-to', 'exchanges', 150 | 'ha-all', 151 | '.*', 152 | '{"ha-mode":"all"}').once 153 | provider.priority = '10' 154 | provider.applyto = 'exchanges' 155 | end 156 | end 157 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_queue/rabbitmqadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_queue).provider(:rabbitmqadmin) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type::Rabbitmq_queue.new( 9 | name: 'test@/', 10 | durable: :true, 11 | auto_delete: :false, 12 | arguments: {} 13 | ) 14 | end 15 | let(:provider) { provider_class.new(resource) } 16 | 17 | it 'returns instances' do 18 | provider_class.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 19 | / 20 | EOT 21 | provider_class.expects(:rabbitmqctl_list).with('queues', '-p', '/', 'name', 'durable', 'auto_delete', 'arguments').returns <<~EOT 22 | test true false [] 23 | 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"}] 24 | EOT 25 | instances = provider_class.instances 26 | expect(instances.size).to eq(2) 27 | end 28 | 29 | it 'calls rabbitmqadmin to create' do 30 | provider.expects(:rabbitmqadmin).with('declare', 'queue', '--vhost=/', '--user=guest', '--password=guest', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 'name=test', 'durable=true', 'auto_delete=false', 'arguments={}') 31 | provider.create 32 | end 33 | 34 | it 'calls rabbitmqadmin to destroy' do 35 | provider.expects(:rabbitmqadmin).with('delete', 'queue', '--vhost=/', '--user=guest', '--password=guest', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 'name=test') 36 | provider.destroy 37 | end 38 | 39 | context 'specifying credentials' do 40 | let(:resource) do 41 | Puppet::Type::Rabbitmq_queue.new( 42 | name: 'test@/', 43 | durable: 'true', 44 | auto_delete: 'false', 45 | arguments: {}, 46 | user: 'colin', 47 | password: 'secret' 48 | ) 49 | end 50 | let(:provider) { provider_class.new(resource) } 51 | 52 | it 'calls rabbitmqadmin to create' do 53 | provider.expects(:rabbitmqadmin).with('declare', 'queue', '--vhost=/', '--user=colin', '--password=secret', '-c', '/etc/rabbitmq/rabbitmqadmin.conf', 'name=test', 'durable=true', 'auto_delete=false', 'arguments={}') 54 | provider.create 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_user/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | provider_class = Puppet::Type.type(:rabbitmq_user).provider(:rabbitmqctl) 6 | describe provider_class do 7 | let(:resource) do 8 | Puppet::Type.type(:rabbitmq_user).new( 9 | ensure: :present, 10 | name: 'rmq_x', 11 | password: 'secret', 12 | provider: described_class.name 13 | ) 14 | end 15 | let(:provider) { provider_class.new(resource) } 16 | let(:instance) { provider.class.instances.first } 17 | 18 | before do 19 | provider.class.stubs(:rabbitmqctl_list).with('users').returns( 20 | "rmq_x [disk, storage]\nrmq_y [network, cpu, administrator]\nrmq_z []\n" 21 | ) 22 | end 23 | 24 | describe '#self.instances' do 25 | it { expect(provider.class.instances.size).to eq(3) } 26 | 27 | it 'returns an array of users' do 28 | users = provider.class.instances.map(&:name) 29 | expect(users).to match_array(%w[rmq_x rmq_y rmq_z]) 30 | end 31 | 32 | it 'returns the expected tags' do 33 | tags = provider.class.instances.first.get(:tags) 34 | expect(tags).to match_array(%w[disk storage]) 35 | end 36 | end 37 | 38 | describe '#exists?' do 39 | it { expect(instance.exists?).to be true } 40 | end 41 | 42 | describe '#create' do 43 | it 'adds a user' do 44 | provider.expects(:rabbitmqctl).with('add_user', 'rmq_x', 'secret') 45 | provider.create 46 | end 47 | 48 | context 'no password supplied' do 49 | let(:resource) do 50 | Puppet::Type.type(:rabbitmq_user).new( 51 | ensure: :present, 52 | name: 'rmq_x' 53 | ) 54 | end 55 | 56 | it 'raises an error' do 57 | expect do 58 | provider.create 59 | end.to raise_error(Puppet::Error, 'Password is a required parameter for rabbitmq_user (user: rmq_x)') 60 | end 61 | end 62 | end 63 | 64 | describe '#destroy' do 65 | it 'removes a user' do 66 | provider.expects(:rabbitmqctl).with('delete_user', 'rmq_x') 67 | provider.destroy 68 | end 69 | end 70 | 71 | describe '#check_password' do 72 | context 'correct password' do 73 | before do 74 | provider.class.stubs(:rabbitmqctl).with( 75 | 'eval', 76 | 'rabbit_access_control:check_user_pass_login(list_to_binary("rmq_x"), list_to_binary("secret")).' 77 | ).returns <<~EOT 78 | {ok,{user,<<"rmq_x">>,[],rabbit_auth_backend_internal, 79 | {internal_user,<<"rmq_x">>, 80 | <<193,81,62,182,129,135,196,89,148,87,227,48,86,2,154, 81 | 192,52,119,214,177>>, 82 | []}}} 83 | EOT 84 | end 85 | 86 | it do 87 | provider.check_password('secret') 88 | end 89 | end 90 | 91 | context 'incorrect password' do 92 | before do 93 | provider.class.stubs(:rabbitmqctl).with( 94 | 'eval', 95 | 'rabbit_access_control:check_user_pass_login(list_to_binary("rmq_x"), list_to_binary("nottherightone")).' 96 | ).returns <<~EOT 97 | {refused,"user '~s' - invalid credentials",[<<"rmq_x">>]} 98 | ...done. 99 | EOT 100 | end 101 | 102 | it do 103 | provider.check_password('nottherightone') 104 | end 105 | end 106 | end 107 | 108 | describe '#tags=' do 109 | it 'clears all tags on existing user' do 110 | provider.set(tags: %w[tag1 tag2 tag3]) 111 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', []) 112 | provider.tags = [] 113 | provider.flush 114 | end 115 | 116 | it 'sets multiple tags' do 117 | provider.set(tags: []) 118 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', %w[tag1 tag2]) 119 | provider.tags = %w[tag1 tag2] 120 | provider.flush 121 | end 122 | 123 | it 'clears tags while keeping admin tag' do 124 | provider.set(tags: %w[administrator tag1 tag2]) 125 | resource[:admin] = true 126 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', ['administrator']) 127 | provider.tags = [] 128 | provider.flush 129 | end 130 | 131 | it 'changes tags while keeping admin tag' do 132 | provider.set(tags: %w[administrator tag1 tag2]) 133 | resource[:admin] = true 134 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', %w[tag1 tag7 tag3 administrator]) 135 | provider.tags = %w[tag1 tag7 tag3] 136 | provider.flush 137 | end 138 | end 139 | 140 | describe '#admin=' do 141 | it 'gets admin value properly' do 142 | provider.set(tags: %w[administrator tag1 tag2]) 143 | expect(provider.admin).to be :true 144 | end 145 | 146 | it 'gets false admin value' do 147 | provider.set(tags: %w[tag1 tag2]) 148 | expect(provider.admin).to be :false 149 | end 150 | 151 | it 'sets admin value' do 152 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', ['administrator']) 153 | resource[:admin] = true 154 | provider.admin = resource[:admin] 155 | provider.flush 156 | end 157 | 158 | it 'adds admin value to existing tags of the user' do 159 | resource[:tags] = %w[tag1 tag2] 160 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', %w[tag1 tag2 administrator]) 161 | resource[:admin] = true 162 | provider.admin = resource[:admin] 163 | provider.flush 164 | end 165 | 166 | it 'unsets admin value' do 167 | provider.set(tags: ['administrator']) 168 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', []) 169 | provider.admin = :false 170 | provider.flush 171 | end 172 | 173 | it 'does not interfere with existing tags on the user when unsetting admin value' do 174 | provider.set(tags: %w[administrator tag1 tag2]) 175 | resource[:tags] = %w[tag1 tag2] 176 | provider.expects(:rabbitmqctl).with('set_user_tags', 'rmq_x', %w[tag1 tag2]) 177 | provider.admin = :false 178 | provider.flush 179 | end 180 | end 181 | end 182 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_user_permissions/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'Puppet::Type.type(:rabbitmq_user_permissions).provider(:rabbitmqctl)' do 6 | let(:resource) do 7 | Puppet::Type::Rabbitmq_user_permissions.new( 8 | name: 'foo@bar' 9 | ) 10 | end 11 | let(:provider_class) { Puppet::Type.type(:rabbitmq_user_permissions).provider(:rabbitmqctl) } 12 | let(:provider) { provider_class.new(resource) } 13 | 14 | after do 15 | provider_class.instance_variable_set(:@users, nil) 16 | end 17 | 18 | it 'matches user permissions from list' do 19 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 20 | bar 1 2 3 21 | EOT 22 | expect(provider.exists?).to eq(configure: '1', write: '2', read: '3') 23 | end 24 | 25 | it 'matches user permissions with empty columns' do 26 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 27 | bar 3 28 | EOT 29 | expect(provider.exists?).to eq(configure: '', write: '', read: '3') 30 | end 31 | 32 | it 'does not match user permissions with more than 3 columns' do 33 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 34 | bar 1 2 3 4 35 | EOT 36 | expect { provider.exists? }.to raise_error(Puppet::Error, %r{cannot parse line from list_user_permissions}) 37 | end 38 | 39 | it 'does not match an empty list' do 40 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns '' 41 | expect(provider.exists?).to eq(nil) 42 | end 43 | 44 | it 'creates default permissions' do 45 | provider.instance_variable_set(:@should_vhost, 'bar') 46 | provider.instance_variable_set(:@should_user, 'foo') 47 | provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', "''", "''", "''") 48 | provider.create 49 | end 50 | 51 | it 'destroys permissions' do 52 | provider.instance_variable_set(:@should_vhost, 'bar') 53 | provider.instance_variable_set(:@should_user, 'foo') 54 | provider.expects(:rabbitmqctl).with('clear_permissions', '-p', 'bar', 'foo') 55 | provider.destroy 56 | end 57 | 58 | { configure_permission: '1', write_permission: '2', read_permission: '3' }.each do |k, v| 59 | it "is able to retrieve #{k}" do 60 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 61 | bar 1 2 3 62 | EOT 63 | expect(provider.send(k)).to eq(v) 64 | end 65 | 66 | it "is able to retrieve #{k} after exists has been called" do 67 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 68 | bar 1 2 3 69 | EOT 70 | provider.exists? 71 | expect(provider.send(k)).to eq(v) 72 | end 73 | end 74 | { configure_permission: %w[foo 2 3], 75 | read_permission: %w[1 2 foo], 76 | write_permission: %w[1 foo 3] }.each do |perm, columns| 77 | it "is able to sync #{perm}" do 78 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 79 | bar 1 2 3 80 | EOT 81 | provider.resource[perm] = 'foo' 82 | provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', *columns) 83 | provider.send("#{perm}=".to_sym, 'foo') 84 | end 85 | end 86 | it 'onlies call set_permissions once' do 87 | provider.class.expects(:rabbitmqctl_list).with('user_permissions', 'foo').returns <<~EOT 88 | bar 1 2 3 89 | EOT 90 | provider.resource[:configure_permission] = 'foo' 91 | provider.resource[:read_permission] = 'foo' 92 | provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', 'foo', '2', 'foo').once 93 | provider.configure_permission = 'foo' 94 | provider.read_permission = 'foo' 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/rabbitmq_vhost/rabbitmqctl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_vhost).provider(:rabbitmqctl) do 5 | let(:resource) do 6 | Puppet::Type::Rabbitmq_vhost.new( 7 | name: 'foo', 8 | description: 'foo description', 9 | default_queue_type: 'quorum', 10 | tags: %w[foo bar] 11 | ) 12 | end 13 | let(:provider) { described_class.new(resource) } 14 | 15 | it 'matches vhost names' do 16 | provider.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 17 | Listing vhosts ... 18 | foo 19 | ...done. 20 | EOT 21 | expect(provider.exists?).to eq(true) 22 | end 23 | 24 | it 'does not match if no vhosts on system' do 25 | provider.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 26 | Listing vhosts ... 27 | ...done. 28 | EOT 29 | expect(provider.exists?).to eq(false) 30 | end 31 | 32 | it 'does not match if no matching vhosts on system' do 33 | provider.expects(:rabbitmqctl_list).with('vhosts').returns <<~EOT 34 | Listing vhosts ... 35 | fooey 36 | ...done. 37 | EOT 38 | expect(provider.exists?).to eq(false) 39 | end 40 | 41 | context 'with RabbitMQ version <3.11.0 (no metadata support)' do 42 | it 'calls rabbitmqctl to create' do 43 | provider.expects(:supports_metadata?).at_least_once.returns false 44 | provider.expects(:rabbitmqctl).with('add_vhost', 'foo') 45 | provider.create 46 | end 47 | end 48 | 49 | context 'with RabbitMQ version >=3.11.0 (metadata support)' do 50 | it 'parses vhost list with valid metadata' do 51 | provider.class.expects(:supports_metadata?).at_least_once.returns true 52 | provider.class.expects(:vhost_list).returns <<~EOT 53 | inventory classic [] 54 | / Default virtual host undefined [] 55 | search quorum [] 56 | testing My cool vhost undefined [tag1, tag2] 57 | EOT 58 | instances = provider.class.instances 59 | expect(instances.size).to eq(4) 60 | expect(instances.map do |prov| 61 | { 62 | name: prov.get(:name), 63 | description: prov.get(:description), 64 | default_queue_type: prov.get(:default_queue_type), 65 | tags: prov.get(:tags) 66 | } 67 | end).to eq( 68 | [ 69 | { 70 | name: 'inventory', 71 | description: '', 72 | default_queue_type: 'classic', 73 | tags: [] 74 | }, 75 | { 76 | name: '/', 77 | description: 'Default virtual host', 78 | default_queue_type: :absent, 79 | tags: [] 80 | }, 81 | { 82 | name: 'search', 83 | description: '', 84 | default_queue_type: 'quorum', 85 | tags: [] 86 | }, 87 | { 88 | name: 'testing', 89 | description: 'My cool vhost', 90 | default_queue_type: :absent, 91 | tags: %w[tag1 tag2] 92 | } 93 | ] 94 | ) 95 | end 96 | 97 | it 'throws error when parsing invalid vhost metadata' do 98 | provider.class.expects(:supports_metadata?).at_least_once.returns true 99 | provider.class.expects(:vhost_list).returns <<~EOT 100 | inventory undefined [] 101 | / Default virtual host undefined 102 | EOT 103 | expect { print provider.class.instances }.to raise_error(Puppet::Error, %r{Cannot parse invalid vhost line: / Default virtual host undefined}) 104 | end 105 | 106 | it 'calls rabbitmqctl to create with metadata' do 107 | provider.expects(:supports_metadata?).at_least_once.returns true 108 | provider.expects(:rabbitmqctl).with('add_vhost', 'foo', ['--description', 'foo description'], \ 109 | ['--default-queue-type', 'quorum'], ['--tags', 'foo,bar']) 110 | provider.create 111 | end 112 | 113 | it 'updates tags' do 114 | provider.set(tags: %w[tag1 tag2]) 115 | provider.expects(:exists?).at_least_once.returns true 116 | provider.expects(:supports_metadata?).at_least_once.returns true 117 | provider.expects(:rabbitmqctl).with('update_vhost_metadata', 'foo', ['--tags', 'tag1,tag2']) 118 | provider.flush 119 | end 120 | 121 | it 'updates description' do 122 | provider.set(description: 'this is the new description') 123 | provider.expects(:exists?).at_least_once.returns true 124 | provider.expects(:supports_metadata?).at_least_once.returns true 125 | provider.expects(:rabbitmqctl).with('update_vhost_metadata', 'foo', ['--description', 'this is the new description']) 126 | provider.flush 127 | end 128 | end 129 | 130 | it 'calls rabbitmqctl to delete' do 131 | provider.expects(:rabbitmqctl).with('delete_vhost', 'foo') 132 | provider.destroy 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_binding_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_binding) do 5 | let(:binding) do 6 | Puppet::Type.type(:rabbitmq_binding).new( 7 | name: 'foo@blub@bar', 8 | destination_type: :queue 9 | ) 10 | end 11 | 12 | it 'accepts an queue name' do 13 | binding[:name] = 'dan@dude@pl' 14 | expect(binding[:name]).to eq('dan@dude@pl') 15 | end 16 | 17 | it 'requires a name' do 18 | expect do 19 | Puppet::Type.type(:rabbitmq_binding).new({}) 20 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 21 | end 22 | 23 | it 'errors when missing source' do 24 | expect do 25 | Puppet::Type.type(:rabbitmq_binding).new( 26 | name: 'test binding', 27 | destination: 'foobar' 28 | ) 29 | end.to raise_error(Puppet::Error, %r{`source` must be defined}) 30 | end 31 | 32 | it 'errors when missing destination' do 33 | expect do 34 | Puppet::Type.type(:rabbitmq_binding).new( 35 | name: 'test binding', 36 | source: 'foobar' 37 | ) 38 | end.to raise_error(Puppet::Error, %r{`destination` must be defined}) 39 | end 40 | 41 | it 'accepts an binding destination_type' do 42 | binding[:destination_type] = :exchange 43 | expect(binding[:destination_type]).to eq(:exchange) 44 | end 45 | 46 | it 'accepts a user' do 47 | binding[:user] = :root 48 | expect(binding[:user]).to eq(:root) 49 | end 50 | 51 | it 'accepts a password' do 52 | binding[:password] = :PaSsw0rD 53 | expect(binding[:password]).to eq(:PaSsw0rD) 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_cluster_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_cluster) do 5 | let(:rabbitmq_cluster) do 6 | Puppet::Type.type(:rabbitmq_cluster).new(name: 'test_cluster') 7 | end 8 | 9 | it 'accepts a cluster name' do 10 | rabbitmq_cluster[:name] = 'test_cluster' 11 | expect(rabbitmq_cluster[:name]).to eq('test_cluster') 12 | end 13 | 14 | it 'requires a name' do 15 | expect do 16 | Puppet::Type.type(:rabbitmq_cluster).new({}) 17 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 18 | end 19 | 20 | it 'check if init_node set to host1' do 21 | rabbitmq_cluster[:init_node] = 'host1' 22 | expect(rabbitmq_cluster[:init_node]).to eq('host1') 23 | end 24 | 25 | it 'check if local_node set to host1' do 26 | rabbitmq_cluster[:local_node] = 'host1' 27 | expect(rabbitmq_cluster[:local_node]).to eq('host1') 28 | end 29 | 30 | it 'local_node not set should default to undef' do 31 | rabbitmq_cluster[:init_node] = 'host1' 32 | expect(rabbitmq_cluster[:local_node]).to eq(:undef) 33 | end 34 | 35 | it 'try to set node_disc_type to ram' do 36 | rabbitmq_cluster[:node_disc_type] = 'ram' 37 | expect(rabbitmq_cluster[:node_disc_type]).to eq('ram') 38 | end 39 | 40 | it 'node_disc_type not set should default to disc' do 41 | rabbitmq_cluster[:name] = 'test_cluster' 42 | expect(rabbitmq_cluster[:node_disc_type]).to eq('disc') 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_exchange_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_exchange) do 5 | let(:exchange) do 6 | Puppet::Type.type(:rabbitmq_exchange).new( 7 | name: 'foo@bar', 8 | type: :topic, 9 | internal: false, 10 | auto_delete: false, 11 | durable: true 12 | ) 13 | end 14 | 15 | it 'accepts an exchange name' do 16 | exchange[:name] = 'dan@pl' 17 | expect(exchange[:name]).to eq('dan@pl') 18 | end 19 | 20 | it 'requires a name' do 21 | expect do 22 | Puppet::Type.type(:rabbitmq_exchange).new({}) 23 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 24 | end 25 | 26 | it 'does not allow whitespace in the name' do 27 | expect do 28 | exchange[:name] = 'b r' 29 | end.to raise_error(Puppet::Error, %r{Valid values match}) 30 | end 31 | 32 | it 'does not allow names without @' do 33 | expect do 34 | exchange[:name] = 'b_r' 35 | end.to raise_error(Puppet::Error, %r{Valid values match}) 36 | end 37 | 38 | it 'accepts an exchange type' do 39 | exchange[:type] = :direct 40 | expect(exchange[:type]).to eq(:direct) 41 | end 42 | 43 | it 'requires a type' do 44 | expect do 45 | Puppet::Type.type(:rabbitmq_exchange).new(name: 'foo@bar') 46 | end.to raise_error(%r{.*must set type when creating exchange.*}) 47 | end 48 | 49 | it 'does not require a type when destroying' do 50 | expect do 51 | Puppet::Type.type(:rabbitmq_exchange).new(name: 'foo@bar', ensure: :absent) 52 | end.not_to raise_error 53 | end 54 | 55 | it 'accepts a user' do 56 | exchange[:user] = :root 57 | expect(exchange[:user]).to eq(:root) 58 | end 59 | 60 | it 'accepts a password' do 61 | exchange[:password] = :PaSsw0rD 62 | expect(exchange[:password]).to eq(:PaSsw0rD) 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_parameter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_parameter) do 5 | let(:parameter) do 6 | Puppet::Type.type(:rabbitmq_parameter).new( 7 | name: 'documentumShovel@/', 8 | component_name: 'shovel', 9 | value: { 10 | 'src-uri' => 'amqp://myremote-server', 11 | 'src-queue' => 'queue.docs.outgoing', 12 | 'dest-uri' => 'amqp://', 13 | 'dest-queue' => 'queue.docs.incoming' 14 | } 15 | ) 16 | end 17 | 18 | it 'accepts a valid name' do 19 | parameter[:name] = 'documentumShovel@/' 20 | expect(parameter[:name]).to eq('documentumShovel@/') 21 | end 22 | 23 | it 'requires a name' do 24 | expect do 25 | Puppet::Type.type(:rabbitmq_parameter).new({}) 26 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 27 | end 28 | 29 | it 'fails when name does not have a @' do 30 | expect do 31 | parameter[:name] = 'documentumShovel' 32 | end.to raise_error(Puppet::Error, %r{Valid values match}) 33 | end 34 | 35 | it 'accepts a string' do 36 | parameter[:component_name] = 'mystring' 37 | expect(parameter[:component_name]).to eq('mystring') 38 | end 39 | 40 | it 'is not empty' do 41 | expect do 42 | parameter[:component_name] = '' 43 | end.to raise_error(Puppet::Error, %r{component_name must be defined}) 44 | end 45 | 46 | it 'accepts a valid hash for value' do 47 | parameter[:value] = { 'message-ttl' => '1800000' } 48 | expect(parameter[:value]).to eq({ 'message-ttl' => 1_800_000 }) 49 | end 50 | 51 | it 'does not accept an empty string for definition' do 52 | expect do 53 | parameter[:value] = '' 54 | end.to raise_error(Puppet::Error, %r{Invalid value}) 55 | end 56 | 57 | it 'does not accept a string for definition' do 58 | expect do 59 | parameter[:value] = 'guest' 60 | end.to raise_error(Puppet::Error, %r{Invalid value}) 61 | end 62 | 63 | it 'does not accept an object for definition' do 64 | expect do 65 | parameter[:value] = { 'message-ttl' => Object.new } 66 | end.to raise_error(Puppet::Error, %r{Invalid value}) 67 | end 68 | 69 | it 'accepts array as myparameter' do 70 | value = { 'myparameter' => %w[my string] } 71 | parameter[:value] = value 72 | expect(parameter[:value]['myparameter']).to eq(%w[my string]) 73 | end 74 | 75 | it 'accepts string as myparameter' do 76 | value = { 'myparameter' => 'mystring' } 77 | parameter[:value] = value 78 | expect(parameter[:value]['myparameter']).to eq('mystring') 79 | end 80 | 81 | it 'converts to integer when string only contains numbers' do 82 | value = { 'myparameter' => '1800000' } 83 | parameter[:value] = value 84 | expect(parameter[:value]['myparameter']).to eq(1_800_000) 85 | end 86 | 87 | context 'autoconvert is set to false' do 88 | let(:parameter) do 89 | Puppet::Type.type(:rabbitmq_parameter).new( 90 | name: 'documentumShovel@/', 91 | component_name: 'shovel', 92 | autoconvert: false, 93 | value: { 'myparameter' => '1800000' } 94 | ) 95 | end 96 | 97 | it 'does not convert numeric string to integer' do 98 | expect(parameter[:value]['myparameter']).to eq('1800000') 99 | expect(parameter[:value]['myparameter']).to be_a(String) 100 | end 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_plugin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_plugin) do 5 | let(:plugin) do 6 | Puppet::Type.type(:rabbitmq_plugin).new(name: 'foo') 7 | end 8 | 9 | it 'accepts a plugin name' do 10 | plugin[:name] = 'plugin-name' 11 | expect(plugin[:name]).to eq('plugin-name') 12 | end 13 | 14 | it 'accepts a mode of offline' do 15 | plugin[:mode] = 'offline' 16 | expect(plugin[:mode]).to eq(:offline) 17 | end 18 | 19 | it 'accepts a mode of online' do 20 | plugin[:mode] = 'online' 21 | expect(plugin[:mode]).to eq(:online) 22 | end 23 | 24 | it 'accepts a mode of best' do 25 | plugin[:mode] = 'best' 26 | expect(plugin[:mode]).to eq(:best) 27 | end 28 | 29 | it 'requires a name' do 30 | expect do 31 | Puppet::Type.type(:rabbitmq_plugin).new({}) 32 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 33 | end 34 | 35 | it 'defaults to a umask of 0022' do 36 | expect(plugin[:umask]).to eq(0o022) 37 | end 38 | 39 | it 'defaults to a mode of best' do 40 | expect(plugin[:mode]).to eq(:best) 41 | end 42 | 43 | it 'does not allow a non-octal value to be specified' do 44 | expect do 45 | plugin[:umask] = '198' 46 | end.to raise_error(Puppet::Error, %r{The umask specification is invalid: "198"}) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_queue_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_queue) do 5 | let(:queue) do 6 | Puppet::Type.type(:rabbitmq_queue).new( 7 | name: 'foo@bar', 8 | durable: :true, 9 | arguments: { 10 | 'x-message-ttl' => 45, 11 | 'x-dead-letter-exchange' => 'deadexchange' 12 | } 13 | ) 14 | end 15 | 16 | it 'accepts an queue name' do 17 | queue[:name] = 'dan@pl' 18 | expect(queue[:name]).to eq('dan@pl') 19 | end 20 | 21 | it 'requires a name' do 22 | expect do 23 | Puppet::Type.type(:rabbitmq_queue).new({}) 24 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 25 | end 26 | 27 | it 'does not allow whitespace in the name' do 28 | expect do 29 | queue[:name] = 'b r' 30 | end.to raise_error(Puppet::Error, %r{Valid values match}) 31 | end 32 | 33 | it 'does not allow names without @' do 34 | expect do 35 | queue[:name] = 'b_r' 36 | end.to raise_error(Puppet::Error, %r{Valid values match}) 37 | end 38 | 39 | it 'accepts an arguments with numbers value' do 40 | queue[:arguments] = { 'x-message-ttl' => 30 } 41 | expect(queue[:arguments].to_json).to eq('{"x-message-ttl":30}') 42 | end 43 | 44 | it 'accepts an arguments with string value' do 45 | queue[:arguments] = { 'x-dead-letter-exchange' => 'catchallexchange' } 46 | expect(queue[:arguments].to_json).to eq('{"x-dead-letter-exchange":"catchallexchange"}') 47 | end 48 | 49 | it 'accepts an queue durable' do 50 | queue[:durable] = :true 51 | expect(queue[:durable]).to eq(:true) 52 | end 53 | 54 | it 'accepts a user' do 55 | queue[:user] = :root 56 | expect(queue[:user]).to eq(:root) 57 | end 58 | 59 | it 'accepts a password' do 60 | queue[:password] = :PaSsw0rD 61 | expect(queue[:password]).to eq(:PaSsw0rD) 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_user_permissions_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_user_permissions) do 5 | let(:perms) do 6 | Puppet::Type.type(:rabbitmq_user_permissions).new(name: 'foo@bar') 7 | end 8 | 9 | it 'accepts a valid hostname name' do 10 | perms[:name] = 'dan@bar' 11 | expect(perms[:name]).to eq('dan@bar') 12 | end 13 | 14 | it 'requires a name' do 15 | expect do 16 | Puppet::Type.type(:rabbitmq_user_permissions).new({}) 17 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 18 | end 19 | 20 | it 'fails when names dont have a @' do 21 | expect do 22 | perms[:name] = 'bar' 23 | end.to raise_error(Puppet::Error, %r{Valid values match}) 24 | end 25 | 26 | %i[configure_permission read_permission write_permission].each do |param| 27 | it 'does not default to anything' do 28 | expect(perms[param]).to eq(nil) 29 | end 30 | 31 | it "accepts a valid regex for #{param}" do 32 | perms[param] = '.*?' 33 | expect(perms[param]).to eq('.*?') 34 | end 35 | 36 | it "accepts an empty string for #{param}" do 37 | perms[param] = '' 38 | expect(perms[param]).to eq('') 39 | end 40 | 41 | it "does not accept invalid regex for #{param}" do 42 | expect do 43 | perms[param] = '*' 44 | end.to raise_error(Puppet::Error, %r{Invalid regexp}) 45 | end 46 | end 47 | { rabbitmq_vhost: 'dan@test', rabbitmq_user: 'test@dan' }.each do |k, v| 48 | it "autorequires #{k}" do 49 | vhost = if k == :rabbitmq_vhost 50 | Puppet::Type.type(k).new(name: 'test') 51 | else 52 | Puppet::Type.type(k).new(name: 'test', password: 'pass') 53 | end 54 | perm = Puppet::Type.type(:rabbitmq_user_permissions).new(name: v) 55 | Puppet::Resource::Catalog.new :testing do |conf| 56 | [vhost, perm].each { |resource| conf.add_resource resource } 57 | end 58 | rel = perm.autorequire[0] 59 | expect(rel.source.ref).to eq(vhost.ref) 60 | expect(rel.target.ref).to eq(perm.ref) 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_user) do 5 | let(:user) do 6 | Puppet::Type.type(:rabbitmq_user).new(name: 'foo', password: 'pass') 7 | end 8 | 9 | it 'accepts a user name' do 10 | user[:name] = 'dan' 11 | expect(user[:name]).to eq('dan') 12 | end 13 | 14 | it 'admin is false when :admin is not set' do 15 | user[:name] = 'dan' 16 | expect(user[:admin]).to eq(:false) 17 | end 18 | 19 | it 'accepts a password' do 20 | user[:password] = 'foo' 21 | expect(user[:password]).to eq('foo') 22 | end 23 | 24 | it 'requires a name' do 25 | expect do 26 | Puppet::Type.type(:rabbitmq_user).new({}) 27 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 28 | end 29 | 30 | it 'does not allow whitespace in the name' do 31 | expect do 32 | user[:name] = 'b r' 33 | end.to raise_error(Puppet::Error, %r{Valid values match}) 34 | end 35 | 36 | [true, false, 'true', 'false'].each do |val| 37 | it "admin property should accept #{val}" do 38 | user[:admin] = val 39 | expect(user[:admin]).to eq(val.to_s.to_sym) 40 | end 41 | end 42 | it 'does not accept non-boolean values for admin' do 43 | expect do 44 | user[:admin] = 'yes' 45 | end.to raise_error(Puppet::Error, %r{Invalid value}) 46 | end 47 | 48 | it 'does not accept tags with spaces' do 49 | expect do 50 | user[:tags] = ['policy maker'] 51 | end.to raise_error(Puppet::Error, %r{Invalid tag}) 52 | end 53 | 54 | it 'does not accept the administrator tag' do 55 | expect do 56 | user[:tags] = ['administrator'] 57 | end.to raise_error(Puppet::Error, %r{must use admin property}) 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/rabbitmq_vhost_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe Puppet::Type.type(:rabbitmq_vhost) do 5 | let(:vhost) do 6 | Puppet::Type.type(:rabbitmq_vhost).new(name: 'foo') 7 | end 8 | 9 | it 'accepts a vhost name' do 10 | vhost[:name] = 'dan' 11 | expect(vhost[:name]).to eq('dan') 12 | end 13 | 14 | it 'requires a name' do 15 | expect do 16 | Puppet::Type.type(:rabbitmq_vhost).new({}) 17 | end.to raise_error(Puppet::Error, 'Title or name must be provided') 18 | end 19 | 20 | it 'does not allow whitespace in the name' do 21 | expect do 22 | vhost[:name] = 'b r' 23 | end.to raise_error(Puppet::Error, %r{Valid values match}) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /templates/README.markdown: -------------------------------------------------------------------------------- 1 | Templates 2 | ========= 3 | 4 | Puppet supports templates and templating via ERB, which is part of the Ruby 5 | standard library and is used for many other projects including Ruby on Rails. 6 | Templates allow you to manage the content of template files, for example 7 | configuration files that cannot yet be managed as a Puppet type. Learn more at 8 | http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Templating 9 | 10 | You can use templates like this: 11 | 12 | class myclass { 13 | package { mypackage: ensure => latest } 14 | service { myservice: ensure => running } 15 | file { "/etc/myfile": 16 | content => template("mymodule/myfile.erb") 17 | } 18 | } 19 | 20 | The templates are searched for in: 21 | 22 | $templatedir/mymodule/myfile.erb 23 | $modulepath/mymodule/templates/myfile.erb 24 | -------------------------------------------------------------------------------- /templates/enabled_plugins.epp: -------------------------------------------------------------------------------- 1 | % This file managed by Puppet 2 | % Template Path: <%= $rabbitmq::config::module_name %>/templates/enabled_plugins 3 | [<%= ($::rabbitmq::config::_plugins.unique).join(',')%>]. 4 | -------------------------------------------------------------------------------- /templates/inetrc.erb: -------------------------------------------------------------------------------- 1 | %% This file managed by Puppet 2 | %% Template Path: <%= @module_name %>/templates/inetrc 3 | <%- if @ipv6 -%> 4 | {inet6, true}. 5 | <%- end -%> 6 | -------------------------------------------------------------------------------- /templates/limits.conf: -------------------------------------------------------------------------------- 1 | rabbitmq soft nofile <%= @file_limit %> 2 | rabbitmq hard nofile <%= @file_limit %> 3 | -------------------------------------------------------------------------------- /templates/rabbitmq-env.conf.epp: -------------------------------------------------------------------------------- 1 | <% $rabbitmq::config::environment_variables.keys.sort.each |$k| { -%> 2 | <%- unless $rabbitmq::config::environment_variables[$k] == Undef {-%> 3 | <%= $k %>=<%= $rabbitmq::config::environment_variables[$k] %> 4 | <%-} -%> 5 | <% } -%> 6 | -------------------------------------------------------------------------------- /templates/rabbitmqadmin.conf.epp: -------------------------------------------------------------------------------- 1 | [default] 2 | <% if $rabbitmq::config::ssl and $rabbitmq::config::management_ssl {-%> 3 | ssl = True 4 | ssl_ca_cert_file = <%= $rabbitmq::config::ssl_management_cacert %> 5 | ssl_cert_file = <%= $rabbitmq::config::ssl_management_cert %> 6 | ssl_key_file = <%= $rabbitmq::config::ssl_management_key %> 7 | port = <%= $rabbitmq::config::ssl_management_port %> 8 | <% unless $rabbitmq::config::management_hostname {-%> 9 | hostname = <%= $facts['networking']['fqdn'] %> 10 | <% } -%> 11 | <% } else {-%> 12 | port = <%= $rabbitmq::config::management_port %> 13 | <% } -%> 14 | <% if $rabbitmq::config::management_hostname { %> 15 | hostname = <%= $rabbitmq::config::management_hostname %> 16 | <% } -%> 17 | --------------------------------------------------------------------------------