├── .fixtures.yml ├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ ├── mend.yml │ ├── nightly.yml │ ├── release.yml │ ├── release_prep.yml │ └── release_without.yml ├── .gitignore ├── .pdkignore ├── .pmtignore ├── .puppet-lint.rc ├── .rspec ├── .rspec_parallel ├── .rubocop.yml ├── .sync.yml ├── .vscode └── extensions.json ├── .yardopts ├── CHANGELOG.md ├── CODEOWNERS ├── Gemfile ├── HISTORY.md ├── LICENSE ├── NOTICE ├── README.md ├── REFERENCE.md ├── Rakefile ├── lib ├── facter │ └── puppetdb_version.rb └── puppet │ ├── functions │ └── puppetdb │ │ ├── create_subsetting_resource_hash.rb │ │ └── flatten_java_args.rb │ ├── provider │ └── puppetdb_conn_validator │ │ └── puppet_https.rb │ ├── type │ └── puppetdb_conn_validator.rb │ └── util │ └── puppetdb_validator.rb ├── manifests ├── database │ ├── default_read_grant.pp │ ├── postgresql.pp │ ├── postgresql_ssl_rules.pp │ ├── read_grant.pp │ ├── read_only_user.pp │ └── ssl_configuration.pp ├── globals.pp ├── init.pp ├── master │ ├── config.pp │ ├── puppetdb_conf.pp │ ├── report_processor.pp │ ├── routes.pp │ └── storeconfigs.pp ├── params.pp ├── server.pp └── server │ ├── command_processing.pp │ ├── database.pp │ ├── firewall.pp │ ├── global.pp │ ├── jetty.pp │ ├── puppetdb.pp │ ├── read_database.pp │ ├── validate_db.pp │ └── validate_read_db.pp ├── metadata.json ├── pdk.yaml ├── provision.yaml ├── rakelib ├── common.rake └── litmus.rake ├── spec ├── acceptance │ └── standalone_spec.rb ├── defines │ └── database │ │ ├── default_read_grant_spec.rb │ │ ├── postgresql_ssl_rules_spec.rb │ │ ├── read_grant_spec.rb │ │ └── read_only_user_spec.rb ├── functions │ ├── create_subsetting_resource_hash_spec.rb │ └── flatten_java_args_spec.rb ├── spec_helper.rb ├── spec_helper_acceptance.rb ├── spec_helper_acceptance_local.rb ├── spec_helper_local.rb ├── support │ ├── acceptance │ │ └── shared │ │ │ ├── puppetdb.rb │ │ │ ├── puppetserver.pp │ │ │ └── puppetserver.rb │ └── unit │ │ ├── facts.rb │ │ └── shared │ │ ├── database.rb │ │ ├── inherits.rb │ │ └── server.rb └── unit │ ├── classes │ ├── database │ │ ├── postgresql_spec.rb │ │ └── ssl_configuration_spec.rb │ ├── globals_spec.rb │ ├── init_spec.rb │ ├── master │ │ ├── config_spec.rb │ │ ├── puppetdb_conf_spec.rb │ │ ├── report_processor_spec.rb │ │ ├── routes_spec.rb │ │ └── storeconfigs_spec.rb │ ├── params_spec.rb │ ├── server │ │ ├── command_processing_spec.rb │ │ ├── database_ini_spec.rb │ │ ├── db_connection_uri_spec.rb │ │ ├── db_read_uri_spec.rb │ │ ├── firewall_spec.rb │ │ ├── global_ini_spec.rb │ │ ├── jetty_ini_spec.rb │ │ ├── puppetdb_ini_spec.rb │ │ ├── read_database_ini_spec.rb │ │ ├── validate_db_spec.rb │ │ └── validate_read_db_spec.rb │ └── server_spec.rb │ ├── facter │ └── puppetdb_version_spec.rb │ └── util │ └── puppetdb_validator_spec.rb ├── templates ├── certificate-whitelist.erb ├── puppetdb-DLO-cleanup.service.epp ├── puppetdb-DLO-cleanup.timer.epp └── routes.yaml.erb └── types └── ttl.pp /.fixtures.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fixtures: 3 | repositories: 4 | inifile: 'https://github.com/puppetlabs/puppetlabs-inifile.git' 5 | stdlib: 'https://github.com/puppetlabs/puppetlabs-stdlib.git' 6 | apt: 'https://github.com/puppetlabs/puppetlabs-apt.git' 7 | concat: 'https://github.com/puppetlabs/puppetlabs-concat.git' 8 | systemd: 'https://github.com/camptocamp/puppet-systemd.git' 9 | provision: 'https://github.com/puppetlabs/provision.git' 10 | puppet_agent: 'https://github.com/puppetlabs/puppetlabs-puppet_agent.git' 11 | facts: 'https://github.com/puppetlabs/puppetlabs-facts.git' 12 | cron_core: 'https://github.com/puppetlabs/puppetlabs-cron_core.git' 13 | yumrepo_core: 'https://github.com/puppetlabs/puppetlabs-yumrepo_core.git' 14 | augeas_core: 'https://github.com/puppetlabs/puppetlabs-augeas_core.git' 15 | postgresql: 'https://github.com/puppetlabs/puppetlabs-postgresql.git' 16 | firewall: 'https://github.com/puppetlabs/puppetlabs-firewall.git' 17 | postgresql: 'https://github.com/puppetlabs/puppetlabs-postgresql.git' 18 | firewall: 'https://github.com/puppetlabs/puppetlabs-firewall.git' 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rb eol=lf 2 | *.erb eol=lf 3 | *.pp eol=lf 4 | *.sh eol=lf 5 | *.epp eol=lf 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "ci" 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - "main" 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | Spec: 16 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_ci.yml@main" 17 | secrets: "inherit" 18 | 19 | Acceptance: 20 | needs: Spec 21 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_acceptance.yml@main" 22 | secrets: "inherit" 23 | with: 24 | runs_on: "ubuntu-20.04" 25 | -------------------------------------------------------------------------------- /.github/workflows/mend.yml: -------------------------------------------------------------------------------- 1 | name: "mend" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "main" 7 | schedule: 8 | - cron: "0 0 * * *" 9 | workflow_dispatch: 10 | 11 | jobs: 12 | 13 | mend: 14 | uses: "puppetlabs/cat-github-actions/.github/workflows/mend_ruby.yml@main" 15 | secrets: "inherit" 16 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "nightly" 3 | 4 | on: 5 | schedule: 6 | - cron: "0 0 * * *" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Spec: 11 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_ci.yml@main" 12 | secrets: "inherit" 13 | 14 | Acceptance: 15 | needs: Spec 16 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_acceptance.yml@main" 17 | secrets: "inherit" 18 | with: 19 | runs_on: "ubuntu-20.04" 20 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: "Publish module" 2 | run-name: > 3 | ${{ format('tag={0}', inputs.tag) }} 4 | ${{ format('release={0}', inputs.release) }} 5 | ${{ format('publish={0}', inputs.publish) }} 6 | ${{ format('edit={0}', inputs.edit) }} 7 | 8 | on: 9 | workflow_dispatch: 10 | inputs: 11 | tag: 12 | description: "Enter an old tag, or blank to tag HEAD of branch" 13 | type: string 14 | release: 15 | description: "Create a Github release" 16 | type: boolean 17 | default: true 18 | publish: 19 | description: "Publish to the Forge" 20 | type: boolean 21 | default: true 22 | edit: 23 | description: "Re-tag and regenerate release notes" 24 | type: boolean 25 | default: false 26 | 27 | jobs: 28 | release: 29 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release.yml@main" 30 | secrets: "inherit" 31 | with: 32 | tag: ${{ inputs.tag }} 33 | release: ${{ inputs.release }} 34 | publish: ${{ inputs.publish }} 35 | edit: ${{ inputs.edit }} 36 | -------------------------------------------------------------------------------- /.github/workflows/release_prep.yml: -------------------------------------------------------------------------------- 1 | name: "Release Prep" 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "Module version to be released. Must be a valid semver string. (1.2.3)" 8 | required: true 9 | 10 | jobs: 11 | release_prep: 12 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release_prep.yml@main" 13 | with: 14 | version: "${{ github.event.inputs.version }}" 15 | secrets: "inherit" 16 | -------------------------------------------------------------------------------- /.github/workflows/release_without.yml: -------------------------------------------------------------------------------- 1 | name: "Publish module without" 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release.yml@main" 9 | secrets: "inherit" 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/* 20 | /tmp/ 21 | /vendor/ 22 | /convert_report.txt 23 | /update_report.txt 24 | .DS_Store 25 | .project 26 | .envrc 27 | /inventory.yaml 28 | /spec/fixtures/litmus_inventory.yaml 29 | -------------------------------------------------------------------------------- /.pdkignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/* 20 | /tmp/ 21 | /vendor/ 22 | /convert_report.txt 23 | /update_report.txt 24 | .DS_Store 25 | .project 26 | .envrc 27 | /inventory.yaml 28 | /spec/fixtures/litmus_inventory.yaml 29 | /.fixtures.yml 30 | /Gemfile 31 | /.gitattributes 32 | /.github/ 33 | /.gitignore 34 | /.pdkignore 35 | /.puppet-lint.rc 36 | /Rakefile 37 | /rakelib/ 38 | /.rspec 39 | /..yml 40 | /.yardopts 41 | /spec/ 42 | /.vscode/ 43 | /.sync.yml 44 | /.devcontainer/ 45 | /.*.yml 46 | /pdk.yaml 47 | /.pmtignore 48 | /.git* 49 | /.editorconfig 50 | /provision.yaml 51 | -------------------------------------------------------------------------------- /.pmtignore: -------------------------------------------------------------------------------- 1 | spec/ 2 | Rakefile 3 | Gemfile 4 | Gemfile.lock 5 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | --relative 2 | --no-parameter_types-check 3 | --no-140chars-check 4 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rspec_parallel: -------------------------------------------------------------------------------- 1 | --format progress 2 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | .rubocop.yml: 3 | default_configs: 4 | AllCops: 5 | NewCops: enable 6 | Include: 7 | - '**/*.rake' 8 | .pdkignore: 9 | paths: 10 | - /.*.yml 11 | - /pdk.yaml 12 | - /.pmtignore 13 | - /.git* 14 | - /.editorconfig 15 | - /provision.yaml 16 | Rakefile: 17 | default_disabled_lint_checks: 18 | - parameter_types 19 | - 140chars 20 | spec/default_facts.yml: 21 | unmanaged: true 22 | spec/spec_helper.rb: 23 | coverage_report: true 24 | minimum_code_coverage_percentage: 100 25 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "puppet.puppet-vscode", 4 | "rebornix.Ruby" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --markup markdown 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @puppetlabs/puppetdb @bastelfreak @smortex 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 2 | 3 | def location_for(place_or_version, fake_version = nil) 4 | git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} 5 | file_url_regex = %r{\Afile:\/\/(?.*)} 6 | 7 | if place_or_version && (git_url = place_or_version.match(git_url_regex)) 8 | [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact 9 | elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) 10 | ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] 11 | else 12 | [place_or_version, { require: false }] 13 | end 14 | end 15 | 16 | group :development do 17 | gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 18 | gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 19 | gem "json", '= 2.5.1', require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 20 | gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 21 | gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 22 | gem "racc", '~> 1.4.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 23 | gem "voxpupuli-puppet-lint-plugins", '~> 5.0', require: false 24 | gem "facterdb", '~> 1.18', require: false 25 | gem "metadata-json-lint", '~> 3.0', require: false 26 | gem "puppetlabs_spec_helper", '~> 6.0', require: false 27 | gem "rspec-puppet-facts", '~> 2.0', require: false 28 | gem "codecov", '~> 0.2', require: false 29 | gem "dependency_checker", '~> 1.0.0', require: false 30 | gem "parallel_tests", '= 3.12.1', require: false 31 | gem "pry", '~> 0.10', require: false 32 | gem "simplecov-console", '~> 0.5', require: false 33 | gem "puppet-debugger", '~> 1.0', require: false 34 | gem "rubocop", '= 1.48.1', require: false 35 | gem "rubocop-performance", '= 1.16.0', require: false 36 | gem "rubocop-rspec", '= 2.19.0', require: false 37 | gem "puppet-strings", '~> 4.0', require: false 38 | gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] 39 | end 40 | group :system_tests do 41 | gem "puppet_litmus", '~> 1.0', require: false, platforms: [:ruby, :x64_mingw] 42 | gem "serverspec", '~> 2.41', require: false 43 | end 44 | group :release_prep do 45 | gem "puppet-strings", '~> 4.0', require: false 46 | gem "puppetlabs_spec_helper", '~> 6.0', require: false 47 | end 48 | 49 | puppet_version = ENV['PUPPET_GEM_VERSION'] 50 | facter_version = ENV['FACTER_GEM_VERSION'] 51 | hiera_version = ENV['HIERA_GEM_VERSION'] 52 | 53 | gems = {} 54 | 55 | gems['puppet'] = location_for(puppet_version) 56 | 57 | # If facter or hiera versions have been specified via the environment 58 | # variables 59 | 60 | gems['facter'] = location_for(facter_version) if facter_version 61 | gems['hiera'] = location_for(hiera_version) if hiera_version 62 | 63 | gems.each do |gem_name, gem_params| 64 | gem gem_name, *gem_params 65 | end 66 | 67 | # Evaluate Gemfile.local and ~/.gemfile if they exist 68 | extra_gemfiles = [ 69 | "#{__FILE__}.local", 70 | File.join(Dir.home, '.gemfile'), 71 | ] 72 | 73 | extra_gemfiles.each do |gemfile| 74 | if File.file?(gemfile) && File.readable?(gemfile) 75 | eval(File.read(gemfile), binding) 76 | end 77 | end 78 | # vim: syntax=ruby 79 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Puppet PuppetDB Module - Puppet module for managing PuppetDB 2 | 3 | Copyright (C) 2012-2014 Puppet Labs, Inc. 4 | 5 | Puppet Labs can be contacted at: info@puppetlabs.com 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | require 'puppet_litmus/rake_tasks' if Gem.loaded_specs.key? 'puppet_litmus' 5 | require 'puppetlabs_spec_helper/rake_tasks' 6 | require 'puppet-syntax/tasks/puppet-syntax' 7 | require 'github_changelog_generator/task' if Gem.loaded_specs.key? 'github_changelog_generator' 8 | require 'puppet-strings/tasks' if Gem.loaded_specs.key? 'puppet-strings' 9 | 10 | def changelog_user 11 | return unless Rake.application.top_level_tasks.include? "changelog" 12 | returnVal = nil || JSON.load(File.read('metadata.json'))['author'] 13 | raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil? 14 | puts "GitHubChangelogGenerator user:#{returnVal}" 15 | returnVal 16 | end 17 | 18 | def changelog_project 19 | return unless Rake.application.top_level_tasks.include? "changelog" 20 | 21 | returnVal = nil 22 | returnVal ||= begin 23 | metadata_source = JSON.load(File.read('metadata.json'))['source'] 24 | metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z}) 25 | 26 | metadata_source_match && metadata_source_match[1] 27 | end 28 | 29 | raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil? 30 | 31 | puts "GitHubChangelogGenerator project:#{returnVal}" 32 | returnVal 33 | end 34 | 35 | def changelog_future_release 36 | return unless Rake.application.top_level_tasks.include? "changelog" 37 | returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version'] 38 | raise "unable to find the future_release (version) in metadata.json" if returnVal.nil? 39 | puts "GitHubChangelogGenerator future_release:#{returnVal}" 40 | returnVal 41 | end 42 | 43 | PuppetLint.configuration.send('disable_relative') 44 | PuppetLint.configuration.send('disable_parameter_types') 45 | PuppetLint.configuration.send('disable_140chars') 46 | 47 | 48 | if Gem.loaded_specs.key? 'github_changelog_generator' 49 | GitHubChangelogGenerator::RakeTask.new :changelog do |config| 50 | raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil? 51 | config.user = "#{changelog_user}" 52 | config.project = "#{changelog_project}" 53 | config.future_release = "#{changelog_future_release}" 54 | config.exclude_labels = ['maintenance'] 55 | config.header = "# Change log\n\nAll notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org)." 56 | config.add_pr_wo_labels = true 57 | config.issues = false 58 | config.merge_prefix = "### UNCATEGORIZED PRS; LABEL THEM ON GITHUB" 59 | config.configure_sections = { 60 | "Changed" => { 61 | "prefix" => "### Changed", 62 | "labels" => ["backwards-incompatible"], 63 | }, 64 | "Added" => { 65 | "prefix" => "### Added", 66 | "labels" => ["enhancement", "feature"], 67 | }, 68 | "Fixed" => { 69 | "prefix" => "### Fixed", 70 | "labels" => ["bug", "documentation", "bugfix"], 71 | }, 72 | } 73 | end 74 | else 75 | desc 'Generate a Changelog from GitHub' 76 | task :changelog do 77 | raise < 1.15' 86 | condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')" 87 | EOM 88 | end 89 | end 90 | 91 | -------------------------------------------------------------------------------- /lib/facter/puppetdb_version.rb: -------------------------------------------------------------------------------- 1 | Facter.add(:puppetdb_version) do 2 | confine { Facter::Util::Resolution.which('puppetdb') } 3 | 4 | setcode do 5 | output = Facter::Core::Execution.execute('puppetdb --version') 6 | output.split(':').last.strip 7 | rescue Facter::Core::Execution::ExecutionFailure 8 | nil 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/puppet/functions/puppetdb/create_subsetting_resource_hash.rb: -------------------------------------------------------------------------------- 1 | Puppet::Functions.create_function(:'puppetdb::create_subsetting_resource_hash') do 2 | dispatch :create_subsetting_resource_hash do 3 | required_param 'Hash', :java_args 4 | required_param 'Any', :params 5 | end 6 | 7 | def create_subsetting_resource_hash(java_args, params) 8 | resource_hash = {} 9 | 10 | java_args.each do |k, v| 11 | item_params = { 'subsetting' => k, 'value' => (v || '') } 12 | item_params.merge!(params) 13 | resource_hash.merge!("'#{k}'" => item_params) 14 | end 15 | 16 | resource_hash 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/puppet/functions/puppetdb/flatten_java_args.rb: -------------------------------------------------------------------------------- 1 | Puppet::Functions.create_function(:'puppetdb::flatten_java_args') do 2 | dispatch :flatten_java_args do 3 | optional_param 'Hash', :java_args 4 | return_type 'String' 5 | end 6 | 7 | def flatten_java_args(java_args = {}) 8 | args = '' 9 | java_args.each { |k, v| args += "#{k}#{v} " } 10 | "\"#{args.chomp(' ')}\"" 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/puppet/provider/puppetdb_conn_validator/puppet_https.rb: -------------------------------------------------------------------------------- 1 | # See: #10295 for more details. 2 | # 3 | # This is a workaround for bug: #4248 whereby ruby files outside of the normal 4 | # provider/type path do not load until pluginsync has occured on the puppetmaster 5 | # 6 | # In this case I'm trying the relative path first, then falling back to normal 7 | # mechanisms. This should be fixed in future versions of puppet but it looks 8 | # like we'll need to maintain this for some time perhaps. 9 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', '..')) 10 | require 'puppet/util/puppetdb_validator' 11 | 12 | # This file contains a provider for the resource type `puppetdb_conn_validator`, 13 | # which validates the puppetdb connection by attempting an https connection. 14 | 15 | Puppet::Type.type(:puppetdb_conn_validator).provide(:puppet_https) do 16 | desc "A provider for the resource type `puppetdb_conn_validator`, 17 | which validates the puppetdb connection by attempting an http(s) 18 | connection to the puppetdb server. Uses the puppet SSL certificate 19 | setup from the local puppet environment to authenticate if use_ssl 20 | is set to true." 21 | 22 | # Test to see if the resource exists, returns true if it does, false if it 23 | # does not. 24 | # 25 | # Here we simply monopolize the resource API, to execute a test to see if the 26 | # database is connectable. When we return a state of `false` it triggers the 27 | # create method where we can return an error message. 28 | # 29 | # @return [bool] did the test succeed? 30 | def exists? 31 | start_time = Time.now 32 | timeout = resource[:timeout] 33 | 34 | success = validator.attempt_connection 35 | 36 | while success == false && ((Time.now - start_time) < timeout) 37 | # It can take several seconds for the puppetdb server to start up; 38 | # especially on the first install. Therefore, our first connection attempt 39 | # may fail. Here we have somewhat arbitrarily chosen to retry every 2 40 | # seconds until the configurable timeout has expired. 41 | Puppet.notice('Failed to connect to puppetdb; sleeping 2 seconds before retry') 42 | sleep 2 43 | success = validator.attempt_connection 44 | end 45 | 46 | unless success 47 | Puppet.notice("Failed to connect to puppetdb within timeout window of #{timeout} seconds; giving up.") 48 | end 49 | 50 | success 51 | end 52 | 53 | # This method is called when the exists? method returns false. 54 | # 55 | # @return [void] 56 | def create 57 | # If `#create` is called, that means that `#exists?` returned false, which 58 | # means that the connection could not be established... so we need to 59 | # cause a failure here. 60 | raise Puppet::Error, "Unable to connect to puppetdb server! (#{@validator.puppetdb_server}:#{@validator.puppetdb_port})" 61 | end 62 | 63 | # Returns the existing validator, if one exists otherwise creates a new object 64 | # from the class. 65 | # 66 | # @api private 67 | def validator 68 | @validator ||= Puppet::Util::PuppetdbValidator.new(resource[:puppetdb_server], resource[:puppetdb_port], resource[:use_ssl], resource[:test_url]) 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/puppet/type/puppetdb_conn_validator.rb: -------------------------------------------------------------------------------- 1 | Puppet::Type.newtype(:puppetdb_conn_validator) do 2 | @doc = "Verify that a connection can be successfully established between a node 3 | and the puppetdb server. Its primary use is as a precondition to 4 | prevent configuration changes from being applied if the puppetdb 5 | server cannot be reached, but it could potentially be used for other 6 | purposes such as monitoring." 7 | 8 | ensurable do 9 | defaultvalues 10 | defaultto :present 11 | end 12 | 13 | newparam(:name, namevar: true) do 14 | desc 'An arbitrary name used as the identity of the resource.' 15 | end 16 | 17 | newparam(:puppetdb_server) do 18 | desc 'The DNS name or IP address of the server where puppetdb should be running.' 19 | end 20 | 21 | newparam(:puppetdb_port) do 22 | desc 'The port that the puppetdb server should be listening on.' 23 | end 24 | 25 | newparam(:use_ssl) do 26 | desc 'Whether the connection will be attempted using https' 27 | defaultto true 28 | end 29 | 30 | newparam(:test_url) do 31 | desc 'URL to use for testing if the PuppetDB database is up' 32 | end 33 | 34 | newparam(:timeout) do 35 | desc 'The max number of seconds that the validator should wait before giving up and deciding that puppetdb is not running; defaults to 15 seconds.' 36 | defaultto 15 37 | 38 | validate do |value| 39 | # This will raise an error if the string is not convertible to an integer 40 | Integer(value) 41 | end 42 | 43 | munge do |value| 44 | Integer(value) 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/puppet/util/puppetdb_validator.rb: -------------------------------------------------------------------------------- 1 | require 'puppet/network/http_pool' 2 | 3 | # Validator class, for testing that PuppetDB is alive 4 | class Puppet::Util::PuppetdbValidator 5 | attr_reader :puppetdb_server 6 | attr_reader :puppetdb_port 7 | attr_reader :use_ssl 8 | attr_reader :test_path 9 | attr_reader :test_headers 10 | 11 | def initialize(puppetdb_server, puppetdb_port, use_ssl = true, test_path = '/pdb/meta/v1/version') 12 | @puppetdb_server = puppetdb_server 13 | @puppetdb_port = puppetdb_port 14 | @use_ssl = use_ssl 15 | @test_path = test_path 16 | @test_headers = { 'Accept' => 'application/json' } 17 | end 18 | 19 | def log_error(cause, code = nil) 20 | if code.nil? 21 | Puppet.notice "Unable to connect to puppetdb server (http#{use_ssl ? 's' : ''}://#{puppetdb_server}:#{puppetdb_port}): #{cause}" 22 | else 23 | Puppet.notice "Unable to connect to puppetdb server (http#{use_ssl ? 's' : ''}://#{puppetdb_server}:#{puppetdb_port}): [#{code}] #{cause}" 24 | end 25 | end 26 | 27 | def valid_connection_new_client? 28 | test_uri = URI("#{use_ssl ? 'https' : 'http'}://#{puppetdb_server}:#{puppetdb_port}#{test_path}") 29 | begin 30 | conn = Puppet.runtime[:http] 31 | _response = conn.get(test_uri, headers: test_headers) 32 | true 33 | rescue Puppet::HTTP::ResponseError => e 34 | log_error e.message, e.response.code 35 | false 36 | end 37 | end 38 | 39 | def valid_connection_old_client? 40 | conn = Puppet::Network::HttpPool.http_instance(puppetdb_server, puppetdb_port, use_ssl) 41 | response = conn.get(test_path, test_headers) 42 | unless response.is_a?(Net::HTTPSuccess) 43 | log_error(response.msg, response.code) 44 | return false 45 | end 46 | true 47 | end 48 | 49 | # Utility method; attempts to make an http/https connection to the puppetdb server. 50 | # This is abstracted out into a method so that it can be called multiple times 51 | # for retry attempts. 52 | # 53 | # @return true if the connection is successful, false otherwise. 54 | def attempt_connection 55 | # All that we care about is that we are able to connect successfully via 56 | # http(s), so here we're simpling hitting a somewhat arbitrary low-impact URL 57 | # on the puppetdb server. 58 | 59 | if Gem::Version.new(Puppet.version) >= Gem::Version.new('7.0.0') 60 | valid_connection_new_client? 61 | else 62 | valid_connection_old_client? 63 | end 64 | rescue StandardError => e 65 | log_error(e.message) 66 | false 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /manifests/database/default_read_grant.pp: -------------------------------------------------------------------------------- 1 | # @summary grant read permissions to $database_read_only_username by default, for new tables created by $database_username 2 | # 3 | # @api private 4 | define puppetdb::database::default_read_grant ( 5 | String[1] $database_name, 6 | String[1] $schema, 7 | String[1] $database_username, 8 | String[1] $database_read_only_username, 9 | Optional[Stdlib::Port] $database_port = undef, 10 | ) { 11 | postgresql_psql { "grant default select permission for ${database_read_only_username}": 12 | db => $database_name, 13 | port => $database_port, 14 | command => "ALTER DEFAULT PRIVILEGES 15 | FOR USER \"${database_username}\" 16 | IN SCHEMA \"${schema}\" 17 | GRANT SELECT ON TABLES 18 | TO \"${database_read_only_username}\"", 19 | unless => "SELECT 20 | ns.nspname, 21 | acl.defaclobjtype, 22 | acl.defaclacl 23 | FROM pg_default_acl acl 24 | JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid 25 | WHERE '@' || array_to_string(acl.defaclacl, '@') || '@' ~ '@(\"?)${database_read_only_username}\\1=r/(\"?)${database_username}\\2@' 26 | AND nspname = '${schema}'", 27 | } 28 | 29 | postgresql_psql { "grant default usage permission for ${database_read_only_username}": 30 | db => $database_name, 31 | port => $database_port, 32 | command => "ALTER DEFAULT PRIVILEGES 33 | FOR USER \"${database_username}\" 34 | IN SCHEMA \"${schema}\" 35 | GRANT USAGE ON SEQUENCES 36 | TO \"${database_read_only_username}\"", 37 | unless => "SELECT 38 | ns.nspname, 39 | acl.defaclobjtype, 40 | acl.defaclacl 41 | FROM pg_default_acl acl 42 | JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid 43 | WHERE '@' || array_to_string(acl.defaclacl, '@') || '@' ~ '@(\"?)${database_read_only_username}\\1=U/(\"?)${database_username}\\2@' 44 | AND nspname = '${schema}'", 45 | } 46 | 47 | postgresql_psql { "grant default execute permission for ${database_read_only_username}": 48 | db => $database_name, 49 | port => $database_port, 50 | command => "ALTER DEFAULT PRIVILEGES 51 | FOR USER \"${database_username}\" 52 | IN SCHEMA \"${schema}\" 53 | GRANT EXECUTE ON FUNCTIONS 54 | TO \"${database_read_only_username}\"", 55 | unless => "SELECT 56 | ns.nspname, 57 | acl.defaclobjtype, 58 | acl.defaclacl 59 | FROM pg_default_acl acl 60 | JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid 61 | WHERE '@' || array_to_string(acl.defaclacl, '@') || '@' ~ '@(\"?)${database_read_only_username}\\1=X/(\"?)${database_username}\\2@' 62 | AND nspname = '${schema}'", 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /manifests/database/postgresql.pp: -------------------------------------------------------------------------------- 1 | # @summary create the PuppetDB postgresql database 2 | # 3 | # @param listen_addresses 4 | # The `listen_address` is a comma-separated list of hostnames or IP addresses on 5 | # which the postgres server should listen for incoming connections. This defaults 6 | # to `localhost`. This parameter maps directly to PostgreSQL's `listen_addresses` 7 | # config option. Use a `*` to allow connections on any accessible address. 8 | # 9 | # @param puppetdb_server 10 | # Hostname or IP address to configure for SSL rules. 11 | # 12 | # @param database_name 13 | # Sets the name of the database. Defaults to `puppetdb`. 14 | # 15 | # @param database_username 16 | # Creates a user for access the database. Defaults to `puppetdb`. 17 | # 18 | # @param database_password 19 | # Sets the password for the database user above. Defaults to `puppetdb`. 20 | # 21 | # @param database_port 22 | # The port that the database server listens on. Defaults to `5432`. 23 | # 24 | # @param manage_database 25 | # If true, the PostgreSQL database will be managed by this module. Defaults to `true`. 26 | # 27 | # @param manage_server 28 | # Conditionally manages the PostgreSQL server via `postgresql::server`. Defaults 29 | # to `true`. If set to `false`, this class will create the database and user via 30 | # `postgresql::server::db` but not attempt to install or manage the server itself. 31 | # 32 | # @param manage_package_repo 33 | # If `true`, the official postgresql.org repo will be added and postgres won't 34 | # be installed from the regular repository. Defaults to `true`. 35 | # 36 | # @param postgres_version 37 | # If the postgresql.org repo is installed, you can install several versions of 38 | # postgres. Defaults to `11` with PuppetDB version 7.0.0 or newer, and `9.6` in older versions. 39 | # 40 | # @param postgresql_ssl_on 41 | # If `true`, it configures SSL connections between PuppetDB and the PostgreSQL database. 42 | # Defaults to `false`. 43 | # 44 | # @param postgresql_ssl_cert_path 45 | # Path to the Postgresql SSL certificate. 46 | # 47 | # @param postgresql_ssl_key_path 48 | # Path to the Postgresql SSL key. 49 | # 50 | # @param postgresql_ssl_ca_cert_path 51 | # Path to the Postgresql SSL CA. 52 | # 53 | # @param read_database_username 54 | # The name of the read database user to connect as. Defaults to `puppetdb-read`. This 55 | # option is supported in PuppetDB >= 1.6. 56 | # 57 | # @param read_database_password 58 | # The password for the read database user. Defaults to `puppetdb-read`. This option is 59 | # supported in PuppetDB >= 1.6. 60 | # 61 | # @param read_database_host 62 | # *This parameter must be set to use another PuppetDB instance for queries.* 63 | # 64 | # The hostname or IP address of the read database server. If set to `undef`, and 65 | # `manage_database` is set to `true`, it will use the value of the `database_host` 66 | # parameter. This option is supported in PuppetDB >= 1.6. 67 | # 68 | # @param password_sensitive 69 | # Whether password should be of Datatype Sensitive[String] 70 | # @param password_encryption 71 | # PostgreSQL password authentication method, either `md5` or `scram-sha-256` 72 | # 73 | class puppetdb::database::postgresql ( 74 | Stdlib::Host $listen_addresses = $puppetdb::params::database_host, 75 | Stdlib::Host $puppetdb_server = $puppetdb::params::puppetdb_server, 76 | String[1] $database_name = $puppetdb::params::database_name, 77 | String[1] $database_username = $puppetdb::params::database_username, 78 | Variant[String[1], Sensitive[String[1]]] $database_password = $puppetdb::params::database_password, 79 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $database_port = $puppetdb::params::database_port, 80 | Boolean $manage_database = $puppetdb::params::manage_database, 81 | Boolean $manage_server = $puppetdb::params::manage_dbserver, 82 | Boolean $manage_package_repo = $puppetdb::params::manage_pg_repo, 83 | String[2,3] $postgres_version = $puppetdb::params::postgres_version, 84 | Boolean $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, 85 | Stdlib::Absolutepath $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, 86 | Stdlib::Absolutepath $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, 87 | Stdlib::Absolutepath $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path, 88 | String[1] $read_database_username = $puppetdb::params::read_database_username, 89 | Variant[String[1], Sensitive[String[1]]] $read_database_password = $puppetdb::params::read_database_password, 90 | Optional[Stdlib::Host] $read_database_host = $puppetdb::params::read_database_host, 91 | Boolean $password_sensitive = false, 92 | Postgresql::Pg_password_encryption $password_encryption = $puppetdb::params::password_encryption, 93 | ) inherits puppetdb::params { 94 | $port = case $database_port.is_a(String) { 95 | true: { scanf($database_port, '%i')[0] } 96 | default: { $database_port } 97 | } 98 | 99 | if $manage_server { 100 | class { 'postgresql::globals': 101 | manage_package_repo => $manage_package_repo, 102 | version => $postgres_version, 103 | } 104 | # get the pg server up and running 105 | class { 'postgresql::server': 106 | ip_mask_allow_all_users => '0.0.0.0/0', 107 | listen_addresses => $listen_addresses, 108 | port => $port, 109 | password_encryption => $password_encryption, 110 | } 111 | 112 | # We need to create the ssl connection for the read user, when 113 | # manage_database is set to true, or when read_database_host is defined. 114 | # Otherwise we don't create it. 115 | if $manage_database or $read_database_host != undef { 116 | $create_read_user_rule = true 117 | } else { 118 | $create_read_user_rule = false 119 | } 120 | 121 | # configure PostgreSQL communication with Puppet Agent SSL certificates if 122 | # postgresql_ssl_on is set to true 123 | if $postgresql_ssl_on { 124 | class { 'puppetdb::database::ssl_configuration': 125 | database_name => $database_name, 126 | database_username => $database_username, 127 | read_database_username => $read_database_username, 128 | puppetdb_server => $puppetdb_server, 129 | postgresql_ssl_key_path => $postgresql_ssl_key_path, 130 | postgresql_ssl_cert_path => $postgresql_ssl_cert_path, 131 | postgresql_ssl_ca_cert_path => $postgresql_ssl_ca_cert_path, 132 | postgres_version => $postgres_version, 133 | create_read_user_rule => $create_read_user_rule, 134 | } 135 | } 136 | 137 | # Only install pg_trgm extension, if database it is actually managed by the module 138 | if $manage_database { 139 | # get the pg contrib to use pg_trgm extension 140 | class { 'postgresql::server::contrib': } 141 | 142 | postgresql::server::extension { 'pg_trgm': 143 | database => $database_name, 144 | require => Postgresql::Server::Db[$database_name], 145 | port => $port, 146 | } 147 | } 148 | } 149 | 150 | if $manage_database { 151 | # create the puppetdb database 152 | postgresql::server::db { $database_name: 153 | user => $database_username, 154 | password => $database_password, 155 | encoding => 'UTF8', 156 | locale => 'en_US.UTF-8', 157 | grant => 'all', 158 | port => $port, 159 | } 160 | 161 | -> postgresql_psql { 'revoke all access on public schema': 162 | db => $database_name, 163 | port => $port, 164 | command => 'REVOKE CREATE ON SCHEMA public FROM public', 165 | unless => "SELECT * FROM 166 | (SELECT has_schema_privilege('public', 'public', 'create') can_create) privs 167 | WHERE privs.can_create=false", 168 | } 169 | 170 | -> postgresql_psql { "grant all permissions to ${database_username}": 171 | db => $database_name, 172 | port => $port, 173 | command => "GRANT CREATE ON SCHEMA public TO \"${database_username}\"", 174 | unless => "SELECT * FROM 175 | (SELECT has_schema_privilege('${database_username}', 'public', 'create') can_create) privs 176 | WHERE privs.can_create=true", 177 | } 178 | 179 | -> puppetdb::database::read_only_user { $read_database_username: 180 | read_database_username => $read_database_username, 181 | database_name => $database_name, 182 | password_hash => postgresql::postgresql_password( 183 | $read_database_username, $read_database_password, $password_sensitive, $password_encryption), 184 | database_owner => $database_username, 185 | database_port => $port, 186 | password_encryption => $password_encryption, 187 | } 188 | 189 | -> postgresql_psql { "grant ${read_database_username} role to ${database_username}": 190 | db => $database_name, 191 | port => $port, 192 | command => "GRANT \"${read_database_username}\" TO \"${database_username}\"", 193 | unless => "SELECT oid, rolname FROM pg_roles WHERE 194 | pg_has_role( '${database_username}', oid, 'member') and rolname = '${read_database_username}'"; 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /manifests/database/postgresql_ssl_rules.pp: -------------------------------------------------------------------------------- 1 | # @summary manage the pg_ident.conf and pg_hba.conf files 2 | # 3 | # @api private 4 | define puppetdb::database::postgresql_ssl_rules ( 5 | String[1] $database_name, 6 | String[1] $database_username, 7 | String[2,3] $postgres_version, 8 | String[1] $puppetdb_server, 9 | ) { 10 | $identity_map_key = "${database_name}-${database_username}-map" 11 | 12 | $clientcert_value = Float($postgres_version) >= 12.0 ? { 13 | true => 'verify-full', 14 | false => '1', 15 | } 16 | 17 | postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv4)": 18 | type => 'hostssl', 19 | database => $database_name, 20 | user => $database_username, 21 | address => '0.0.0.0/0', 22 | auth_method => 'cert', 23 | order => 0, 24 | auth_option => "map=${identity_map_key} clientcert=${clientcert_value}", 25 | } 26 | 27 | postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv6)": 28 | type => 'hostssl', 29 | database => $database_name, 30 | user => $database_username, 31 | address => '::0/0', 32 | auth_method => 'cert', 33 | order => 0, 34 | auth_option => "map=${identity_map_key} clientcert=${clientcert_value}", 35 | } 36 | 37 | postgresql::server::pg_ident_rule { "Map the SSL certificate of the server as a ${database_username} user": 38 | map_name => $identity_map_key, 39 | system_username => $puppetdb_server, 40 | database_username => $database_username, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /manifests/database/read_grant.pp: -------------------------------------------------------------------------------- 1 | # @summary grant read-only permissions to $database_read_only_username for all objects in $schema of $database_name 2 | # 3 | # @api private 4 | define puppetdb::database::read_grant ( 5 | String[1] $database_name, 6 | String[1] $schema, 7 | String[1] $database_read_only_username, 8 | Optional[Stdlib::Port] $database_port = undef, 9 | ) { 10 | postgresql_psql { "grant select permission for ${database_read_only_username}": 11 | db => $database_name, 12 | port => $database_port, 13 | command => "GRANT SELECT 14 | ON ALL TABLES IN SCHEMA \"${schema}\" 15 | TO \"${database_read_only_username}\"", 16 | unless => "SELECT * FROM ( 17 | SELECT COUNT(*) 18 | FROM pg_tables 19 | WHERE schemaname='public' 20 | AND has_table_privilege('${database_read_only_username}', schemaname || '.' || tablename, 'SELECT')=false 21 | ) x 22 | WHERE x.count=0", 23 | } 24 | 25 | postgresql_psql { "grant usage permission for ${database_read_only_username}": 26 | db => $database_name, 27 | port => $database_port, 28 | command => "GRANT USAGE 29 | ON ALL SEQUENCES IN SCHEMA \"${schema}\" 30 | TO \"${database_read_only_username}\"", 31 | unless => "SELECT * FROM ( 32 | SELECT COUNT(*) 33 | FROM information_schema.sequences 34 | WHERE sequence_schema='public' 35 | AND has_sequence_privilege('${database_read_only_username}', sequence_schema || '.' || sequence_name, 'USAGE')=false 36 | ) x 37 | WHERE x.count=0", 38 | } 39 | 40 | postgresql_psql { "grant execution permission for ${database_read_only_username}": 41 | db => $database_name, 42 | port => $database_port, 43 | command => "GRANT EXECUTE 44 | ON ALL FUNCTIONS IN SCHEMA \"${schema}\" 45 | TO \"${database_read_only_username}\"", 46 | unless => "SELECT * FROM ( 47 | SELECT COUNT(*) 48 | FROM pg_catalog.pg_proc p 49 | LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace 50 | WHERE n.nspname='public' 51 | AND has_function_privilege('${database_read_only_username}', p.oid, 'EXECUTE')=false 52 | ) x 53 | WHERE x.count=0", 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /manifests/database/read_only_user.pp: -------------------------------------------------------------------------------- 1 | # @summary manage the creation of a read-only postgres users 2 | # 3 | # In particular, it manages the necessary grants to enable such a user 4 | # to have read-only access to any existing objects as well as changes 5 | # the default access privileges so read-only access is maintained when 6 | # new objects are created by the $database_owner 7 | # 8 | # @param read_database_username 9 | # The name of the postgres read only user. 10 | # @param database_name 11 | # The name of the database to grant access to. 12 | # @param database_owner 13 | # The user which owns the database (i.e. the migration user for the database). 14 | # @param password_hash 15 | # The value of $_database_password in app_database. 16 | # @param password_encryption 17 | # The hash method for postgresql password, since PostgreSQL 14 default is `scram-sha-256`. 18 | # 19 | # @api private 20 | define puppetdb::database::read_only_user ( 21 | String[1] $read_database_username, 22 | String[1] $database_name, 23 | String[1] $database_owner, 24 | Variant[String[1], Boolean, Sensitive[String[1]]] $password_hash = false, 25 | Optional[Stdlib::Port] $database_port = undef, 26 | Optional[Postgresql::Pg_password_encryption] $password_encryption = undef, 27 | ) { 28 | postgresql::server::role { $read_database_username: 29 | password_hash => $password_hash, 30 | port => $database_port, 31 | hash => $password_encryption, 32 | } 33 | 34 | -> postgresql::server::database_grant { "${database_name} grant connection permission to ${read_database_username}": 35 | privilege => 'CONNECT', 36 | db => $database_name, 37 | role => $read_database_username, 38 | port => $database_port, 39 | } 40 | 41 | -> puppetdb::database::default_read_grant { 42 | "${database_name} grant read permission on new objects from ${database_owner} to ${read_database_username}": 43 | database_username => $database_owner, 44 | database_read_only_username => $read_database_username, 45 | database_name => $database_name, 46 | database_port => $database_port, 47 | schema => 'public', 48 | } 49 | 50 | -> puppetdb::database::read_grant { 51 | "${database_name} grant read-only permission on existing objects to ${read_database_username}": 52 | database_read_only_username => $read_database_username, 53 | database_name => $database_name, 54 | database_port => $database_port, 55 | schema => 'public', 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /manifests/database/ssl_configuration.pp: -------------------------------------------------------------------------------- 1 | # @summary configure SSL for the PuppetDB postgresql database 2 | # 3 | # @api private 4 | class puppetdb::database::ssl_configuration ( 5 | String[1] $database_name = $puppetdb::params::database_name, 6 | String[1] $database_username = $puppetdb::params::database_username, 7 | String[1] $read_database_username = $puppetdb::params::read_database_username, 8 | Optional[Stdlib::Host] $read_database_host = $puppetdb::params::read_database_host, 9 | String[1] $puppetdb_server = $puppetdb::params::puppetdb_server, 10 | Stdlib::Absolutepath $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, 11 | Stdlib::Absolutepath $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, 12 | Stdlib::Absolutepath $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path, 13 | String[2,3] $postgres_version = $puppetdb::params::postgres_version, 14 | Boolean $create_read_user_rule = false, 15 | ) inherits puppetdb::params { 16 | File { 17 | ensure => present, 18 | owner => 'postgres', 19 | mode => '0600', 20 | require => Package['postgresql-server'], 21 | } 22 | 23 | file { 'postgres private key': 24 | path => "${postgresql::server::datadir}/server.key", 25 | source => $postgresql_ssl_key_path, 26 | } 27 | 28 | file { 'postgres public key': 29 | path => "${postgresql::server::datadir}/server.crt", 30 | source => $postgresql_ssl_cert_path, 31 | } 32 | 33 | postgresql::server::config_entry { 'ssl': 34 | ensure => present, 35 | value => 'on', 36 | require => [File['postgres private key'], File['postgres public key']], 37 | } 38 | 39 | postgresql::server::config_entry { 'ssl_cert_file': 40 | ensure => present, 41 | value => "${postgresql::server::datadir}/server.crt", 42 | require => [File['postgres private key'], File['postgres public key']], 43 | } 44 | 45 | postgresql::server::config_entry { 'ssl_key_file': 46 | ensure => present, 47 | value => "${postgresql::server::datadir}/server.key", 48 | require => [File['postgres private key'], File['postgres public key']], 49 | } 50 | 51 | postgresql::server::config_entry { 'ssl_ca_file': 52 | ensure => present, 53 | value => $postgresql_ssl_ca_cert_path, 54 | require => [File['postgres private key'], File['postgres public key']], 55 | } 56 | 57 | puppetdb::database::postgresql_ssl_rules { "Configure postgresql ssl rules for ${database_username}": 58 | database_name => $database_name, 59 | database_username => $database_username, 60 | postgres_version => $postgres_version, 61 | puppetdb_server => $puppetdb_server, 62 | } 63 | 64 | if $create_read_user_rule { 65 | puppetdb::database::postgresql_ssl_rules { "Configure postgresql ssl rules for ${read_database_username}": 66 | database_name => $database_name, 67 | database_username => $read_database_username, 68 | postgres_version => $postgres_version, 69 | puppetdb_server => $puppetdb_server, 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /manifests/globals.pp: -------------------------------------------------------------------------------- 1 | # @summary global configuration class for PuppetDB 2 | # 3 | # @param version 4 | # The version of the `puppetdb` package that should be installed. You may specify 5 | # an explicit version number, 'present', or 'latest' (defaults to 'present'). 6 | # 7 | # @param puppet_confdir 8 | # Puppet's config directory. Defaults to `/etc/puppetlabs/puppet`. 9 | # 10 | class puppetdb::globals ( 11 | String[1] $version = 'present', 12 | Stdlib::Absolutepath $puppet_confdir = $settings::confdir, 13 | ) { 14 | if !(fact('os.family') in ['RedHat', 'Suse', 'Archlinux', 'Debian', 'OpenBSD', 'FreeBSD']) { 15 | fail("${module_name} does not support your osfamily ${fact('os.family')}") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /manifests/master/puppetdb_conf.pp: -------------------------------------------------------------------------------- 1 | # @summary manage the puppetdb.conf file on the puppet primary 2 | # 3 | # @api private 4 | class puppetdb::master::puppetdb_conf ( 5 | Stdlib::Host $server = 'localhost', 6 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $port = '8081', 7 | Stdlib::Absolutepath $puppet_confdir = $puppetdb::params::puppet_confdir, 8 | Boolean $soft_write_failure = $puppetdb::disable_ssl ? { 9 | true => true, 10 | default => false, 11 | }, 12 | Boolean $legacy_terminus = $puppetdb::params::terminus_package ? { 13 | /(puppetdb-terminus)/ => true, 14 | default => false, 15 | }, 16 | ) inherits puppetdb::params { 17 | Ini_setting { 18 | ensure => present, 19 | section => 'main', 20 | path => "${puppet_confdir}/puppetdb.conf", 21 | } 22 | 23 | if $legacy_terminus { 24 | ini_setting { 'puppetdbserver': 25 | setting => 'server', 26 | value => $server, 27 | } 28 | ini_setting { 'puppetdbport': 29 | setting => 'port', 30 | value => $port, 31 | } 32 | } else { 33 | ini_setting { 'puppetdbserver_urls': 34 | setting => 'server_urls', 35 | value => "https://${server}:${port}/", 36 | } 37 | } 38 | 39 | ini_setting { 'soft_write_failure': 40 | setting => 'soft_write_failure', 41 | value => $soft_write_failure, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /manifests/master/report_processor.pp: -------------------------------------------------------------------------------- 1 | # @summary manage the installation of the report processor on the primary 2 | # 3 | # @api private 4 | class puppetdb::master::report_processor ( 5 | Stdlib::Absolutepath $puppet_conf = $puppetdb::params::puppet_conf, 6 | Boolean $masterless = $puppetdb::params::masterless, 7 | Boolean $enable = false 8 | ) inherits puppetdb::params { 9 | if $masterless { 10 | $puppet_conf_section = 'main' 11 | } else { 12 | $puppet_conf_section = 'master' 13 | } 14 | 15 | $puppetdb_ensure = $enable ? { 16 | true => present, 17 | default => absent, 18 | } 19 | 20 | ini_subsetting { 'puppet.conf/reports/puppetdb': 21 | ensure => $puppetdb_ensure, 22 | path => $puppet_conf, 23 | section => $puppet_conf_section, 24 | setting => 'reports', 25 | subsetting => 'puppetdb', 26 | subsetting_separator => ',', 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /manifests/master/routes.pp: -------------------------------------------------------------------------------- 1 | # @summary manages the routes configuration file on the master 2 | # 3 | # @api private 4 | class puppetdb::master::routes ( 5 | Stdlib::Absolutepath $puppet_confdir = $puppetdb::params::puppet_confdir, 6 | Boolean $masterless = $puppetdb::params::masterless, 7 | Optional[Hash] $routes = undef, 8 | ) inherits puppetdb::params { 9 | if $masterless { 10 | $routes_real = { 11 | 'apply' => { 12 | 'catalog' => { 13 | 'terminus' => 'compiler', 14 | 'cache' => 'puppetdb', 15 | }, 16 | 'facts' => { 17 | 'terminus' => 'facter', 18 | 'cache' => 'puppetdb_apply', 19 | }, 20 | }, 21 | } 22 | } elsif $routes { 23 | $routes_real = $routes 24 | } else { 25 | if (defined('$serverversion')) and (versioncmp($serverversion, '7.0') >= 0) { 26 | $default_fact_cache = 'json' 27 | } else { 28 | $default_fact_cache = 'yaml' 29 | } 30 | $routes_real = { 31 | 'master' => { 32 | 'facts' => { 33 | 'terminus' => 'puppetdb', 34 | 'cache' => $default_fact_cache, 35 | }, 36 | }, 37 | } 38 | } 39 | 40 | # TODO: this will overwrite any existing routes.yaml; 41 | # to handle this properly we should just be ensuring 42 | # that the proper settings exist, but to do that we'd need 43 | # to parse the yaml file and rewrite it, dealing with indentation issues etc 44 | # I don't think there is currently a puppet module or an augeas lens for 45 | # this. 46 | file { "${puppet_confdir}/routes.yaml": 47 | ensure => file, 48 | content => template('puppetdb/routes.yaml.erb'), 49 | mode => '0644', 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /manifests/master/storeconfigs.pp: -------------------------------------------------------------------------------- 1 | # @summary configure the puppet master to enable storeconfigs and to use puppetdb as the storeconfigs backend 2 | # 3 | # @api private 4 | class puppetdb::master::storeconfigs ( 5 | Stdlib::Absolutepath $puppet_conf = $puppetdb::params::puppet_conf, 6 | Boolean $masterless = $puppetdb::params::masterless, 7 | Boolean $enable = true, 8 | ) inherits puppetdb::params { 9 | if $masterless { 10 | $puppet_conf_section = 'main' 11 | } else { 12 | $puppet_conf_section = 'master' 13 | } 14 | 15 | $storeconfigs_ensure = $enable ? { 16 | true => present, 17 | default => absent, 18 | } 19 | 20 | Ini_setting { 21 | section => $puppet_conf_section, 22 | path => $puppet_conf, 23 | ensure => $storeconfigs_ensure, 24 | } 25 | 26 | ini_setting { "puppet.conf/${puppet_conf_section}/storeconfigs": 27 | setting => 'storeconfigs', 28 | value => true, 29 | } 30 | 31 | ini_setting { "puppet.conf/${puppet_conf_section}/storeconfigs_backend": 32 | setting => 'storeconfigs_backend', 33 | value => 'puppetdb', 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /manifests/params.pp: -------------------------------------------------------------------------------- 1 | # @summary default configuration settings 2 | # 3 | # @api private 4 | class puppetdb::params inherits puppetdb::globals { 5 | $listen_address = 'localhost' 6 | $listen_port = '8080' 7 | $disable_cleartext = false 8 | $open_listen_port = false 9 | $ssl_listen_address = '0.0.0.0' 10 | $ssl_listen_port = '8081' 11 | $ssl_protocols = undef 12 | $disable_ssl = false 13 | $cipher_suites = undef 14 | $open_ssl_listen_port = false 15 | $postgres_listen_addresses = 'localhost' 16 | 17 | $puppetdb_version = $puppetdb::globals::version 18 | $manage_dbserver = true 19 | $manage_database = true 20 | 21 | if fact('os.family') =~ /RedHat|Debian/ { 22 | $manage_pg_repo = true 23 | } else { 24 | $manage_pg_repo = false 25 | } 26 | 27 | $postgres_version = '14' 28 | 29 | $puppetdb_major_version = $puppetdb_version ? { 30 | 'latest' => '8', 31 | 'present' => '8', 32 | default => $puppetdb_version.split('.')[0], 33 | } 34 | 35 | $database_host = 'localhost' 36 | $database_port = '5432' 37 | $database_name = 'puppetdb' 38 | $database_username = 'puppetdb' 39 | $database_password = 'puppetdb' 40 | $manage_db_password = true 41 | $jdbc_ssl_properties = '' 42 | $database_validate = true 43 | $database_max_pool_size = undef 44 | $puppetdb_server = fact('networking.fqdn') 45 | $password_encryption = 'scram-sha-256' 46 | 47 | # These settings manage the various auto-deactivation and auto-purge settings 48 | $node_ttl = '7d' 49 | $node_purge_ttl = '14d' 50 | $report_ttl = '14d' 51 | 52 | $facts_blacklist = undef 53 | 54 | $gc_interval = '60' 55 | $node_purge_gc_batch_limit = '25' 56 | 57 | $conn_max_age = '60' 58 | $conn_lifetime = '0' 59 | 60 | $max_threads = undef 61 | $migrate = true 62 | 63 | # These settings are for the read database 64 | $read_database_host = undef 65 | $read_database_port = '5432' 66 | $read_database_name = 'puppetdb' 67 | $read_database_username = 'puppetdb-read' 68 | $read_database_password = 'puppetdb-read' 69 | $manage_read_db_password = true 70 | $read_database_jdbc_ssl_properties = '' 71 | $read_database_validate = true 72 | $read_conn_max_age = '60' 73 | $read_conn_lifetime = '0' 74 | $read_database_max_pool_size = undef 75 | 76 | $manage_firewall = true 77 | $java_args = {} 78 | $merge_default_java_args = true 79 | 80 | $puppetdb_service = 'puppetdb' 81 | $masterless = false 82 | 83 | if !($puppetdb_version in ['latest','present','absent']) and versioncmp($puppetdb_version, '3.0.0') < 0 { 84 | case fact('os.family') { 85 | 'RedHat', 'Suse', 'Archlinux','Debian': { 86 | $puppetdb_package = 'puppetdb' 87 | $terminus_package = 'puppetdb-terminus' 88 | $etcdir = '/etc/puppetdb' 89 | $vardir = '/var/lib/puppetdb' 90 | $puppet_confdir = pick($puppetdb::globals::puppet_confdir,'/etc/puppet') 91 | $puppet_service_name = 'puppetmaster' 92 | } 93 | 'OpenBSD': { 94 | $puppetdb_package = 'puppetdb' 95 | $terminus_package = 'puppetdb-terminus' 96 | $etcdir = '/etc/puppetdb' 97 | $vardir = '/var/db/puppetdb' 98 | $puppet_confdir = pick($puppetdb::globals::puppet_confdir,'/etc/puppet') 99 | $puppet_service_name = 'puppetmasterd' 100 | } 101 | 'FreeBSD': { 102 | $puppetdb_package = inline_epp('puppetdb<%= $puppetdb::params::puppetdb_major_version %>') 103 | $terminus_package = inline_epp('puppetdb-terminus<%= $puppetdb::params::puppetdb_major_version %>') 104 | $etcdir = '/usr/local/etc/puppetdb' 105 | $vardir = '/var/db/puppetdb' 106 | $puppet_confdir = pick($puppetdb::globals::puppet_confdir,'/usr/local/etc/puppet') 107 | $puppet_service_name = 'puppetmaster' 108 | } 109 | default: { 110 | fail("The fact 'os.family' is set to ${fact('os.family')} which is not supported by the puppetdb module.") 111 | } 112 | } 113 | $test_url = '/v3/version' 114 | } else { 115 | case fact('os.family') { 116 | 'RedHat', 'Suse', 'Archlinux','Debian': { 117 | $puppetdb_package = 'puppetdb' 118 | $terminus_package = 'puppetdb-termini' 119 | $etcdir = '/etc/puppetlabs/puppetdb' 120 | $puppet_confdir = pick($puppetdb::globals::puppet_confdir,'/etc/puppetlabs/puppet') 121 | $puppet_service_name = 'puppetserver' 122 | $vardir = '/opt/puppetlabs/server/data/puppetdb' 123 | } 124 | 'OpenBSD': { 125 | $puppetdb_package = 'puppetdb' 126 | $terminus_package = 'puppetdb-termini' 127 | $etcdir = '/etc/puppetlabs/puppetdb' 128 | $puppet_confdir = pick($puppetdb::globals::puppet_confdir,'/etc/puppetlabs/puppet') 129 | $puppet_service_name = undef 130 | $vardir = '/opt/puppetlabs/server/data/puppetdb' 131 | } 132 | 'FreeBSD': { 133 | $puppetdb_package = inline_epp('puppetdb<%= $puppetdb::params::puppetdb_major_version %>') 134 | $terminus_package = inline_epp('puppetdb-terminus<%= $puppetdb::params::puppetdb_major_version %>') 135 | $etcdir = '/usr/local/etc/puppetdb' 136 | $puppet_confdir = pick($puppetdb::globals::puppet_confdir,'/usr/local/etc/puppet') 137 | $puppet_service_name = 'puppetserver' 138 | $vardir = '/var/db/puppetdb' 139 | } 140 | default: { 141 | fail("The fact 'os.family' is set to ${fact('os.family')} which is not supported by the puppetdb module.") 142 | } 143 | } 144 | $test_url = '/pdb/meta/v1/version' 145 | } 146 | 147 | $confdir = "${etcdir}/conf.d" 148 | $ssl_dir = "${etcdir}/ssl" 149 | 150 | case fact('os.family') { 151 | 'RedHat', 'Suse', 'Archlinux': { 152 | $puppetdb_user = 'puppetdb' 153 | $puppetdb_group = 'puppetdb' 154 | $puppetdb_initconf = '/etc/sysconfig/puppetdb' 155 | } 156 | 'Debian': { 157 | $puppetdb_user = 'puppetdb' 158 | $puppetdb_group = 'puppetdb' 159 | $puppetdb_initconf = '/etc/default/puppetdb' 160 | } 161 | 'OpenBSD': { 162 | $puppetdb_user = '_puppetdb' 163 | $puppetdb_group = '_puppetdb' 164 | $puppetdb_initconf = undef 165 | } 166 | 'FreeBSD': { 167 | $puppetdb_user = 'puppetdb' 168 | $puppetdb_group = 'puppetdb' 169 | $puppetdb_initconf = undef 170 | } 171 | default: { 172 | fail("The fact 'os.family' is set to ${fact('os.family')} which is not supported by the puppetdb module.") 173 | } 174 | } 175 | 176 | $puppet_conf = "${puppet_confdir}/puppet.conf" 177 | $puppetdb_startup_timeout = 120 178 | $puppetdb_service_status = 'running' 179 | 180 | $command_threads = undef 181 | $concurrent_writes = undef 182 | $store_usage = undef 183 | $temp_usage = undef 184 | $disable_update_checking = undef 185 | 186 | # reports of failed actions: https://puppet.com/docs/puppetdb/5.2/maintain_and_tune.html#clean-up-the-dead-letter-office 187 | $automatic_dlo_cleanup = true 188 | # any value for a systemd timer is valid: https://www.freedesktop.org/software/systemd/man/systemd.time.html 189 | $cleanup_timer_interval = "*-*-* ${fqdn_rand(24)}:${fqdn_rand(60)}:00" 190 | $dlo_max_age = 90 191 | 192 | # certificates used for PostgreSQL SSL configuration. Puppet certificates are used 193 | $postgresql_ssl_on = false 194 | $postgresql_ssl_folder = "${puppet_confdir}/ssl" 195 | $postgresql_ssl_cert_path = "${postgresql_ssl_folder}/certs/${trusted['certname']}.pem" 196 | $postgresql_ssl_key_path = "${postgresql_ssl_folder}/private_keys/${trusted['certname']}.pem" 197 | $postgresql_ssl_ca_cert_path = "${postgresql_ssl_folder}/certs/ca.pem" 198 | 199 | # certificates used for Jetty configuration 200 | $ssl_set_cert_paths = false 201 | $ssl_cert_path = "${ssl_dir}/public.pem" 202 | $ssl_key_path = "${ssl_dir}/private.pem" 203 | $ssl_ca_cert_path = "${ssl_dir}/ca.pem" 204 | $ssl_deploy_certs = false 205 | $ssl_key = undef 206 | $ssl_cert = undef 207 | $ssl_ca_cert = undef 208 | 209 | # certificate used by PuppetDB SSL Configuration 210 | $ssl_key_pk8_path = regsubst($ssl_key_path, '.pem', '.pk8') 211 | 212 | $certificate_whitelist_file = "${etcdir}/certificate-whitelist" 213 | # the default is free access for now 214 | $certificate_whitelist = [] 215 | # change to this to only allow access by the puppet master by default: 216 | #$certificate_whitelist = [ $::servername ] 217 | 218 | # Get the parameter name for the database connection pool tuning 219 | if $puppetdb_version in ['latest','present'] or versioncmp($puppetdb_version, '4.0.0') >= 0 { 220 | $database_max_pool_size_setting_name = 'maximum-pool-size' 221 | } elsif versioncmp($puppetdb_version, '2.8.0') >= 0 { 222 | $database_max_pool_size_setting_name = 'partition-conn-max' 223 | } else { 224 | $database_max_pool_size_setting_name = undef 225 | } 226 | 227 | # java binary path for PuppetDB. If undef, default will be used. 228 | $java_bin = undef 229 | } 230 | -------------------------------------------------------------------------------- /manifests/server/command_processing.pp: -------------------------------------------------------------------------------- 1 | # @summary manage puppetdb config ini 2 | # 3 | # @api private 4 | class puppetdb::server::command_processing ( 5 | Stdlib::Absolutepath $confdir = $puppetdb::params::confdir, 6 | Optional[Integer[0]] $command_threads = $puppetdb::params::command_threads, 7 | Optional[Integer[0]] $concurrent_writes = $puppetdb::params::concurrent_writes, 8 | Optional[Integer[0]] $store_usage = $puppetdb::params::store_usage, 9 | Optional[Integer[0]] $temp_usage = $puppetdb::params::temp_usage, 10 | ) inherits puppetdb::params { 11 | $config_ini = "${confdir}/config.ini" 12 | 13 | # Set the defaults 14 | Ini_setting { 15 | path => $config_ini, 16 | ensure => 'present', 17 | section => 'command-processing', 18 | require => File[$config_ini], 19 | } 20 | 21 | if $command_threads { 22 | ini_setting { 'puppetdb_command_processing_threads': 23 | setting => 'threads', 24 | value => $command_threads, 25 | } 26 | } else { 27 | ini_setting { 'puppetdb_command_processing_threads': 28 | ensure => 'absent', 29 | setting => 'threads', 30 | } 31 | } 32 | 33 | if $concurrent_writes { 34 | ini_setting { 'puppetdb_command_processing_concurrent_writes': 35 | setting => 'concurrent-writes', 36 | value => $concurrent_writes, 37 | } 38 | } else { 39 | ini_setting { 'puppetdb_command_processing_concurrent_writes': 40 | ensure => 'absent', 41 | setting => 'concurrent-writes', 42 | } 43 | } 44 | 45 | if $store_usage { 46 | ini_setting { 'puppetdb_command_processing_store_usage': 47 | setting => 'store-usage', 48 | value => $store_usage, 49 | } 50 | } else { 51 | ini_setting { 'puppetdb_command_processing_store_usage': 52 | ensure => 'absent', 53 | setting => 'store-usage', 54 | } 55 | } 56 | 57 | if $temp_usage { 58 | ini_setting { 'puppetdb_command_processing_temp_usage': 59 | setting => 'temp-usage', 60 | value => $temp_usage, 61 | } 62 | } else { 63 | ini_setting { 'puppetdb_command_processing_temp_usage': 64 | ensure => 'absent', 65 | setting => 'temp-usage', 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /manifests/server/database.pp: -------------------------------------------------------------------------------- 1 | # @summary manage puppetdb database ini 2 | # 3 | # @api private 4 | class puppetdb::server::database ( 5 | Stdlib::Host $database_host = $puppetdb::params::database_host, 6 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $database_port = $puppetdb::params::database_port, 7 | String[1] $database_username = $puppetdb::params::database_username, 8 | Variant[String[1], Sensitive[String[1]]] $database_password = $puppetdb::params::database_password, 9 | String[1] $database_name = $puppetdb::params::database_name, 10 | Boolean $manage_db_password = $puppetdb::params::manage_db_password, 11 | Variant[String[0], Boolean[false]] $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, 12 | Boolean $database_validate = $puppetdb::params::database_validate, 13 | Pattern[/\A[0-9dhms]+\Z/] $node_ttl = $puppetdb::params::node_ttl, 14 | Pattern[/\A[0-9dhms]+\Z/] $node_purge_ttl = $puppetdb::params::node_purge_ttl, 15 | Pattern[/\A[0-9dhms]+\Z/] $report_ttl = $puppetdb::params::report_ttl, 16 | Optional[Array] $facts_blacklist = $puppetdb::params::facts_blacklist, 17 | Variant[Integer[0], Pattern[/\A[0-9]+\Z/]] $gc_interval = $puppetdb::params::gc_interval, 18 | Variant[Integer[0], Pattern[/\A[0-9]+\Z/]] $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, 19 | Variant[Integer[0], Pattern[/\A[0-9]+\Z/]] $conn_max_age = $puppetdb::params::conn_max_age, 20 | Variant[Integer[0], Pattern[/\A[0-9]+\Z/]] $conn_lifetime = $puppetdb::params::conn_lifetime, 21 | Stdlib::Absolutepath $confdir = $puppetdb::params::confdir, 22 | String[1] $puppetdb_group = $puppetdb::params::puppetdb_group, 23 | Optional[Variant[Integer[0], Enum['absent'], Pattern[/\A[0-9]+\Z/]]] $database_max_pool_size = $puppetdb::params::database_max_pool_size, 24 | Boolean $migrate = $puppetdb::params::migrate, 25 | Boolean $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, 26 | Stdlib::Absolutepath $ssl_cert_path = $puppetdb::params::ssl_cert_path, 27 | Stdlib::Absolutepath $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, 28 | Stdlib::Absolutepath $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path 29 | ) inherits puppetdb::params { 30 | if str2bool($database_validate) { 31 | # Validate the database connection. If we can't connect, we want to fail 32 | # and skip the rest of the configuration, so that we don't leave puppetdb 33 | # in a broken state. 34 | # 35 | # NOTE: 36 | # Because of a limitation in the postgres module this will break with 37 | # a duplicate declaration if read and write database host+name are the 38 | # same. 39 | class { 'puppetdb::server::validate_db': 40 | database_host => $database_host, 41 | database_port => $database_port, 42 | database_username => $database_username, 43 | database_password => $database_password, 44 | database_name => $database_name, 45 | } 46 | } 47 | 48 | $database_ini = "${confdir}/database.ini" 49 | 50 | file { $database_ini: 51 | ensure => file, 52 | owner => 'root', 53 | group => $puppetdb_group, 54 | mode => '0640', 55 | } 56 | 57 | $file_require = File[$database_ini] 58 | $ini_setting_require = str2bool($database_validate) ? { 59 | false => $file_require, 60 | default => [$file_require, Class['puppetdb::server::validate_db']], 61 | } 62 | # Set the defaults 63 | Ini_setting { 64 | path => $database_ini, 65 | ensure => present, 66 | section => 'database', 67 | require => $ini_setting_require, 68 | } 69 | 70 | if !empty($jdbc_ssl_properties) { 71 | $database_suffix = $jdbc_ssl_properties 72 | } 73 | else { 74 | $database_suffix = '' 75 | } 76 | 77 | $subname_default = "//${database_host}:${database_port}/${database_name}${database_suffix}" 78 | 79 | if $postgresql_ssl_on and !empty($jdbc_ssl_properties) { 80 | fail("Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!") 81 | } 82 | 83 | if $postgresql_ssl_on { 84 | $subname = @("EOT"/L) 85 | ${subname_default}?\ 86 | ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ 87 | sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ 88 | sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ 89 | | EOT 90 | } else { 91 | $subname = $subname_default 92 | } 93 | 94 | ini_setting { 'puppetdb_psdatabase_username': 95 | setting => 'username', 96 | value => $database_username, 97 | } 98 | 99 | if $database_password != undef and $manage_db_password { 100 | ini_setting { 'puppetdb_psdatabase_password': 101 | setting => 'password', 102 | value => $database_password, 103 | show_diff => false, 104 | } 105 | } 106 | 107 | ini_setting { 'puppetdb_pgs': 108 | setting => 'syntax_pgs', 109 | value => true, 110 | } 111 | 112 | ini_setting { 'puppetdb_subname': 113 | setting => 'subname', 114 | value => $subname, 115 | } 116 | 117 | ini_setting { 'puppetdb_gc_interval': 118 | setting => 'gc-interval', 119 | value => $gc_interval, 120 | } 121 | 122 | ini_setting { 'puppetdb_node_purge_gc_batch_limit': 123 | setting => 'node-purge-gc-batch-limit', 124 | value => $node_purge_gc_batch_limit, 125 | } 126 | 127 | ini_setting { 'puppetdb_node_ttl': 128 | setting => 'node-ttl', 129 | value => $node_ttl, 130 | } 131 | 132 | ini_setting { 'puppetdb_node_purge_ttl': 133 | setting => 'node-purge-ttl', 134 | value => $node_purge_ttl, 135 | } 136 | 137 | ini_setting { 'puppetdb_report_ttl': 138 | setting => 'report-ttl', 139 | value => $report_ttl, 140 | } 141 | 142 | ini_setting { 'puppetdb_conn_max_age': 143 | setting => 'conn-max-age', 144 | value => $conn_max_age, 145 | } 146 | 147 | ini_setting { 'puppetdb_conn_lifetime': 148 | setting => 'conn-lifetime', 149 | value => $conn_lifetime, 150 | } 151 | 152 | ini_setting { 'puppetdb_migrate': 153 | setting => 'migrate', 154 | value => $migrate, 155 | } 156 | 157 | if $puppetdb::params::database_max_pool_size_setting_name != undef { 158 | if $database_max_pool_size == 'absent' { 159 | ini_setting { 'puppetdb_database_max_pool_size': 160 | ensure => absent, 161 | setting => $puppetdb::params::database_max_pool_size_setting_name, 162 | } 163 | } elsif $database_max_pool_size != undef { 164 | ini_setting { 'puppetdb_database_max_pool_size': 165 | setting => $puppetdb::params::database_max_pool_size_setting_name, 166 | value => $database_max_pool_size, 167 | } 168 | } 169 | } 170 | 171 | if ($facts_blacklist) and length($facts_blacklist) != 0 { 172 | $joined_facts_blacklist = join($facts_blacklist, ', ') 173 | ini_setting { 'puppetdb_facts_blacklist': 174 | setting => 'facts-blacklist', 175 | value => $joined_facts_blacklist, 176 | } 177 | } else { 178 | ini_setting { 'puppetdb_facts_blacklist': 179 | ensure => absent, 180 | setting => 'facts-blacklist', 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /manifests/server/firewall.pp: -------------------------------------------------------------------------------- 1 | # @summary manage puppetdb firewall rules 2 | # 3 | # @api private 4 | class puppetdb::server::firewall ( 5 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $http_port = $puppetdb::params::listen_port, 6 | Boolean $open_http_port = $puppetdb::params::open_listen_port, 7 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $ssl_port = $puppetdb::params::ssl_listen_port, 8 | Boolean $open_ssl_port = $puppetdb::params::open_ssl_listen_port, 9 | ) inherits puppetdb::params { 10 | include firewall 11 | 12 | if ($open_http_port) { 13 | firewall { "${http_port} accept - puppetdb": 14 | dport => $http_port, 15 | proto => 'tcp', 16 | jump => 'accept', 17 | } 18 | } 19 | 20 | if ($open_ssl_port) { 21 | firewall { "${ssl_port} accept - puppetdb": 22 | dport => $ssl_port, 23 | proto => 'tcp', 24 | jump => 'accept', 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /manifests/server/global.pp: -------------------------------------------------------------------------------- 1 | # @summary manage puppetdb global setting 2 | # 3 | # @api private 4 | class puppetdb::server::global ( 5 | Stdlib::Absolutepath $vardir = $puppetdb::params::vardir, 6 | Stdlib::Absolutepath $confdir = $puppetdb::params::confdir, 7 | String[1] $puppetdb_group = $puppetdb::params::puppetdb_group, 8 | ) inherits puppetdb::params { 9 | $config_ini = "${confdir}/config.ini" 10 | 11 | file { $config_ini: 12 | ensure => file, 13 | owner => 'root', 14 | group => $puppetdb_group, 15 | mode => '0640', 16 | } 17 | 18 | # Set the defaults 19 | Ini_setting { 20 | path => $config_ini, 21 | ensure => 'present', 22 | section => 'global', 23 | require => File[$config_ini], 24 | } 25 | 26 | if $vardir { 27 | ini_setting { 'puppetdb_global_vardir': 28 | setting => 'vardir', 29 | value => $vardir, 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /manifests/server/jetty.pp: -------------------------------------------------------------------------------- 1 | # @summary configures puppetdb jetty ini 2 | # 3 | # @api private 4 | class puppetdb::server::jetty ( 5 | Stdlib::Host $listen_address = $puppetdb::params::listen_address, 6 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $listen_port = $puppetdb::params::listen_port, 7 | Boolean $disable_cleartext = $puppetdb::params::disable_cleartext, 8 | Stdlib::Host $ssl_listen_address = $puppetdb::params::ssl_listen_address, 9 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $ssl_listen_port = $puppetdb::params::ssl_listen_port, 10 | Boolean $disable_ssl = $puppetdb::params::disable_ssl, 11 | Boolean $ssl_set_cert_paths = $puppetdb::params::ssl_set_cert_paths, 12 | Stdlib::Absolutepath $ssl_cert_path = $puppetdb::params::ssl_cert_path, 13 | Stdlib::Absolutepath $ssl_key_path = $puppetdb::params::ssl_key_path, 14 | Stdlib::Absolutepath $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path, 15 | Optional[String[1]] $ssl_protocols = $puppetdb::params::ssl_protocols, 16 | Optional[String[1]] $cipher_suites = $puppetdb::params::cipher_suites, 17 | Stdlib::Absolutepath $confdir = $puppetdb::params::confdir, 18 | Optional[Integer[0]] $max_threads = $puppetdb::params::max_threads, 19 | String[1] $puppetdb_group = $puppetdb::params::puppetdb_group, 20 | ) inherits puppetdb::params { 21 | $jetty_ini = "${confdir}/jetty.ini" 22 | 23 | file { $jetty_ini: 24 | ensure => file, 25 | owner => 'root', 26 | group => $puppetdb_group, 27 | mode => '0640', 28 | } 29 | 30 | # Set the defaults 31 | Ini_setting { 32 | path => $jetty_ini, 33 | ensure => present, 34 | section => 'jetty', 35 | require => File[$jetty_ini], 36 | } 37 | 38 | $cleartext_setting_ensure = $disable_cleartext ? { 39 | true => 'absent', 40 | default => 'present', 41 | } 42 | 43 | ini_setting { 'puppetdb_host': 44 | ensure => $cleartext_setting_ensure, 45 | setting => 'host', 46 | value => $listen_address, 47 | } 48 | 49 | ini_setting { 'puppetdb_port': 50 | ensure => $cleartext_setting_ensure, 51 | setting => 'port', 52 | value => $listen_port, 53 | } 54 | 55 | $ssl_setting_ensure = $disable_ssl ? { 56 | true => 'absent', 57 | default => 'present', 58 | } 59 | 60 | ini_setting { 'puppetdb_sslhost': 61 | ensure => $ssl_setting_ensure, 62 | setting => 'ssl-host', 63 | value => $ssl_listen_address, 64 | } 65 | 66 | ini_setting { 'puppetdb_sslport': 67 | ensure => $ssl_setting_ensure, 68 | setting => 'ssl-port', 69 | value => $ssl_listen_port, 70 | } 71 | 72 | if $ssl_protocols { 73 | ini_setting { 'puppetdb_sslprotocols': 74 | ensure => $ssl_setting_ensure, 75 | setting => 'ssl-protocols', 76 | value => $ssl_protocols, 77 | } 78 | } 79 | 80 | if $cipher_suites { 81 | ini_setting { 'puppetdb_cipher-suites': 82 | ensure => $ssl_setting_ensure, 83 | setting => 'cipher-suites', 84 | value => $cipher_suites, 85 | } 86 | } 87 | 88 | if $ssl_set_cert_paths { 89 | # assume paths have been validated in calling class 90 | ini_setting { 'puppetdb_ssl_key': 91 | ensure => present, 92 | setting => 'ssl-key', 93 | value => $ssl_key_path, 94 | } 95 | ini_setting { 'puppetdb_ssl_cert': 96 | ensure => present, 97 | setting => 'ssl-cert', 98 | value => $ssl_cert_path, 99 | } 100 | ini_setting { 'puppetdb_ssl_ca_cert': 101 | ensure => present, 102 | setting => 'ssl-ca-cert', 103 | value => $ssl_ca_cert_path, 104 | } 105 | } 106 | 107 | if ($max_threads) { 108 | ini_setting { 'puppetdb_max_threads': 109 | setting => 'max-threads', 110 | value => $max_threads, 111 | } 112 | } else { 113 | ini_setting { 'puppetdb_max_threads': 114 | ensure => absent, 115 | setting => 'max-threads', 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /manifests/server/puppetdb.pp: -------------------------------------------------------------------------------- 1 | # @summary manage puppetdb ini 2 | # 3 | # @api private 4 | class puppetdb::server::puppetdb ( 5 | Stdlib::Absolutepath $certificate_whitelist_file = $puppetdb::params::certificate_whitelist_file, 6 | Array $certificate_whitelist = $puppetdb::params::certificate_whitelist, 7 | Optional[Boolean] $disable_update_checking = $puppetdb::params::disable_update_checking, 8 | Stdlib::Absolutepath $confdir = $puppetdb::params::confdir, 9 | String[1] $puppetdb_group = $puppetdb::params::puppetdb_group, 10 | ) inherits puppetdb::params { 11 | $puppetdb_ini = "${confdir}/puppetdb.ini" 12 | 13 | file { $puppetdb_ini: 14 | ensure => file, 15 | owner => 'root', 16 | group => $puppetdb_group, 17 | mode => '0640', 18 | } 19 | 20 | # Set the defaults 21 | Ini_setting { 22 | path => $puppetdb_ini, 23 | ensure => present, 24 | section => 'puppetdb', 25 | require => File[$puppetdb_ini], 26 | } 27 | 28 | $certificate_whitelist_setting_ensure = empty($certificate_whitelist) ? { 29 | true => 'absent', 30 | default => 'present', 31 | } 32 | 33 | # accept connections only from puppet master 34 | ini_setting { 'puppetdb-connections-from-master-only': 35 | ensure => $certificate_whitelist_setting_ensure, 36 | section => 'puppetdb', 37 | setting => 'certificate-whitelist', 38 | value => $certificate_whitelist_file, 39 | } 40 | 41 | file { $certificate_whitelist_file: 42 | ensure => $certificate_whitelist_setting_ensure, 43 | content => template('puppetdb/certificate-whitelist.erb'), 44 | mode => '0644', 45 | owner => 0, 46 | group => 0, 47 | } 48 | 49 | if $disable_update_checking { 50 | ini_setting { 'puppetdb_disable_update_checking': 51 | setting => 'disable-update-checking', 52 | value => $disable_update_checking, 53 | } 54 | } else { 55 | ini_setting { 'puppetdb_disable_update_checking': 56 | ensure => 'absent', 57 | setting => 'disable-update-checking', 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /manifests/server/read_database.pp: -------------------------------------------------------------------------------- 1 | # @summary manage puppetdb read_database ini 2 | # 3 | # @api private 4 | class puppetdb::server::read_database ( 5 | Optional[Stdlib::Host] $read_database_host = $puppetdb::params::read_database_host, 6 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $read_database_port = $puppetdb::params::read_database_port, 7 | String[1] $read_database_username = $puppetdb::params::read_database_username, 8 | Variant[String[1], Sensitive[String[1]]] $read_database_password = $puppetdb::params::read_database_password, 9 | String[1] $read_database_name = $puppetdb::params::read_database_name, 10 | Boolean $manage_db_password = $puppetdb::params::manage_read_db_password, 11 | Variant[String[0], Boolean[false]] $jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, 12 | Boolean $database_validate = $puppetdb::params::read_database_validate, 13 | Variant[Integer[0], Pattern[/\A[0-9]+\Z/]] $conn_max_age = $puppetdb::params::read_conn_max_age, 14 | Variant[Integer[0], Pattern[/\A[0-9]+\Z/]] $conn_lifetime = $puppetdb::params::read_conn_lifetime, 15 | Stdlib::Absolutepath $confdir = $puppetdb::params::confdir, 16 | String[1] $puppetdb_group = $puppetdb::params::puppetdb_group, 17 | Optional[Variant[Integer[0], Enum['absent'], Pattern[/\A[0-9]+\Z/]]] $database_max_pool_size = $puppetdb::params::read_database_max_pool_size, 18 | Boolean $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, 19 | Stdlib::Absolutepath $ssl_cert_path = $puppetdb::params::ssl_cert_path, 20 | Stdlib::Absolutepath $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, 21 | Stdlib::Absolutepath $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path 22 | ) inherits puppetdb::params { 23 | if $read_database_host != undef { 24 | if str2bool($database_validate) { 25 | # Validate the database connection. If we can't connect, we want to fail 26 | # and skip the rest of the configuration, so that we don't leave puppetdb 27 | # in a broken state. 28 | # 29 | # NOTE: 30 | # Because of a limitation in the postgres module this will break with 31 | # a duplicate declaration if read and write database host+name are the 32 | # same. 33 | class { 'puppetdb::server::validate_read_db': 34 | database_host => $read_database_host, 35 | database_port => $read_database_port, 36 | database_username => $read_database_username, 37 | database_password => $read_database_password, 38 | database_name => $read_database_name, 39 | } 40 | } 41 | 42 | $read_database_ini = "${confdir}/read_database.ini" 43 | 44 | file { $read_database_ini: 45 | ensure => file, 46 | owner => 'root', 47 | group => $puppetdb_group, 48 | mode => '0640', 49 | } 50 | 51 | $file_require = File[$read_database_ini] 52 | $ini_setting_require = str2bool($database_validate) ? { 53 | false => $file_require, 54 | default => [$file_require, Class['puppetdb::server::validate_read_db']], 55 | } 56 | # Set the defaults 57 | Ini_setting { 58 | path => $read_database_ini, 59 | ensure => present, 60 | section => 'read-database', 61 | require => $ini_setting_require, 62 | } 63 | 64 | if !empty($jdbc_ssl_properties) { 65 | $database_suffix = $jdbc_ssl_properties 66 | } 67 | else { 68 | $database_suffix = '' 69 | } 70 | 71 | $subname_default = "//${read_database_host}:${read_database_port}/${read_database_name}${database_suffix}" 72 | 73 | if $postgresql_ssl_on and !empty($jdbc_ssl_properties) { 74 | fail("Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!") 75 | } 76 | 77 | if $postgresql_ssl_on { 78 | $subname = @("EOT"/L) 79 | ${subname_default}?\ 80 | ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ 81 | sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ 82 | sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ 83 | | EOT 84 | } else { 85 | $subname = $subname_default 86 | } 87 | 88 | ini_setting { 'puppetdb_read_database_username': 89 | setting => 'username', 90 | value => $read_database_username, 91 | } 92 | 93 | if $read_database_password != undef and $manage_db_password { 94 | ini_setting { 'puppetdb_read_database_password': 95 | setting => 'password', 96 | value => $read_database_password, 97 | show_diff => false, 98 | } 99 | } 100 | 101 | ini_setting { 'puppetdb_read_pgs': 102 | setting => 'syntax_pgs', 103 | value => true, 104 | } 105 | 106 | ini_setting { 'puppetdb_read_subname': 107 | setting => 'subname', 108 | value => $subname, 109 | } 110 | 111 | ini_setting { 'puppetdb_read_conn_max_age': 112 | setting => 'conn-max-age', 113 | value => $conn_max_age, 114 | } 115 | 116 | ini_setting { 'puppetdb_read_conn_lifetime': 117 | setting => 'conn-lifetime', 118 | value => $conn_lifetime, 119 | } 120 | 121 | if $puppetdb::params::database_max_pool_size_setting_name != undef { 122 | if $database_max_pool_size == 'absent' { 123 | ini_setting { 'puppetdb_read_database_max_pool_size': 124 | ensure => absent, 125 | setting => $puppetdb::params::database_max_pool_size_setting_name, 126 | } 127 | } elsif $database_max_pool_size != undef { 128 | ini_setting { 'puppetdb_read_database_max_pool_size': 129 | setting => $puppetdb::params::database_max_pool_size_setting_name, 130 | value => $database_max_pool_size, 131 | } 132 | } 133 | } else { 134 | file { "${confdir}/read_database.ini": 135 | ensure => absent, 136 | } 137 | } 138 | } else { 139 | file { "${confdir}/read_database.ini": 140 | ensure => absent, 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /manifests/server/validate_db.pp: -------------------------------------------------------------------------------- 1 | # @summary validates the database connection 2 | # 3 | # @api private 4 | class puppetdb::server::validate_db ( 5 | Stdlib::Host $database_host = $puppetdb::params::database_host, 6 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $database_port = $puppetdb::params::database_port, 7 | String[1] $database_username = $puppetdb::params::database_username, 8 | Variant[String[1], Sensitive[String[1]]] $database_password = $puppetdb::params::database_password, 9 | String[1] $database_name = $puppetdb::params::database_name, 10 | Variant[String[0], Boolean[false]] $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, 11 | ) inherits puppetdb::params { 12 | if ($database_password != undef and $jdbc_ssl_properties == false) { 13 | postgresql_conn_validator { 'validate puppetdb postgres connection': 14 | host => $database_host, 15 | port => $database_port, 16 | db_username => $database_username, 17 | db_password => $database_password, 18 | db_name => $database_name, 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /manifests/server/validate_read_db.pp: -------------------------------------------------------------------------------- 1 | # @summary validates the read only database connection 2 | # 3 | # @api private 4 | class puppetdb::server::validate_read_db ( 5 | Stdlib::Host $database_host = $puppetdb::params::database_host, 6 | Variant[Stdlib::Port::User, Pattern[/\A[0-9]+\Z/]] $database_port = $puppetdb::params::database_port, 7 | String[1] $database_username = $puppetdb::params::database_username, 8 | Variant[String[1], Sensitive[String[1]]] $database_password = $puppetdb::params::database_password, 9 | String[1] $database_name = $puppetdb::params::database_name, 10 | Variant[String[0], Boolean[false]] $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, 11 | ) inherits puppetdb::params { 12 | if ($database_password != undef and $jdbc_ssl_properties == false) { 13 | postgresql_conn_validator { 'validate puppetdb postgres (read) connection': 14 | host => $database_host, 15 | port => $database_port, 16 | db_username => $database_username, 17 | db_password => $database_password, 18 | db_name => $database_name, 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppetlabs-puppetdb", 3 | "version": "8.1.0", 4 | "author": "puppetlabs", 5 | "summary": "Installs PostgreSQL and PuppetDB, sets up the connection to Puppet master.", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/puppetlabs/puppetlabs-puppetdb.git", 8 | "project_page": "http://github.com/puppetlabs/puppetlabs-puppetdb", 9 | "issues_url": "https://tickets.puppetlabs.com/browse/PDB", 10 | "dependencies": [ 11 | { 12 | "name": "puppetlabs/inifile", 13 | "version_requirement": ">= 1.1.3 < 7.0.0" 14 | }, 15 | { 16 | "name": "puppetlabs/postgresql", 17 | "version_requirement": ">= 10.0.0 < 11.0.0" 18 | }, 19 | { 20 | "name": "puppetlabs/firewall", 21 | "version_requirement": ">= 7.0.0 < 9.0.0" 22 | }, 23 | { 24 | "name": "puppetlabs/stdlib", 25 | "version_requirement": ">= 4.13.1 < 10.0.0" 26 | } 27 | ], 28 | "operatingsystem_support": [ 29 | { 30 | "operatingsystem": "RedHat", 31 | "operatingsystemrelease": [ 32 | "7", 33 | "8" 34 | ] 35 | }, 36 | { 37 | "operatingsystem": "CentOS", 38 | "operatingsystemrelease": [ 39 | "7", 40 | "8" 41 | ] 42 | }, 43 | { 44 | "operatingsystem": "OracleLinux", 45 | "operatingsystemrelease": [ 46 | "7", 47 | "8" 48 | ] 49 | }, 50 | { 51 | "operatingsystem": "SLES", 52 | "operatingsystemrelease": [ 53 | "12 SP3" 54 | ] 55 | }, 56 | { 57 | "operatingsystem": "Debian", 58 | "operatingsystemrelease": [ 59 | "10", 60 | "11" 61 | ] 62 | }, 63 | { 64 | "operatingsystem": "Ubuntu", 65 | "operatingsystemrelease": [ 66 | "18.04", 67 | "20.04" 68 | ] 69 | } 70 | ], 71 | "requirements": [ 72 | { 73 | "name": "puppet", 74 | "version_requirement": ">= 7.0.0 < 9.0.0" 75 | } 76 | ], 77 | "description": "Module for installing/configuring PuppetDB", 78 | "pdk-version": "3.0.1", 79 | "template-url": "https://github.com/puppetlabs/pdk-templates#3.0.1", 80 | "template-ref": "tags/3.0.1-0-gd13288a" 81 | } 82 | -------------------------------------------------------------------------------- /pdk.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: [] 3 | -------------------------------------------------------------------------------- /provision.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | default: 3 | provisioner: docker 4 | images: 5 | - litmusimage/ubuntu:20.04 6 | yum: 7 | provisioner: docker 8 | images: 9 | - litmusimage/centos:7 10 | dnf: 11 | provisioner: docker 12 | images: 13 | - litmusimage/centos:8 14 | apt: 15 | provisioner: docker 16 | images: 17 | - litmusimage/ubuntu:20.04 18 | ci: 19 | provisioner: docker 20 | images: 21 | - litmusimage/centos:7 22 | - litmusimage/centos:8 23 | - litmusimage/oraclelinux:7 24 | - litmusimage/oraclelinux:8 25 | - litmusimage/debian:10 26 | - litmusimage/debian:11 27 | - litmusimage/ubuntu:18.04 28 | - litmusimage/ubuntu:20.04 29 | -------------------------------------------------------------------------------- /rakelib/common.rake: -------------------------------------------------------------------------------- 1 | begin 2 | require 'metadata_json_lint' 3 | 4 | # PDK validate behaviors 5 | MetadataJsonLint.options.fail_on_warnings = true 6 | MetadataJsonLint.options.strict_license = true 7 | MetadataJsonLint.options.strict_puppet_version = true 8 | MetadataJsonLint.options.strict_dependencies = true 9 | 10 | PuppetLint.configuration.log_forat = '%{path}:%{line}:%{check}:%{KIND}:%{message}' 11 | PuppetLint.configuration.fail_on_warnings = true 12 | PuppetLint.configuration.ignore_paths.reject! { |c| c == 'spec/**/*.pp' } 13 | PuppetLint.configuration.ignore_paths << 'spec/fixtures/**/*.pp' 14 | rescue LoadError 15 | # ignore 16 | end 17 | 18 | # output task execution 19 | unless Rake.application.options.trace 20 | setup = ->(task, *_args) do 21 | puts "===> rake: #{task}" 22 | end 23 | 24 | task :log_hooker do 25 | Rake::Task.tasks.reject { |t| t.to_s == 'log_hooker' }.each do |a_task| 26 | a_task.actions.prepend(setup) 27 | end 28 | end 29 | Rake.application.top_level_tasks.prepend(:log_hooker) 30 | end 31 | -------------------------------------------------------------------------------- /rakelib/litmus.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | litmus_cleanup = false 4 | at_exit { Rake::Task['litmus:tear_down'].invoke if litmus_cleanup } 5 | 6 | desc "Provision machines, run acceptance tests, and tear down\n(defaults: group=default, tag=nil)" 7 | task :acceptance, [:group, :tag] do |_task, args| 8 | args.with_defaults(group: 'default', tag: nil) 9 | Rake::Task['spec_prep'].invoke 10 | litmus_cleanup = ENV.fetch('LITMUS_teardown', 'true').downcase.match?(%r{(true|auto)}) 11 | Rake::Task['litmus:provision_list'].invoke args[:group] 12 | Rake::Task['litmus:install_agent'].invoke 13 | Rake::Task['litmus:install_modules'].invoke 14 | begin 15 | Rake::Task['litmus:acceptance:parallel'].invoke args[:tag] 16 | rescue SystemExit 17 | litmus_cleanup = false if ENV.fetch('LITMUS_teardown', '').casecmp('auto').zero? 18 | raise 19 | end 20 | end 21 | 22 | namespace :litmus do 23 | desc "Run tests against all nodes in the litmus inventory\n(defaults: tag=nil)" 24 | task :acceptance, [:tag] do |_task, args| 25 | args.with_defaults(tag: nil) 26 | 27 | Rake::Task.tasks.select { |t| t.to_s =~ %r{^litmus:acceptance:(?!(localhost|parallel)$)} }.each do |litmus_task| 28 | puts "Running task #{litmus_task}" 29 | litmus_task.invoke(*args) 30 | end 31 | end 32 | 33 | desc "install all fixture modules\n(defaults: resolve_dependencies=false)" 34 | task :install_modules_from_fixtures, [:resolve_dependencies] do |_task, args| 35 | args.with_defaults(resolve_dependencies: false) 36 | 37 | Rake::Task['spec_prep'].invoke 38 | Rake::Task['litmus:install_modules_from_directory'].invoke(nil, nil, nil, !args[:resolve_dependencies]) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/acceptance/standalone_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper_acceptance' 2 | 3 | describe 'standalone' do 4 | it_behaves_like 'puppetserver' 5 | 6 | let(:puppetdb_params) {} 7 | let(:puppetdb_master_config_params) {} 8 | 9 | let(:postgres_version) { 'undef' } # default 10 | let(:manage_firewall) { "(getvar('facts.os.family') == 'RedHat' and Integer(getvar('facts.os.release.major')) > 7)" } 11 | 12 | describe 'with defaults' do 13 | it_behaves_like 'puppetdb' 14 | 15 | describe service('puppetdb'), :status do 16 | it { is_expected.to be_enabled } 17 | it { is_expected.to be_running } 18 | end 19 | 20 | describe port(8080), :status do 21 | it { is_expected.to be_listening } 22 | end 23 | 24 | describe port(8081), :status do 25 | it { is_expected.to be_listening } 26 | end 27 | 28 | context 'puppetdb postgres user', :status do 29 | it 'is not allowing read-only user to create tables' do 30 | run_shell('psql "postgresql://puppetdb-read:puppetdb-read@localhost/puppetdb" -c "create table tables(id int)"', expect_failures: true) do |r| 31 | expect(r.stderr).to match(%r{^ERROR: permission denied for schema public.*}) 32 | expect(r.exit_code).to eq 1 33 | end 34 | end 35 | 36 | it 'is allowing normal user to manage schema' do 37 | run_shell('psql "postgresql://puppetdb:puppetdb@localhost/puppetdb" -c "create table testing(id int); drop table testing"') do |r| 38 | expect(r.exit_status).to eq 0 39 | end 40 | end 41 | 42 | it 'is allowing read-only user to select' do 43 | run_shell('psql "postgresql://puppetdb-read:puppetdb-read@localhost/puppetdb" -c "select * from catalogs limit 1"') do |r| 44 | expect(r.exit_status).to eq 0 45 | end 46 | end 47 | end 48 | end 49 | 50 | context 'with manage report processor', :change do 51 | ['remove', 'add'].each do |outcome| 52 | context "#{outcome}s puppet config puppetdb report processor" do 53 | let(:enable_reports) { (outcome == 'add') ? true : false } 54 | 55 | let(:puppetdb_master_config_params) do 56 | <<~EOS 57 | manage_report_processor => true, 58 | enable_reports => #{enable_reports}, 59 | EOS 60 | end 61 | 62 | it_behaves_like 'puppetdb' 63 | 64 | describe command('puppet config print --section master reports') do 65 | its(:stdout) do 66 | option = enable_reports ? 'to' : 'not_to' 67 | is_expected.method(option).call match 'puppetdb' 68 | end 69 | end 70 | end 71 | end 72 | end 73 | 74 | describe 'puppetdb with postgresql ssl', :change do 75 | let(:puppetdb_params) do 76 | <<~EOS 77 | postgresql_ssl_on => true, 78 | database_listen_address => '0.0.0.0', 79 | database_host => $facts['networking']['fqdn'], 80 | EOS 81 | end 82 | 83 | it_behaves_like 'puppetdb' 84 | end 85 | 86 | describe 'set wrong database password in puppetdb conf', :change do 87 | it 'applies manifest' do 88 | pp = <<~EOS 89 | ini_setting { "puppetdb password": 90 | ensure => present, 91 | path => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 92 | section => 'database', 93 | setting => 'password', 94 | value => 'random_password', 95 | } 96 | ~> service { 'puppetdb': 97 | ensure => 'running', 98 | } 99 | EOS 100 | 101 | apply_manifest(pp, expect_failures: false, debug: ENV.key?('DEBUG')) 102 | end 103 | 104 | describe service('puppetdb') do 105 | it { is_expected.to be_running } 106 | end 107 | end 108 | 109 | describe 'supports changing database port', :change do 110 | let(:puppetdb_params) do 111 | <<~EOS 112 | database_port => '5433', 113 | read_database_port => '5433', 114 | EOS 115 | end 116 | 117 | it_behaves_like 'puppetdb' 118 | 119 | describe port(5433), :status do 120 | it { is_expected.to be_listening } 121 | end 122 | 123 | describe service('puppetdb') do 124 | it { is_expected.to be_running } 125 | end 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /spec/defines/database/default_read_grant_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'puppetdb::database::default_read_grant' do 6 | defaults = { 7 | database_name: 'puppetdb', 8 | schema: 'public', 9 | database_username: 'puppetdb', 10 | database_read_only_username: 'puppetdb-read', 11 | } 12 | valid = { 13 | 'standard': defaults, 14 | 'standard with port': defaults.merge({ database_port: 5433 }), 15 | } 16 | 17 | invalid = { 18 | 'no params': {}, 19 | 'without database_name': { 20 | schema: 'public', 21 | database_username: 'puppetdb', 22 | database_read_only_username: 'puppetdb-read', 23 | }, 24 | 'invalid data type': defaults.merge({ database_port: '5433' }), 25 | } 26 | 27 | let(:facts) { on_supported_os.take(1).first[1] } 28 | let(:pre_condition) { 'include postgresql::server' } 29 | let(:name) { title } 30 | let(:args) { params } 31 | 32 | context 'with valid parameters' do 33 | valid.each do |name, params| 34 | context name do 35 | include_examples 'puppetdb::database::default_read_grant' do 36 | let(:title) { name.to_s } 37 | let(:params) { params } 38 | end 39 | end 40 | end 41 | end 42 | 43 | context 'with invalid parameters' do 44 | invalid.each do |name, params| 45 | context name do 46 | include_examples 'puppetdb::database::default_read_grant', Puppet::Error do 47 | let(:title) { name.to_s } 48 | let(:params) { params } 49 | end 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/defines/database/postgresql_ssl_rules_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | valid = { 6 | 'puppetdb-read': { 7 | database_name: 'puppetdb', 8 | database_username: 'monitor', 9 | postgres_version: '11', 10 | puppetdb_server: 'localhost', 11 | }, 12 | 'monitor': { 13 | database_name: 'opensesame', 14 | database_username: 'grover', 15 | postgres_version: '11', 16 | puppetdb_server: 'rainbow', 17 | }, 18 | } 19 | 20 | valid_12plus = { 21 | 'puppetdb-read': { 22 | database_name: 'puppetdb', 23 | database_username: 'monitor', 24 | postgres_version: '12', 25 | puppetdb_server: 'localhost', 26 | }, 27 | 'monitor': { 28 | database_name: 'opensesame', 29 | database_username: 'grover', 30 | postgres_version: '12', 31 | puppetdb_server: 'rainbow', 32 | }, 33 | } 34 | 35 | invalid = { 36 | 'no params': {}, 37 | } 38 | 39 | describe 'puppetdb::database::postgresql_ssl_rules' do 40 | let(:facts) { on_supported_os.take(1).first[1] } 41 | let(:pre_condition) { 'include postgresql::server' } 42 | let(:name) { title } 43 | let(:args) { params } 44 | 45 | valid.each do |name, params| 46 | context "for valid #{name}" do 47 | include_examples 'puppetdb::database::postgresql_ssl_rules' do 48 | let(:title) { name.to_s } 49 | let(:params) { params } 50 | end 51 | end 52 | end 53 | 54 | valid_12plus.each do |name, params| 55 | context "for valid_12plus #{name}" do 56 | include_examples 'puppetdb::database::postgresql_ssl_rules' do 57 | let(:title) { name.to_s } 58 | let(:params) { params } 59 | end 60 | end 61 | end 62 | 63 | invalid.each do |name, params| 64 | context "for invalid #{name}" do 65 | include_examples 'puppetdb::database::postgresql_ssl_rules', Puppet::Error do 66 | let(:title) { name.to_s } 67 | let(:params) { params } 68 | end 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /spec/defines/database/read_grant_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | defaults = { 6 | database_read_only_username: 'puppetdb-read', 7 | database_name: 'puppetdb', 8 | schema: 'public', 9 | } 10 | 11 | valid = { 12 | 'grant read on new objects from blah to blah': defaults, 13 | 'grant read on new objects from blah to blah with port': defaults.merge({ database_port: 5433 }), 14 | } 15 | 16 | invalid = { 17 | 'no params': {}, 18 | 'invalid data type': defaults.merge({ database_port: '5433' }), 19 | } 20 | 21 | describe 'puppetdb::database::read_grant' do 22 | let(:facts) { on_supported_os.take(1).first[1] } 23 | let(:pre_condition) { 'include postgresql::server' } 24 | let(:name) { title } 25 | let(:args) { params } 26 | 27 | valid.each do |name, params| 28 | context "for valid #{name}" do 29 | include_examples 'puppetdb::database::read_grant' do 30 | let(:title) { name.to_s } 31 | let(:params) { params } 32 | end 33 | end 34 | end 35 | 36 | invalid.each do |name, params| 37 | context "for invalid #{name}" do 38 | include_examples 'puppetdb::database::read_grant', Puppet::Error do 39 | let(:title) { name.to_s } 40 | let(:params) { params } 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/defines/database/read_only_user_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | defaults = { 6 | read_database_username: 'puppetdb-read', 7 | database_name: 'puppetdb', 8 | database_owner: 'puppetdb', 9 | } 10 | 11 | valid = { 12 | 'puppetdb-read': defaults.merge({ password_hash: 'blash' }), 13 | 'spectest': { 14 | read_database_username: 'spectest-read', 15 | database_name: 'spectest', 16 | database_owner: 'spectest', 17 | }, 18 | 'with port': defaults.merge({ database_port: 5433 }), 19 | } 20 | 21 | invalid = { 22 | 'no params': {}, 23 | 'invalid data type': defaults.merge({ database_port: '5433' }), 24 | } 25 | 26 | describe 'puppetdb::database::read_only_user', type: :define do 27 | let(:facts) { on_supported_os.take(1).first[1] } 28 | let(:pre_condition) { 'include postgresql::server' } 29 | let(:name) { title } 30 | let(:args) { params } 31 | 32 | valid.each do |name, params| 33 | context "for valid #{name}" do 34 | include_examples 'puppetdb::database::read_only_user' do 35 | let(:title) { name.to_s } 36 | let(:params) { params } 37 | end 38 | end 39 | end 40 | 41 | invalid.each do |name, params| 42 | context "for invalid #{name}" do 43 | include_examples 'puppetdb::database::read_only_user', Puppet::Error do 44 | let(:title) { name.to_s } 45 | let(:params) { params } 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/functions/create_subsetting_resource_hash_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::create_subsetting_resource_hash' do 4 | it { is_expected.not_to eq(nil) } 5 | it { is_expected.to run.with_params.and_raise_error(ArgumentError) } 6 | it { is_expected.to run.with_params('test' => 1).and_raise_error(ArgumentError) } 7 | it { is_expected.to run.with_params('foo', 'bar').and_raise_error(ArgumentError) } 8 | it { is_expected.to run.with_params({ 'foo' => 1 }, { 'bar' => 2 }, 'baz' => 3).and_raise_error(ArgumentError) } 9 | it { 10 | is_expected.to run.with_params({ 'foo' => 1, 'bar' => 2 }, 'baz' => 3) 11 | .and_return("'foo'" => { 'subsetting' => 'foo', 'value' => 1, 'baz' => 3 }, "'bar'" => { 'subsetting' => 'bar', 'value' => 2, 'baz' => 3 }) 12 | } 13 | end 14 | -------------------------------------------------------------------------------- /spec/functions/flatten_java_args_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::flatten_java_args' do 4 | it { is_expected.not_to eq(nil) } 5 | it { is_expected.to run.with_params.and_return('""') } 6 | it { is_expected.to run.with_params({ 'test' => 1 }, 'foo' => 2).and_raise_error(ArgumentError) } 7 | it { is_expected.to run.with_params('foo').and_raise_error(ArgumentError) } 8 | it { is_expected.to run.with_params('foo' => 1).and_return('"foo1"') } 9 | end 10 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |c| 4 | c.mock_with :rspec 5 | end 6 | 7 | require 'puppetlabs_spec_helper/module_spec_helper' 8 | require 'rspec-puppet-facts' 9 | 10 | require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) 11 | 12 | include RspecPuppetFacts 13 | 14 | default_facts = { 15 | puppetversion: Puppet.version, 16 | facterversion: Facter.version, 17 | } 18 | 19 | default_fact_files = [ 20 | File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), 21 | File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), 22 | ] 23 | 24 | default_fact_files.each do |f| 25 | next unless File.exist?(f) && File.readable?(f) && File.size?(f) 26 | 27 | begin 28 | default_facts.merge!(YAML.safe_load(File.read(f), permitted_classes: [], permitted_symbols: [], aliases: true)) 29 | rescue StandardError => e 30 | RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" 31 | end 32 | end 33 | 34 | # read default_facts and merge them over what is provided by facterdb 35 | default_facts.each do |fact, value| 36 | add_custom_fact fact, value 37 | end 38 | 39 | RSpec.configure do |c| 40 | c.default_facts = default_facts 41 | c.before :each do 42 | # set to strictest setting for testing 43 | # by default Puppet runs at warning level 44 | Puppet.settings[:strict] = :warning 45 | Puppet.settings[:strict_variables] = true 46 | end 47 | c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] 48 | c.after(:suite) do 49 | RSpec::Puppet::Coverage.report!(100) 50 | end 51 | 52 | # Filter backtrace noise 53 | backtrace_exclusion_patterns = [ 54 | %r{spec_helper}, 55 | %r{gems}, 56 | ] 57 | 58 | if c.respond_to?(:backtrace_exclusion_patterns) 59 | c.backtrace_exclusion_patterns = backtrace_exclusion_patterns 60 | elsif c.respond_to?(:backtrace_clean_patterns) 61 | c.backtrace_clean_patterns = backtrace_exclusion_patterns 62 | end 63 | end 64 | 65 | # Ensures that a module is defined 66 | # @param module_name Name of the module 67 | def ensure_module_defined(module_name) 68 | module_name.split('::').reduce(Object) do |last_module, next_module| 69 | last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) 70 | last_module.const_get(next_module, false) 71 | end 72 | end 73 | 74 | # 'spec_overrides' from sync.yml will appear below this line 75 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet_litmus' 4 | PuppetLitmus.configure! 5 | 6 | require 'spec_helper_acceptance_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_acceptance_local.rb')) 7 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'singleton' 4 | class LitmusHelper 5 | include Singleton 6 | include PuppetLitmus 7 | end 8 | 9 | Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f } 10 | 11 | RSpec.configure do |c| 12 | c.fail_fast = true 13 | end 14 | 15 | RSpec::Matchers.define(:be_one_of) do |expected| 16 | match do |actual| 17 | expected.include?(actual) 18 | end 19 | 20 | failure_message do |actual| 21 | "expected one of #{expected}, got #{actual}" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/spec_helper_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | include RspecPuppetFacts 4 | 5 | Dir['./spec/support/unit/**/*.rb'].sort.each { |f| require f } 6 | 7 | RSpec.configure do |c| 8 | c.fail_if_no_examples = true 9 | c.silence_filter_announcements = true 10 | 11 | c.expect_with :rspec do |expectations| 12 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/acceptance/shared/puppetdb.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | shared_examples 'puppetdb' do 4 | let(:pp) do 5 | <<~PP 6 | if $facts['os']['family'] == 'RedHat' { 7 | # Work-around EL systemd in docker bug affecting forked services 8 | file_line { 'puppetdb-unit-remove-pidfile': 9 | path => '/lib/systemd/system/puppetdb.service', 10 | line => '#PIDFile=/run/puppetlabs/puppetdb/puppetdb.pid', 11 | match => '^PIDFile.*', 12 | append_on_no_match => false, 13 | require => Package['puppetdb'], 14 | notify => Service['puppetdb'], 15 | } 16 | } 17 | 18 | # reduce pgs memory 19 | postgresql::server::config_entry { 'max_connections': value => '20' } 20 | postgresql::server::config_entry { 'shared_buffers': value => '128kB' } 21 | postgresql::server::config_entry { 'effective_cache_size': value => '24MB' } 22 | postgresql::server::config_entry { 'maintenance_work_mem': value => '1MB' } 23 | postgresql::server::config_entry { 'checkpoint_completion_target': value => '0.9' } 24 | postgresql::server::config_entry { 'wal_buffers': value => '32kB' } 25 | postgresql::server::config_entry { 'random_page_cost': value => '4' } 26 | postgresql::server::config_entry { 'effective_io_concurrency': value => '2' } 27 | postgresql::server::config_entry { 'work_mem': value => '204kB' } 28 | postgresql::server::config_entry { 'huge_pages': value => 'off' } 29 | postgresql::server::config_entry { 'min_wal_size': value => '80MB' } 30 | postgresql::server::config_entry { 'max_wal_size': value => '1GB' } 31 | 32 | class { 'puppetdb': 33 | postgres_version => #{postgres_version}, 34 | manage_firewall => #{manage_firewall}, 35 | database_max_pool_size => '2', 36 | read_database_max_pool_size => '2', 37 | #{puppetdb_params} 38 | } 39 | -> class { 'puppetdb::master::config': 40 | #{puppetdb_master_config_params} 41 | } 42 | PP 43 | end 44 | 45 | it 'applies idempotently' do 46 | idempotent_apply(pp, debug: ENV.key?('DEBUG')) 47 | end 48 | 49 | it 'agent can puppetdb_query' do 50 | apply_manifest("$envs = puppetdb_query('environments[name]{}')", expect_failures: false, debug: ENV.key?('DEBUG')) 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/support/acceptance/shared/puppetserver.pp: -------------------------------------------------------------------------------- 1 | # some provision environments (docker) may not setup or isolate domains 2 | # this ensures the instance FQDN is always resolved locally 3 | host { 'primary': 4 | name => $facts['networking']['fqdn'], 5 | ip => $facts['networking']['ip'], 6 | host_aliases => [ 7 | $facts['networking']['hostname'], 8 | ], 9 | } 10 | 11 | if $facts['os']['family'] == 'RedHat' { 12 | # TODO: backport to litmusimage, required for serverspec port tests 13 | package { 'iproute': ensure => installed } 14 | 15 | # TODO: rework this hack, maybe not needed for newer version of postgresl module? 16 | if versioncmp($facts['os']['release']['major'], '8') >= 0 { 17 | package { 'disable-builtin-dnf-postgresql-module': 18 | ensure => 'disabled', 19 | name => 'postgresql', 20 | provider => 'dnfmodule', 21 | } 22 | 23 | Yumrepo <| tag == 'postgresql::repo' |> 24 | -> Package['disable-dnf-postgresql-module'] 25 | -> Package <| tag == 'postgresql' |> 26 | } 27 | 28 | # Work-around EL systemd in docker with cgroupsv1? issue and forked services 29 | # Without this, the puppet agent will stall for 300 seconds waiting for 30 | # the service to start... then miserably fail. 31 | # systemd error message: 32 | # New main PID 1411 does not belong to service, and PID file is not 33 | # owned by root. Refusing. 34 | # PIDFile is not needed, but it cannot be reset by a drop-in, therefor the 35 | # original unit must be modified 36 | file_line { 'puppetserver-unit-remove-pidfile': 37 | path => '/lib/systemd/system/puppetserver.service', 38 | line => '#PIDFile=/run/puppetlabs/puppetserver.pid', 39 | match => '^PIDFile.*', 40 | append_on_no_match => false, 41 | require => Package['puppetserver'], 42 | notify => Service['puppetserver'], 43 | } 44 | } 45 | 46 | $sysconfdir = $facts['os']['family'] ? { 47 | 'Debian' => '/etc/default', 48 | default => '/etc/sysconfig', 49 | } 50 | 51 | package { 'puppetserver': 52 | ensure => installed, 53 | } 54 | # savagely disable dropsonde 55 | ~> file { 56 | [ 57 | '/opt/puppetlabs/server/data/puppetserver/dropsonde/bin/dropsonde', 58 | '/opt/puppetlabs/server/apps/puppetserver/cli/apps/dropsonde', 59 | ]: 60 | ensure => absent, 61 | } 62 | -> exec { '/opt/puppetlabs/bin/puppetserver ca setup': 63 | creates => '/etc/puppetlabs/puppetserver/ca/ca_crt.pem', 64 | } 65 | # drop memory requirements to fit on a low memory containers 66 | -> augeas { 'puppetserver-environment': 67 | context => "/files${sysconfdir}/puppetserver", 68 | changes => [ 69 | 'set JAVA_ARGS \'"-Xms512m -Djruby.logger.class=com.puppetlabs.jruby_utils.jruby.Slf4jLogger"\'', 70 | ], 71 | } 72 | -> service { 'puppetserver': 73 | ensure => running, 74 | enable => true, 75 | } 76 | -------------------------------------------------------------------------------- /spec/support/acceptance/shared/puppetserver.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | shared_examples 'puppetserver' do 4 | let(:pp) { File.read(File.join(File.dirname(__FILE__), 'puppetserver.pp')) } 5 | 6 | it 'applies idempotently' do 7 | idempotent_apply(pp, debug: ENV.key?('DEBUG')) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/unit/facts.rb: -------------------------------------------------------------------------------- 1 | # Rough conversion of grepping in the puppet source: 2 | # grep defaultfor lib/puppet/provider/service/*.rb 3 | # Source https://github.com/voxpupuli/voxpupuli-test/blob/master/lib/voxpupuli/test/facts.rb 4 | add_custom_fact :service_provider, ->(_os, facts) do 5 | os = RSpec.configuration.facterdb_string_keys ? facts['os'] : facts[:os] 6 | case os['family'].downcase 7 | when 'archlinux' 8 | 'systemd' 9 | when 'darwin' 10 | 'launchd' 11 | when 'debian' 12 | 'systemd' 13 | when 'freebsd' 14 | 'freebsd' 15 | when 'gentoo' 16 | 'openrc' 17 | when 'openbsd' 18 | 'openbsd' 19 | when 'redhat' 20 | (os['release']['major'].to_i >= 7) ? 'systemd' : 'redhat' 21 | when 'suse' 22 | (os['release']['major'].to_i >= 12) ? 'systemd' : 'redhat' 23 | when 'windows' 24 | 'windows' 25 | else 26 | 'init' 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/support/unit/shared/database.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppetlabs_spec_helper/puppetlabs_spec/puppet_internals' 4 | 5 | shared_examples 'postgresql_psql read grant' do 6 | it { 7 | is_expected.to contain_postgresql_psql("grant select permission for #{with[:database_read_only_username]}") 8 | .with( 9 | db: with[:database_name], 10 | command: "GRANT SELECT 11 | ON ALL TABLES IN SCHEMA \"public\" 12 | TO \"#{with[:database_read_only_username]}\"", 13 | unless: "SELECT * FROM ( 14 | SELECT COUNT(*) 15 | FROM pg_tables 16 | WHERE schemaname='public' 17 | AND has_table_privilege('#{with[:database_read_only_username]}', schemaname || '.' || tablename, 'SELECT')=false 18 | ) x 19 | WHERE x.count=0", 20 | ) 21 | } 22 | 23 | it { 24 | is_expected.to contain_postgresql_psql("grant usage permission for #{with[:database_read_only_username]}") 25 | .with( 26 | db: with[:database_name], 27 | command: "GRANT USAGE 28 | ON ALL SEQUENCES IN SCHEMA \"public\" 29 | TO \"#{with[:database_read_only_username]}\"", 30 | unless: "SELECT * FROM ( 31 | SELECT COUNT(*) 32 | FROM information_schema.sequences 33 | WHERE sequence_schema='public' 34 | AND has_sequence_privilege('#{with[:database_read_only_username]}', sequence_schema || '.' || sequence_name, 'USAGE')=false 35 | ) x 36 | WHERE x.count=0", 37 | ) 38 | } 39 | 40 | it { 41 | is_expected.to contain_postgresql_psql("grant execution permission for #{with[:database_read_only_username]}") 42 | .with( 43 | db: with[:database_name], 44 | command: "GRANT EXECUTE 45 | ON ALL FUNCTIONS IN SCHEMA \"public\" 46 | TO \"#{with[:database_read_only_username]}\"", 47 | unless: "SELECT * FROM ( 48 | SELECT COUNT(*) 49 | FROM pg_catalog.pg_proc p 50 | LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace 51 | WHERE n.nspname='public' 52 | AND has_function_privilege('#{with[:database_read_only_username]}', p.oid, 'EXECUTE')=false 53 | ) x 54 | WHERE x.count=0", 55 | ) 56 | } 57 | end 58 | 59 | shared_examples 'postgresql_psql default read grant' do 60 | it { 61 | is_expected.to contain_postgresql_psql("grant default select permission for #{with[:database_read_only_username]}") 62 | .with( 63 | db: with[:database_name], 64 | command: "ALTER DEFAULT PRIVILEGES 65 | FOR USER \"#{with[:database_username]}\" 66 | IN SCHEMA \"public\" 67 | GRANT SELECT ON TABLES 68 | TO \"#{with[:database_read_only_username]}\"", 69 | unless: "SELECT 70 | ns.nspname, 71 | acl.defaclobjtype, 72 | acl.defaclacl 73 | FROM pg_default_acl acl 74 | JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid 75 | WHERE '@' || array_to_string(acl.defaclacl, '@') || '@' ~ '@(\"?)#{with[:database_read_only_username]}\\1=r/(\"?)#{with[:database_username]}\\2@' 76 | AND nspname = 'public'", 77 | ) 78 | } 79 | 80 | it { 81 | is_expected.to contain_postgresql_psql("grant default usage permission for #{with[:database_read_only_username]}") 82 | .with( 83 | db: with[:database_name], 84 | command: "ALTER DEFAULT PRIVILEGES 85 | FOR USER \"#{with[:database_username]}\" 86 | IN SCHEMA \"public\" 87 | GRANT USAGE ON SEQUENCES 88 | TO \"#{with[:database_read_only_username]}\"", 89 | unless: "SELECT 90 | ns.nspname, 91 | acl.defaclobjtype, 92 | acl.defaclacl 93 | FROM pg_default_acl acl 94 | JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid 95 | WHERE '@' || array_to_string(acl.defaclacl, '@') || '@' ~ '@(\"?)#{with[:database_read_only_username]}\\1=U/(\"?)#{with[:database_username]}\\2@' 96 | AND nspname = 'public'", 97 | ) 98 | } 99 | 100 | it { 101 | is_expected.to contain_postgresql_psql("grant default execute permission for #{with[:database_read_only_username]}") 102 | .with( 103 | db: with[:database_name], 104 | command: "ALTER DEFAULT PRIVILEGES 105 | FOR USER \"#{with[:database_username]}\" 106 | IN SCHEMA \"public\" 107 | GRANT EXECUTE ON FUNCTIONS 108 | TO \"#{with[:database_read_only_username]}\"", 109 | unless: "SELECT 110 | ns.nspname, 111 | acl.defaclobjtype, 112 | acl.defaclacl 113 | FROM pg_default_acl acl 114 | JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid 115 | WHERE '@' || array_to_string(acl.defaclacl, '@') || '@' ~ '@(\"?)#{with[:database_read_only_username]}\\1=X/(\"?)#{with[:database_username]}\\2@' 116 | AND nspname = 'public'", 117 | ) 118 | } 119 | end 120 | 121 | shared_examples 'puppetdb::database::read_only_user' do |error = false| 122 | let(:defaults) do 123 | { 124 | read_database_username: nil, 125 | database_name: nil, 126 | database_owner: nil, 127 | password_hash: false, 128 | } 129 | end 130 | let(:with) { defined?(args) ? defaults.merge(args) : defaults } 131 | 132 | if error 133 | it { is_expected.to raise_error(error) } 134 | else 135 | it { is_expected.to contain_puppetdb__database__read_only_user(name).with(with) } 136 | 137 | it { 138 | is_expected.to contain_postgresql__server__role(with[:read_database_username]) 139 | .that_comes_before("Postgresql::Server::Database_grant[#{with[:database_name]} grant connection permission to #{with[:read_database_username]}]") 140 | .with_password_hash(with[:password_hash]) 141 | } 142 | 143 | it { 144 | btitle = "#{with[:database_name]} grant read permission on new objects from #{with[:database_owner]} to #{with[:read_database_username]}" 145 | is_expected.to contain_postgresql__server__database_grant("#{with[:database_name]} grant connection permission to #{with[:read_database_username]}") 146 | .that_comes_before("Puppetdb::Database::Default_read_grant[#{btitle}]") 147 | .with( 148 | privilege: 'CONNECT', 149 | db: with[:database_name], 150 | role: with[:read_database_username], 151 | ) 152 | } 153 | 154 | it { 155 | rtitle = "#{with[:database_name]} grant read permission on new objects from #{with[:database_owner]} to #{with[:read_database_username]}" 156 | is_expected.to contain_puppetdb__database__default_read_grant(rtitle) 157 | .that_comes_before("Puppetdb::Database::Read_grant[#{with[:database_name]} grant read-only permission on existing objects to #{with[:read_database_username]}]") 158 | .with( 159 | database_username: with[:database_owner], 160 | database_read_only_username: with[:read_database_username], 161 | database_name: with[:database_name], 162 | schema: 'public', 163 | ) 164 | } 165 | 166 | it_behaves_like 'postgresql_psql default read grant' do 167 | let(:with) do 168 | { 169 | database_username: super()[:database_owner], 170 | database_read_only_username: super()[:read_database_username], 171 | database_name: super()[:database_name], 172 | } 173 | end 174 | end 175 | 176 | it { 177 | is_expected.to contain_puppetdb__database__read_grant("#{with[:database_name]} grant read-only permission on existing objects to #{with[:read_database_username]}") 178 | .with( 179 | database_read_only_username: with[:read_database_username], 180 | database_name: with[:database_name], 181 | schema: 'public', 182 | ) 183 | } 184 | 185 | it_behaves_like 'postgresql_psql read grant' do 186 | let(:with) do 187 | { 188 | database_read_only_username: super()[:read_database_username], 189 | database_name: super()[:database_name], 190 | } 191 | end 192 | end 193 | end 194 | end 195 | 196 | shared_examples 'puppetdb::database::read_grant' do |error| 197 | let(:defaults) { {} } 198 | let(:with) { defined?(args) ? defaults.merge(args) : defaults } 199 | 200 | if error 201 | it { is_expected.to raise_error(error) } 202 | else 203 | it { is_expected.to contain_puppetdb__database__read_grant(name).with(with) } 204 | 205 | include_examples 'postgresql_psql read grant' 206 | end 207 | end 208 | 209 | shared_examples 'puppetdb::database::default_read_grant' do |error| 210 | let(:defaults) { {} } 211 | let(:with) { defined?(args) ? defaults.merge(args) : defaults } 212 | 213 | if error 214 | it { is_expected.to raise_error(error) } 215 | else 216 | it { is_expected.to contain_puppetdb__database__default_read_grant(name).with(with) } 217 | 218 | include_examples 'postgresql_psql default read grant' 219 | end 220 | end 221 | 222 | shared_examples 'puppetdb::database::postgresql_ssl_rules' do |error| 223 | let(:defaults) { { postgres_version: '14' } } 224 | let(:with) { defined?(args) ? defaults.merge(args) : defaults } 225 | 226 | if error 227 | it { is_expected.to raise_error(error) } 228 | else 229 | let(:identity_map_key) { "#{with[:database_name]}-#{with[:database_username]}-map" } 230 | let(:client_cert) { (with[:postgres_version].to_f >= 12.0) ? 'verify-full' : '1' } 231 | 232 | it { is_expected.to contain_puppetdb__database__postgresql_ssl_rules(name).with(with) } 233 | 234 | it { 235 | is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{with[:database_name]} as #{with[:database_username]} (ipv4)") 236 | .with( 237 | type: 'hostssl', 238 | database: with[:database_name], 239 | user: with[:database_username], 240 | address: '0.0.0.0/0', 241 | auth_method: 'cert', 242 | order: 0, 243 | auth_option: "map=#{identity_map_key} clientcert=#{client_cert}", 244 | ) 245 | } 246 | 247 | it { 248 | is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{with[:database_name]} as #{with[:database_username]} (ipv6)") 249 | .with( 250 | type: 'hostssl', 251 | database: with[:database_name], 252 | user: with[:database_username], 253 | address: '::0/0', 254 | auth_method: 'cert', 255 | order: 0, 256 | auth_option: "map=#{identity_map_key} clientcert=#{client_cert}", 257 | ) 258 | } 259 | 260 | it { 261 | is_expected.to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{with[:database_username]} user") 262 | .with( 263 | map_name: identity_map_key, 264 | system_username: with[:puppetdb_server], 265 | database_username: with[:database_username], 266 | ) 267 | } 268 | end 269 | end 270 | -------------------------------------------------------------------------------- /spec/support/unit/shared/inherits.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | shared_examples 'puppetdb::params' do 4 | include_examples 'puppetdb::globals' 5 | 6 | it { is_expected.to contain_class('puppetdb::params') } 7 | end 8 | 9 | shared_examples 'puppetdb::globals' do |error = false| 10 | let(:defaults) do 11 | { 12 | version: 'present', 13 | puppet_confdir: Puppet[:confdir], 14 | } 15 | end 16 | 17 | let(:with) { defaults.merge(defined?(args) ? args : {}) } 18 | 19 | it { 20 | if error 21 | is_expected.to raise_error(error) 22 | else 23 | is_expected.to contain_class('puppetdb::globals').with(with) 24 | end 25 | } 26 | end 27 | -------------------------------------------------------------------------------- /spec/support/unit/shared/server.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | shared_examples 'puppetdb::server::firewall' do 4 | let(:defaults) do 5 | { 6 | http_port: '8080', 7 | open_http_port: false, 8 | ssl_port: '8081', 9 | open_ssl_port: false, 10 | } 11 | end 12 | 13 | let(:with) { defined?(params) ? defaults.merge(params) : defaults } 14 | 15 | it { is_expected.to contain_class('puppetdb::server::firewall').with(with) } 16 | it { is_expected.to contain_class('firewall') } 17 | 18 | it { 19 | option = with[:open_http_port] ? 'to' : 'not_to' 20 | is_expected.method(option).call contain_firewall("#{with[:http_port]} accept - puppetdb") 21 | .with( 22 | dport: with[:http_port], 23 | proto: 'tcp', 24 | jump: 'accept', 25 | ) 26 | } 27 | 28 | it { 29 | option = with[:open_ssl_port] ? 'to' : 'not_to' 30 | is_expected.method(option).call contain_firewall("#{with[:ssl_port]} accept - puppetdb") 31 | .with( 32 | dport: with[:ssl_port], 33 | proto: 'tcp', 34 | jump: 'accept', 35 | ) 36 | } 37 | end 38 | -------------------------------------------------------------------------------- /spec/unit/classes/database/postgresql_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'puppetdb::database::postgresql', type: :class do 6 | let(:facts) { on_supported_os.take(1).first[1] } 7 | 8 | context 'on a supported platform' do 9 | it { is_expected.to contain_class('puppetdb::database::postgresql') } 10 | 11 | it { is_expected.to contain_class('postgresql::server::contrib') } 12 | 13 | it { 14 | is_expected.to contain_postgresql__server__extension('pg_trgm') 15 | .that_requires('Postgresql::Server::Db[puppetdb]') 16 | .with_database('puppetdb') 17 | } 18 | 19 | context 'when ssl communication is used' do 20 | let(:params) do 21 | { 22 | postgresql_ssl_on: true, 23 | } 24 | end 25 | 26 | it { is_expected.to contain_class('puppetdb::database::ssl_configuration') } 27 | 28 | context 'when params disable create_read_user_rule' do 29 | let(:params) { super().merge({ manage_database: false }) } 30 | 31 | it { is_expected.not_to contain_puppetdb__database__postgresql_ssl_rules('Configure postgresql ssl rules for puppetdb-read') } 32 | end 33 | end 34 | 35 | context 'when ssl communication is not used' do 36 | let(:params) do 37 | { 38 | postgresql_ssl_on: false, 39 | } 40 | end 41 | 42 | it { is_expected.not_to contain_class('puppetdb::database::ssl_configuration') } 43 | end 44 | 45 | context 'manage database with defaults' do 46 | let(:params) do 47 | { 48 | manage_database: true, 49 | database_name: 'puppetdb', 50 | database_username: 'puppetdb', 51 | database_password: 'puppetdb', 52 | read_database_username: 'puppetdb-read', 53 | read_database_password: 'puppetdb-read', 54 | database_port: '5432', 55 | } 56 | end 57 | 58 | it { 59 | is_expected.to contain_postgresql__server__db(params[:database_name]) 60 | .with( 61 | user: params[:database_username], 62 | password: params[:database_password], 63 | grant: 'all', 64 | port: params[:database_port].to_i, 65 | encoding: 'UTF8', 66 | locale: 'en_US.UTF-8', 67 | ) 68 | } 69 | 70 | it { 71 | is_expected.to contain_postgresql_psql('revoke all access on public schema') 72 | .that_requires("Postgresql::Server::Db[#{params[:database_name]}]") 73 | .with( 74 | db: params[:database_name], 75 | port: params[:database_port].to_i, 76 | command: 'REVOKE CREATE ON SCHEMA public FROM public', 77 | unless: "SELECT * FROM 78 | (SELECT has_schema_privilege('public', 'public', 'create') can_create) privs 79 | WHERE privs.can_create=false", 80 | ) 81 | } 82 | 83 | it { 84 | is_expected.to contain_postgresql_psql("grant all permissions to #{params[:database_username]}") 85 | .that_requires('Postgresql_psql[revoke all access on public schema]') 86 | .that_comes_before("Puppetdb::Database::Read_only_user[#{params[:read_database_username]}]") 87 | .with( 88 | db: params[:database_name], 89 | port: params[:database_port].to_i, 90 | command: "GRANT CREATE ON SCHEMA public TO \"#{params[:database_username]}\"", 91 | unless: "SELECT * FROM 92 | (SELECT has_schema_privilege('#{params[:database_username]}', 'public', 'create') can_create) privs 93 | WHERE privs.can_create=true", 94 | ) 95 | } 96 | 97 | it_behaves_like 'puppetdb::database::read_only_user' do 98 | let(:name) { 'puppetdb-read' } 99 | let(:args) do 100 | { 101 | read_database_username: params[:read_database_username], 102 | database_name: params[:database_name], 103 | password_hash: %r{^(md5|SCRAM)}, # TODO: mock properly 104 | database_owner: params[:database_username], 105 | database_port: params[:database_port].to_i, 106 | } 107 | end 108 | end 109 | 110 | it { 111 | is_expected.to contain_postgresql_psql("grant #{params[:read_database_username]} role to #{params[:database_username]}") 112 | .that_requires("Puppetdb::Database::Read_only_user[#{params[:read_database_username]}]") 113 | .with( 114 | db: params[:database_name], 115 | port: params[:database_port].to_i, 116 | command: "GRANT \"#{params[:read_database_username]}\" TO \"#{params[:database_username]}\"", 117 | unless: "SELECT oid, rolname FROM pg_roles WHERE 118 | pg_has_role( '#{params[:database_username]}', oid, 'member') and rolname = '#{params[:read_database_username]}'", 119 | ) 120 | } 121 | end 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /spec/unit/classes/database/ssl_configuration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::database::ssl_configuration', type: :class do 4 | context 'on a supported platform' do 5 | let(:facts) { on_supported_os.take(1).first[1] } 6 | 7 | let(:params) do 8 | { 9 | postgresql_ssl_key_path: '/puppet/ssl/key.pem', 10 | postgresql_ssl_cert_path: '/puppet/ssl/cert.pem', 11 | postgresql_ssl_ca_cert_path: '/puppet/cert/ca.pem', 12 | database_name: 'puppetdb', 13 | database_username: 'puppetdb', 14 | read_database_username: 'puppetdb-read', 15 | } 16 | end 17 | 18 | let(:identity_map) { "#{params[:database_name]}-#{params[:database_username]}-map" } 19 | let(:read_identity_map) { "#{params[:database_name]}-#{params[:read_database_username]}-map" } 20 | let(:datadir_path) { '/var/lib/data' } 21 | 22 | let(:pre_condition) do 23 | "class { 'postgresql::server': datadir => '/var/lib/data'} " 24 | end 25 | 26 | it { is_expected.to contain_class('puppetdb::database::ssl_configuration') } 27 | it { is_expected.to compile.with_all_deps } 28 | 29 | it 'has server.key file' do 30 | is_expected.to contain_file('postgres private key') 31 | .with( 32 | ensure: 'present', 33 | owner: 'postgres', 34 | mode: '0600', 35 | path: "#{datadir_path}/server.key", 36 | ) 37 | .that_requires('Package[postgresql-server]') 38 | end 39 | 40 | it 'has server.crt file' do 41 | is_expected.to contain_file('postgres public key') 42 | .with( 43 | ensure: 'present', 44 | owner: 'postgres', 45 | mode: '0600', 46 | path: "#{datadir_path}/server.crt", 47 | ) 48 | .that_requires('Package[postgresql-server]') 49 | end 50 | 51 | it 'has ssl config attribute' do 52 | is_expected.to contain_postgresql__server__config_entry('ssl') 53 | .with_value('on').with_ensure('present') 54 | .that_requires('File[postgres private key]') 55 | .that_requires('File[postgres public key]') 56 | end 57 | 58 | it 'has ssl_cert_file config attribute' do 59 | is_expected.to contain_postgresql__server__config_entry('ssl_cert_file') 60 | .with_value("#{datadir_path}/server.crt").with_ensure('present') 61 | .that_requires('File[postgres private key]') 62 | .that_requires('File[postgres public key]') 63 | end 64 | 65 | it 'has ssl_key_file config attribute' do 66 | is_expected.to contain_postgresql__server__config_entry('ssl_key_file') 67 | .with_value("#{datadir_path}/server.key").with_ensure('present') 68 | .that_requires('File[postgres private key]') 69 | .that_requires('File[postgres public key]') 70 | end 71 | 72 | it 'has ssl_ca_file config attribute' do 73 | is_expected.to contain_postgresql__server__config_entry('ssl_ca_file') 74 | .with_value(params[:postgresql_ssl_ca_cert_path]).with_ensure('present') 75 | .that_requires('File[postgres private key]') 76 | .that_requires('File[postgres public key]') 77 | end 78 | 79 | context 'does not create ssl rules for puppetdb-read user by default' do 80 | it { is_expected.not_to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:read_database_username]} (ipv4)") } 81 | it { is_expected.not_to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:read_database_username]} (ipv6)") } 82 | it { is_expected.not_to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{params[:read_database_username]} user") } 83 | end 84 | 85 | context 'configure ssl rules' do 86 | let(:name) { "Configure postgresql ssl rules for #{args[:database_username]}" } 87 | let(:args) do 88 | { 89 | database_name: params[:database_name], 90 | database_username: params[:database_username], 91 | puppetdb_server: params[:puppetdb_server] || facts[:networking]['fqdn'], 92 | } 93 | end 94 | 95 | context 'when the puppetdb_server is not set' do 96 | include_examples 'puppetdb::database::postgresql_ssl_rules' 97 | end 98 | 99 | context 'when the puppetdb_server is set' do 100 | let(:params) { super().merge({ puppetdb_server: 'puppetdb_fqdn' }) } 101 | 102 | include_examples 'puppetdb::database::postgresql_ssl_rules' 103 | end 104 | 105 | context 'when the create_read_user_rule is true' do 106 | let(:params) { super().merge({ create_read_user_rule: true }) } 107 | 108 | it_behaves_like 'puppetdb::database::postgresql_ssl_rules' do 109 | let(:args) { super().merge({ database_username: params[:read_database_username] }) } 110 | end 111 | end 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /spec/unit/classes/globals_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::globals', type: :class do 4 | # loop required to test fail function 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let(:facts) { facts } 8 | 9 | include_examples 'puppetdb::globals' 10 | end 11 | end 12 | 13 | context 'on other os' do 14 | include_examples 'puppetdb::globals', %r{puppetdb does not support your os} do 15 | let(:facts) { { os: { 'family' => 'Nonsense' } } } 16 | end 17 | end 18 | 19 | context 'on invalid confdir' do 20 | include_examples 'puppetdb::globals', Puppet::ParseError do 21 | let(:params) { { puppet_confdir: './relative' } } 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/unit/classes/init_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb', type: :class do 4 | ttl_args = ['node_ttl', 'node_purge_ttl', 'report_ttl'] 5 | 6 | on_supported_os.each do |os, facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | facts.merge(selinux: false, service_provider: 'systemd') 10 | end 11 | 12 | describe 'when using default values for puppetdb class' do 13 | it { is_expected.to compile.with_all_deps } 14 | it { is_expected.to contain_class('puppetdb') } 15 | it { is_expected.to contain_class('puppetdb::server') } 16 | it { is_expected.to contain_class('puppetdb::database::postgresql') } 17 | it { is_expected.to contain_postgresql__server__db('puppetdb') } 18 | end 19 | 20 | describe 'without managed postgresql' do 21 | let :pre_condition do 22 | <<-HEREDOC 23 | class { 'postgresql::server': 24 | } 25 | HEREDOC 26 | end 27 | 28 | let :params do 29 | { 30 | manage_dbserver: false, 31 | } 32 | end 33 | 34 | describe 'manifest' do 35 | it { is_expected.to compile.with_all_deps } 36 | end 37 | end 38 | describe 'without managed postgresql database' do 39 | let :params do 40 | { 41 | manage_dbserver: true, 42 | manage_database: false, 43 | } 44 | end 45 | 46 | describe 'manifest' do 47 | it { is_expected.to compile.with_all_deps } 48 | it { is_expected.not_to contain_postgresql__server__db('puppetdb') } 49 | end 50 | end 51 | 52 | context 'when not managing the database password' do 53 | let(:params) do 54 | { 55 | 'manage_db_password' => false, 56 | 'manage_read_db_password' => false, 57 | 'read_database_host' => '10.0.0.1', # Make sure the read_database class is enforced. 58 | } 59 | end 60 | 61 | describe 'ini_setting entries for the password will not exist' do 62 | it { is_expected.to contain_class('puppetdb::server').with('manage_db_password' => false) } 63 | it { is_expected.to contain_class('puppetdb::server').with('manage_read_db_password' => false) } 64 | 65 | it { is_expected.not_to contain_ini__setting('puppetdb_psdatabase_password') } 66 | it { is_expected.not_to contain_ini__setting('puppetdb_read_database_password') } 67 | end 68 | end 69 | 70 | context 'with password encryption' do 71 | let :params do 72 | { 73 | postgresql_password_encryption: 'md5', 74 | } 75 | end 76 | 77 | it do 78 | is_expected.to contain_postgresql__server__pg_hba_rule('allow access to all users for instance main') 79 | .with_type('host') 80 | .with_database('all') 81 | .with_user('all') 82 | .with_auth_method('md5') 83 | end 84 | end 85 | 86 | context 'when using ssl certificates' do 87 | let(:params) do 88 | { 89 | postgresql_ssl_on: true, 90 | puppetdb_server: 'puppetdb.example.com', 91 | } 92 | end 93 | 94 | it { is_expected.to contain_class('puppetdb::server').with('postgresql_ssl_on' => true) } 95 | it { 96 | is_expected.to contain_class('puppetdb::database::postgresql') 97 | .with( 98 | 'postgresql_ssl_on' => true, 99 | 'puppetdb_server' => 'puppetdb.example.com', 100 | ) 101 | } 102 | end 103 | end 104 | end 105 | 106 | context 'with invalid arguments on a supported platform' do 107 | let(:facts) do 108 | { 109 | osfamily: 'RedHat', 110 | operatingsystem: 'Debian', 111 | puppetversion: Puppet.version, 112 | operatingsystemrelease: '6.0', 113 | kernel: 'Linux', 114 | concat_basedir: '/var/lib/puppet/concat', 115 | selinux: true, 116 | iptables_persistent_version: '0.5.7', 117 | } 118 | end 119 | 120 | ttl_args.each do |ttl_arg| 121 | let(:params) do 122 | { 123 | ttl_arg => 'invalid_value', 124 | } 125 | end 126 | 127 | it "when using a value that does not match the validation regex for #{ttl_arg} puppetdb class" do 128 | expect { is_expected.to contain_class('puppetdb') }.to raise_error(Puppet::Error) 129 | end 130 | end 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /spec/unit/classes/master/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::master::config', type: :class do 4 | let(:node) { 'puppetdb.example.com' } 5 | 6 | on_supported_os.each do |os, facts| 7 | context "on #{os}" do 8 | let(:facts) { facts } 9 | 10 | context 'when PuppetDB on remote server' do 11 | context 'when using default values' do 12 | it { is_expected.to compile.with_all_deps } 13 | end 14 | end 15 | 16 | context 'when PuppetDB and Puppet Master are on the same server' do 17 | context 'when using default values' do 18 | let(:pre_condition) { 'class { "puppetdb": }' } 19 | 20 | it { 21 | is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( 22 | puppetdb_server: 'puppetdb.example.com', 23 | puppetdb_port: '8081', 24 | use_ssl: 'true', 25 | ) 26 | } 27 | end 28 | 29 | context 'when puppetdb class is declared with disable_ssl => true' do 30 | let(:pre_condition) { 'class { "puppetdb": disable_ssl => true }' } 31 | 32 | it { 33 | is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( 34 | puppetdb_port: '8080', 35 | use_ssl: 'false', 36 | ) 37 | } 38 | end 39 | 40 | context 'when puppetdb_port => 1234' do 41 | let(:pre_condition) { 'class { "puppetdb": }' } 42 | let(:params) { { puppetdb_port: '1234' } } 43 | 44 | it { 45 | is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( 46 | puppetdb_port: '1234', 47 | use_ssl: 'true', 48 | ) 49 | } 50 | end 51 | 52 | context 'when puppetdb_port => 1234 AND the puppetdb class is declared with disable_ssl => true' do 53 | let(:pre_condition) { 'class { "puppetdb": disable_ssl => true }' } 54 | let(:params) { { puppetdb_port: '1234' } } 55 | 56 | it { 57 | is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( 58 | puppetdb_port: '1234', 59 | use_ssl: 'false', 60 | ) 61 | } 62 | end 63 | 64 | context 'when using default values' do 65 | it { is_expected.to contain_package('puppetdb-termini').with(ensure: 'present') } 66 | it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with(test_url: '/pdb/meta/v1/version') } 67 | end 68 | 69 | context 'when using an older puppetdb version' do 70 | let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } 71 | 72 | it { is_expected.to contain_package('puppetdb-terminus').with(ensure: '2.2.0') } 73 | it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with(test_url: '/v3/version') } 74 | it { 75 | is_expected.to contain_service('puppetmaster') 76 | .with_ensure('running') 77 | .with_enable(true) 78 | } 79 | end 80 | end 81 | 82 | context 'when restart_puppet is true' do 83 | let(:pre_condition) { 'class { "puppetdb": }' } 84 | 85 | context 'with create_puppet_service_resource as default' do 86 | let(:params) do 87 | { 88 | puppet_service_name: 'puppetserver', 89 | restart_puppet: true, 90 | } 91 | end 92 | 93 | it { is_expected.to contain_service('puppetserver').with(ensure: 'running') } 94 | end 95 | 96 | context 'with create_puppet_service_resource = true' do 97 | let(:params) do 98 | { 99 | create_puppet_service_resource: true, 100 | puppet_service_name: 'puppetserver', 101 | restart_puppet: true, 102 | } 103 | end 104 | 105 | it { is_expected.to contain_service('puppetserver').with(ensure: 'running') } 106 | end 107 | 108 | context 'with create_puppet_service_resource = false' do 109 | # Also setting the various parameters that notify the service to be false. Otherwise this error surfaces: 110 | # `Could not find resource 'Service[puppetserver]' for relationship from 'Class[Puppetdb::Master::Puppetdb_conf]'` 111 | let(:params) do 112 | { 113 | create_puppet_service_resource: false, 114 | manage_config: false, 115 | manage_report_processor: false, 116 | manage_routes: false, 117 | puppet_service_name: 'puppetserver', 118 | restart_puppet: true, 119 | } 120 | end 121 | 122 | it { is_expected.not_to contain_service('puppetserver') } 123 | end 124 | end 125 | 126 | context 'when upgrading to from v2 to v3 of PuppetDB on RedHat', if: os =~ %r{^redhat-7} do 127 | let(:pre_condition) { 'class { "puppetdb::globals": version => "3.1.1-1.el7", }' } 128 | 129 | it { is_expected.to contain_exec('Remove puppetdb-terminus metadata for upgrade').with(command: 'rpm -e --justdb puppetdb-terminus') } 130 | end 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /spec/unit/classes/master/puppetdb_conf_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::master::puppetdb_conf', type: :class do 4 | let :node do 5 | 'puppetdb.example.com' 6 | end 7 | 8 | on_supported_os.each do |os, facts| 9 | context "on #{os}" do 10 | let(:facts) do 11 | facts.merge(puppetversion: Puppet.version, 12 | service_provider: 'systemd', 13 | selinux: false) 14 | end 15 | 16 | let(:pre_condition) { 'class { "puppetdb": }' } 17 | 18 | it { 19 | is_expected.to contain_ini_setting('soft_write_failure') 20 | .with_setting('soft_write_failure') 21 | .with_value(false) 22 | } 23 | 24 | context 'when using default values' do 25 | it { is_expected.to contain_ini_setting('puppetdbserver_urls').with(value: 'https://localhost:8081/') } 26 | end 27 | 28 | context 'when using legacy_terminus' do 29 | let(:params) { { legacy_terminus: true } } 30 | 31 | it { is_expected.to contain_ini_setting('puppetdbserver').with(value: 'localhost') } 32 | it { is_expected.to contain_ini_setting('puppetdbport').with(value: '8081') } 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/unit/classes/master/report_processor_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::master::report_processor', type: :class do 4 | around(:each) do |example| 5 | confdir = RSpec.configuration.confdir 6 | RSpec.configuration.confdir = '/etc/puppet' 7 | example.run 8 | RSpec.configuration.confdir = confdir 9 | end 10 | 11 | on_supported_os.each do |os, facts| 12 | context "on #{os}" do 13 | let(:facts) do 14 | facts.merge(puppetversion: Puppet.version, 15 | service_provider: 'systemd', 16 | clientcert: 'test.domain.local') 17 | end 18 | 19 | it { is_expected.to contain_class('puppetdb::master::report_processor') } 20 | 21 | describe 'when using default values' do 22 | it { 23 | is_expected.to contain_ini_subsetting('puppet.conf/reports/puppetdb') 24 | .with( 25 | 'ensure' => 'absent', 26 | 'path' => '/etc/puppet/puppet.conf', 27 | 'section' => 'master', 28 | 'setting' => 'reports', 29 | 'subsetting' => 'puppetdb', 30 | 'subsetting_separator' => ',', 31 | ) 32 | } 33 | end 34 | 35 | describe 'when enabling reports' do 36 | let(:params) do 37 | { 38 | 'enable' => true, 39 | } 40 | end 41 | 42 | it { 43 | is_expected.to contain_ini_subsetting('puppet.conf/reports/puppetdb') 44 | .with( 45 | 'ensure' => 'present', 46 | 'path' => '/etc/puppet/puppet.conf', 47 | 'section' => 'master', 48 | 'setting' => 'reports', 49 | 'subsetting' => 'puppetdb', 50 | 'subsetting_separator' => ',', 51 | ) 52 | } 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/unit/classes/master/routes_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | shared_examples 'routes master.facts.cache format' do |format| 6 | it "is expected to set master.facts.cache to equal #{format} in routes.yaml" do 7 | yaml_data = catalogue.resource('file', "#{params[:puppet_confdir]}/routes.yaml").send(:parameters)[:content] 8 | parsed = YAML.safe_load(yaml_data, symbolize_names: true) 9 | 10 | expect(parsed[:master][:facts][:cache]).to eq format.to_s 11 | end 12 | end 13 | 14 | describe 'puppetdb::master::routes', type: :class do 15 | let(:facts) { on_supported_os.take(1).first[1] } 16 | let(:params) do 17 | { 18 | puppet_confdir: Puppet[:confdir], 19 | masterless: false, 20 | } 21 | end 22 | 23 | let(:serverversion) { Puppet.version } 24 | 25 | let(:routes_real) do 26 | if params[:masterless] 27 | { 28 | apply: { 29 | catalog: { 30 | terminus: 'compiler', 31 | cache: 'puppetdb', 32 | }, 33 | facts: { 34 | terminus: 'facter', 35 | cache: 'puppetdb_apply', 36 | }, 37 | }, 38 | } 39 | elsif params[:routes] 40 | params[:routes] 41 | else 42 | { 43 | master: { 44 | facts: { 45 | terminus: 'puppetdb', 46 | cache: (Puppet::Util::Package.versioncmp(serverversion, '7.0') >= 0) ? 'json' : 'yaml' 47 | }, 48 | } 49 | } 50 | end 51 | end 52 | 53 | context 'with defaults' do 54 | it { 55 | is_expected.to contain_file("#{params[:puppet_confdir]}/routes.yaml") 56 | .with( 57 | ensure: 'file', 58 | mode: '0644', 59 | ) 60 | } 61 | 62 | it { 63 | yaml_data = catalogue.resource('file', "#{params[:puppet_confdir]}/routes.yaml").send(:parameters)[:content] 64 | parsed = YAML.safe_load(yaml_data, symbolize_names: true) 65 | 66 | expect(parsed).to eq routes_real 67 | } 68 | end 69 | 70 | # TODO: remove puppetserver 6 support 71 | # unable to easily test puppetserver 6 with rspec 72 | # and it's not a supported version 73 | context "with puppetserver version #{Puppet.version}" do 74 | include_examples 'routes master.facts.cache format', :json 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/unit/classes/master/storeconfigs_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'puppetdb::master::storeconfigs', type: :class do 6 | let(:facts) { on_supported_os.take(1).first[1] } 7 | let(:params) do 8 | { 9 | masterless: false, 10 | enable: true, 11 | } 12 | end 13 | 14 | let(:param_ensure) { params[:enable] ? 'present' : 'absent' } 15 | let(:puppet_conf_section) { params[:masterless] ? 'main' : 'master' } 16 | let(:puppet_conf) { File.join(Puppet[:confdir], 'puppet.conf') } 17 | 18 | context 'with default parameters' do 19 | it { 20 | is_expected.to contain_ini_setting("puppet.conf/#{puppet_conf_section}/storeconfigs") 21 | .with_ensure(param_ensure) 22 | .with( 23 | section: puppet_conf_section, 24 | path: puppet_conf, 25 | setting: 'storeconfigs', 26 | value: true, 27 | ) 28 | } 29 | it { 30 | is_expected.to contain_ini_setting("puppet.conf/#{puppet_conf_section}/storeconfigs_backend") 31 | .with_ensure(param_ensure) 32 | .with( 33 | section: puppet_conf_section, 34 | path: puppet_conf, 35 | setting: 'storeconfigs_backend', 36 | value: 'puppetdb', 37 | ) 38 | } 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/unit/classes/params_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::params', type: :class do 4 | # loop required to test fail function 5 | on_supported_os.each do |os, facts| 6 | let(:facts) { facts } 7 | context "on #{os}" do 8 | it { is_expected.to contain_class('puppetdb::globals') } 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/unit/classes/server/command_processing_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::command_processing', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | let(:pre_condition) { 'include puppetdb::server::global' } 7 | 8 | it { is_expected.to contain_class('puppetdb::server::command_processing') } 9 | 10 | describe 'when using default values' do 11 | it { 12 | is_expected.to contain_ini_setting('puppetdb_command_processing_threads') 13 | .with( 14 | 'ensure' => 'absent', 15 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 16 | 'section' => 'command-processing', 17 | 'setting' => 'threads', 18 | ) 19 | } 20 | it { 21 | is_expected.to contain_ini_setting('puppetdb_command_processing_concurrent_writes') 22 | .with( 23 | 'ensure' => 'absent', 24 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 25 | 'section' => 'command-processing', 26 | 'setting' => 'concurrent-writes', 27 | ) 28 | } 29 | it { 30 | is_expected.to contain_ini_setting('puppetdb_command_processing_store_usage') 31 | .with( 32 | 'ensure' => 'absent', 33 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 34 | 'section' => 'command-processing', 35 | 'setting' => 'store-usage', 36 | ) 37 | } 38 | it { 39 | is_expected.to contain_ini_setting('puppetdb_command_processing_temp_usage') 40 | .with( 41 | 'ensure' => 'absent', 42 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 43 | 'section' => 'command-processing', 44 | 'setting' => 'temp-usage', 45 | ) 46 | } 47 | end 48 | 49 | describe 'when using legacy PuppetDB' do 50 | let(:pre_condition) do 51 | [ 52 | 'class { "puppetdb::globals": version => "2.2.0", }', 53 | super(), 54 | ].join("\n") 55 | end 56 | 57 | it { 58 | is_expected.to contain_ini_setting('puppetdb_command_processing_threads') 59 | .with( 60 | 'ensure' => 'absent', 61 | 'path' => '/etc/puppetdb/conf.d/config.ini', 62 | 'section' => 'command-processing', 63 | 'setting' => 'threads', 64 | ) 65 | } 66 | it { 67 | is_expected.to contain_ini_setting('puppetdb_command_processing_store_usage') 68 | .with( 69 | 'ensure' => 'absent', 70 | 'path' => '/etc/puppetdb/conf.d/config.ini', 71 | 'section' => 'command-processing', 72 | 'setting' => 'store-usage', 73 | ) 74 | } 75 | it { 76 | is_expected.to contain_ini_setting('puppetdb_command_processing_temp_usage') 77 | .with( 78 | 'ensure' => 'absent', 79 | 'path' => '/etc/puppetdb/conf.d/config.ini', 80 | 'section' => 'command-processing', 81 | 'setting' => 'temp-usage', 82 | ) 83 | } 84 | end 85 | 86 | describe 'when using custom values' do 87 | let(:params) do 88 | { 89 | 'command_threads' => 10, 90 | 'concurrent_writes' => 3, 91 | 'store_usage' => 4000, 92 | 'temp_usage' => 2000, 93 | } 94 | end 95 | 96 | it { 97 | is_expected.to contain_ini_setting('puppetdb_command_processing_threads') 98 | .with( 99 | 'ensure' => 'present', 100 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 101 | 'section' => 'command-processing', 102 | 'setting' => 'threads', 103 | 'value' => '10', 104 | ) 105 | } 106 | it { 107 | is_expected.to contain_ini_setting('puppetdb_command_processing_concurrent_writes') 108 | .with( 109 | 'ensure' => 'present', 110 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 111 | 'section' => 'command-processing', 112 | 'setting' => 'concurrent-writes', 113 | 'value' => '3', 114 | ) 115 | } 116 | it { 117 | is_expected.to contain_ini_setting('puppetdb_command_processing_store_usage') 118 | .with( 119 | 'ensure' => 'present', 120 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 121 | 'section' => 'command-processing', 122 | 'setting' => 'store-usage', 123 | 'value' => '4000', 124 | ) 125 | } 126 | it { 127 | is_expected.to contain_ini_setting('puppetdb_command_processing_temp_usage') 128 | .with( 129 | 'ensure' => 'present', 130 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 131 | 'section' => 'command-processing', 132 | 'setting' => 'temp-usage', 133 | 'value' => '2000', 134 | ) 135 | } 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /spec/unit/classes/server/database_ini_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::database', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | it { is_expected.to contain_class('puppetdb::server::database') } 7 | 8 | ['default', 'legacy'].each do |values| 9 | describe "when using #{values} values" do 10 | let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } if values == 'legacy' 11 | let(:pdbconfdir) do 12 | if values == 'legacy' 13 | '/etc/puppetdb/conf.d' 14 | else 15 | '/etc/puppetlabs/puppetdb/conf.d' 16 | end 17 | end 18 | 19 | it { 20 | is_expected.to contain_file("#{pdbconfdir}/database.ini") 21 | .with( 22 | 'ensure' => 'file', 23 | 'owner' => 'root', 24 | 'group' => 'puppetdb', 25 | 'mode' => '0640', 26 | ) 27 | } 28 | it { 29 | is_expected.to contain_ini_setting('puppetdb_psdatabase_username') 30 | .with( 31 | 'ensure' => 'present', 32 | 'path' => "#{pdbconfdir}/database.ini", 33 | 'section' => 'database', 34 | 'setting' => 'username', 35 | 'value' => 'puppetdb', 36 | ) 37 | } 38 | it { 39 | is_expected.to contain_ini_setting('puppetdb_psdatabase_password') 40 | .with( 41 | 'ensure' => 'present', 42 | 'path' => "#{pdbconfdir}/database.ini", 43 | 'section' => 'database', 44 | 'setting' => 'password', 45 | 'value' => 'puppetdb', 46 | 'show_diff' => false, 47 | ) 48 | } 49 | it { 50 | is_expected.to contain_ini_setting('puppetdb_pgs') 51 | .with( 52 | 'ensure' => 'present', 53 | 'path' => "#{pdbconfdir}/database.ini", 54 | 'section' => 'database', 55 | 'setting' => 'syntax_pgs', 56 | 'value' => true, 57 | ) 58 | } 59 | it { 60 | is_expected.to contain_ini_setting('puppetdb_subname') 61 | .with( 62 | 'ensure' => 'present', 63 | 'path' => "#{pdbconfdir}/database.ini", 64 | 'section' => 'database', 65 | 'setting' => 'subname', 66 | 'value' => '//localhost:5432/puppetdb', 67 | ) 68 | } 69 | it { 70 | is_expected.to contain_ini_setting('puppetdb_gc_interval') 71 | .with( 72 | 'ensure' => 'present', 73 | 'path' => "#{pdbconfdir}/database.ini", 74 | 'section' => 'database', 75 | 'setting' => 'gc-interval', 76 | 'value' => '60', 77 | ) 78 | } 79 | it { 80 | is_expected.to contain_ini_setting('puppetdb_node_purge_gc_batch_limit') 81 | .with( 82 | 'ensure' => 'present', 83 | 'path' => "#{pdbconfdir}/database.ini", 84 | 'section' => 'database', 85 | 'setting' => 'node-purge-gc-batch-limit', 86 | 'value' => '25', 87 | ) 88 | } 89 | it { 90 | is_expected.to contain_ini_setting('puppetdb_node_ttl') 91 | .with( 92 | 'ensure' => 'present', 93 | 'path' => "#{pdbconfdir}/database.ini", 94 | 'section' => 'database', 95 | 'setting' => 'node-ttl', 96 | 'value' => '7d', 97 | ) 98 | } 99 | it { 100 | is_expected.to contain_ini_setting('puppetdb_node_purge_ttl') 101 | .with( 102 | 'ensure' => 'present', 103 | 'path' => "#{pdbconfdir}/database.ini", 104 | 'section' => 'database', 105 | 'setting' => 'node-purge-ttl', 106 | 'value' => '14d', 107 | ) 108 | } 109 | it { 110 | is_expected.to contain_ini_setting('puppetdb_report_ttl') 111 | .with( 112 | 'ensure' => 'present', 113 | 'path' => "#{pdbconfdir}/database.ini", 114 | 'section' => 'database', 115 | 'setting' => 'report-ttl', 116 | 'value' => '14d', 117 | ) 118 | } 119 | it { 120 | is_expected.to contain_ini_setting('puppetdb_conn_max_age') 121 | .with( 122 | 'ensure' => 'present', 123 | 'path' => "#{pdbconfdir}/database.ini", 124 | 'section' => 'database', 125 | 'setting' => 'conn-max-age', 126 | 'value' => '60', 127 | ) 128 | } 129 | it { 130 | is_expected.to contain_ini_setting('puppetdb_conn_lifetime') 131 | .with( 132 | 'ensure' => 'present', 133 | 'path' => "#{pdbconfdir}/database.ini", 134 | 'section' => 'database', 135 | 'setting' => 'conn-lifetime', 136 | 'value' => '0', 137 | ) 138 | } 139 | it { 140 | is_expected.to contain_ini_setting('puppetdb_migrate') 141 | .with( 142 | 'ensure' => 'present', 143 | 'path' => "#{pdbconfdir}/database.ini", 144 | 'section' => 'database', 145 | 'setting' => 'migrate', 146 | 'value' => true, 147 | ) 148 | } 149 | it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } 150 | it { 151 | is_expected.to contain_ini_setting('puppetdb_facts_blacklist') 152 | .with( 153 | 'ensure' => 'absent', 154 | 'path' => "#{pdbconfdir}/database.ini", 155 | 'section' => 'database', 156 | 'setting' => 'facts-blacklist', 157 | ) 158 | } 159 | end 160 | end 161 | 162 | describe 'when using facts_blacklist' do 163 | let(:params) do 164 | { 165 | 'facts_blacklist' => [ 166 | 'one_fact', 167 | 'another_fact', 168 | ], 169 | } 170 | end 171 | 172 | it { 173 | is_expected.to contain_ini_setting('puppetdb_facts_blacklist') 174 | .with( 175 | 'ensure' => 'present', 176 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 177 | 'section' => 'database', 178 | 'setting' => 'facts-blacklist', 179 | 'value' => 'one_fact, another_fact', 180 | ) 181 | } 182 | end 183 | 184 | describe 'when setting max pool size' do 185 | context 'on current PuppetDB' do 186 | describe 'to a numeric value' do 187 | let(:params) do 188 | { 189 | 'database_max_pool_size' => 12_345, 190 | } 191 | end 192 | 193 | it { 194 | is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') 195 | .with( 196 | 'ensure' => 'present', 197 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 198 | 'section' => 'database', 199 | 'setting' => 'maximum-pool-size', 200 | 'value' => '12345', 201 | ) 202 | } 203 | end 204 | 205 | describe 'to absent' do 206 | let(:params) do 207 | { 208 | 'database_max_pool_size' => 'absent', 209 | } 210 | end 211 | 212 | it { 213 | is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') 214 | .with( 215 | 'ensure' => 'absent', 216 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 217 | 'section' => 'database', 218 | 'setting' => 'maximum-pool-size', 219 | ) 220 | } 221 | end 222 | end 223 | 224 | context 'on PuppetDB 3.2' do 225 | let(:pre_condition) { 'class { "puppetdb::globals": version => "3.2.0", }' } 226 | 227 | describe 'to a numeric value' do 228 | let(:params) do 229 | { 230 | 'database_max_pool_size' => 12_345, 231 | } 232 | end 233 | 234 | it { 235 | is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') 236 | .with( 237 | 'ensure' => 'present', 238 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 239 | 'section' => 'database', 240 | 'setting' => 'partition-conn-max', 241 | 'value' => '12345', 242 | ) 243 | } 244 | end 245 | 246 | describe 'to absent' do 247 | let(:params) do 248 | { 249 | 'database_max_pool_size' => 'absent', 250 | } 251 | end 252 | 253 | it { 254 | is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') 255 | .with( 256 | 'ensure' => 'absent', 257 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 258 | 'section' => 'database', 259 | 'setting' => 'partition-conn-max', 260 | ) 261 | } 262 | end 263 | end 264 | 265 | context 'on a legacy PuppetDB version' do 266 | let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } 267 | 268 | describe 'to a numeric value' do 269 | let(:params) do 270 | { 271 | 'database_max_pool_size' => 12_345, 272 | } 273 | end 274 | 275 | it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } 276 | end 277 | 278 | describe 'to absent' do 279 | let(:params) do 280 | { 281 | 'database_max_pool_size' => 'absent', 282 | } 283 | end 284 | 285 | it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } 286 | end 287 | end 288 | end 289 | 290 | describe 'when using ssl communication' do 291 | let(:params) do 292 | { 293 | 'postgresql_ssl_on' => true, 294 | 'ssl_key_pk8_path' => '/tmp/private_key.pk8', 295 | } 296 | end 297 | 298 | it 'configures subname correctly' do 299 | is_expected.to contain_ini_setting('puppetdb_subname') 300 | .with( 301 | ensure: 'present', 302 | path: '/etc/puppetlabs/puppetdb/conf.d/database.ini', 303 | section: 'database', 304 | setting: 'subname', 305 | value: '//localhost:5432/puppetdb?' \ 306 | 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ 307 | 'sslmode=verify-full&' \ 308 | 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ 309 | 'sslkey=/tmp/private_key.pk8&' \ 310 | 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', 311 | ) 312 | end 313 | end 314 | end 315 | -------------------------------------------------------------------------------- /spec/unit/classes/server/db_connection_uri_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::database', type: :class do 4 | context 'on a supported platform' do 5 | let(:facts) do 6 | { 7 | os: { 8 | family: 'RedHat', 9 | }, 10 | operatingsystemrelease: '7.0', 11 | networking: { 12 | fqdn: 'test.domain.local', 13 | }, 14 | service_provider: 'systemd', 15 | } 16 | end 17 | 18 | describe 'when passing jdbc subparams' do 19 | let(:params) do 20 | { 21 | jdbc_ssl_properties: '?ssl=true', 22 | } 23 | end 24 | 25 | it { 26 | is_expected.to contain_ini_setting('puppetdb_subname') 27 | .with( 28 | section: 'database', 29 | setting: 'subname', 30 | value: '//localhost:5432/puppetdb?ssl=true', 31 | ) 32 | } 33 | end 34 | 35 | describe 'when using ssl communication' do 36 | let(:params) do 37 | { 38 | postgresql_ssl_on: true, 39 | ssl_key_pk8_path: '/tmp/private_key.pk8', 40 | } 41 | end 42 | 43 | it 'configures subname correctly' do 44 | is_expected.to contain_ini_setting('puppetdb_subname') 45 | .with( 46 | ensure: 'present', 47 | path: '/etc/puppetlabs/puppetdb/conf.d/database.ini', 48 | section: 'database', 49 | setting: 'subname', 50 | value: '//localhost:5432/puppetdb?' \ 51 | 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ 52 | 'sslmode=verify-full&' \ 53 | 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ 54 | 'sslkey=/tmp/private_key.pk8&' \ 55 | 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', 56 | ) 57 | end 58 | 59 | context 'when setting jdbc_ssl_properties as well' do 60 | let(:params) do 61 | { 62 | jdbc_ssl_properties: '?ssl=true', 63 | postgresql_ssl_on: true, 64 | } 65 | end 66 | 67 | it 'raises an error' do 68 | is_expected.to compile 69 | .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/unit/classes/server/db_read_uri_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::read_database', type: :class do 4 | context 'on a supported platform' do 5 | let(:facts) do 6 | { 7 | os: { 8 | family: 'RedHat', 9 | }, 10 | operatingsystemrelease: '7.0', 11 | networking: { 12 | fqdn: 'test.domain.local', 13 | }, 14 | service_provider: 'systemd', 15 | } 16 | end 17 | 18 | describe 'when passing jdbc subparams' do 19 | let(:params) do 20 | { 21 | read_database_host: 'localhost', 22 | jdbc_ssl_properties: '?ssl=true', 23 | } 24 | end 25 | 26 | it { 27 | is_expected.to contain_ini_setting('puppetdb_read_subname') 28 | .with( 29 | section: 'read-database', 30 | setting: 'subname', 31 | value: '//localhost:5432/puppetdb?ssl=true', 32 | ) 33 | } 34 | end 35 | 36 | describe 'when using ssl communication' do 37 | let(:params) do 38 | { 39 | read_database_host: 'cheery-rime.puppetlabs.net', 40 | postgresql_ssl_on: true, 41 | ssl_key_pk8_path: '/tmp/private_key.pk8', 42 | } 43 | end 44 | 45 | it 'configures subname correctly' do 46 | is_expected.to contain_ini_setting('puppetdb_read_subname') 47 | .with( 48 | ensure: 'present', 49 | path: '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 50 | section: 'read-database', 51 | setting: 'subname', 52 | value: '//cheery-rime.puppetlabs.net:5432/puppetdb?' \ 53 | 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ 54 | 'sslmode=verify-full&' \ 55 | 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ 56 | 'sslkey=/tmp/private_key.pk8&' \ 57 | 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', 58 | ) 59 | end 60 | 61 | context 'when setting jdbc_ssl_properties as well' do 62 | let(:params) do 63 | { 64 | read_database_host: 'puppetdb', 65 | jdbc_ssl_properties: '?ssl=true', 66 | postgresql_ssl_on: true, 67 | } 68 | end 69 | 70 | it 'raises an error' do 71 | is_expected.to compile 72 | .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) 73 | end 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /spec/unit/classes/server/firewall_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::firewall', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | context 'defaults' do 7 | include_examples 'puppetdb::server::firewall' 8 | end 9 | 10 | context 'custom ports and open firewall' do 11 | let(:params) do 12 | { 13 | http_port: '9000', 14 | open_http_port: true, 15 | ssl_port: '9001', 16 | open_ssl_port: true, 17 | } 18 | end 19 | 20 | include_examples 'puppetdb::server::firewall' 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/unit/classes/server/global_ini_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::global', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | describe 'when using default values' do 7 | include_examples 'puppetdb::params' 8 | 9 | it { 10 | is_expected.to contain_ini_setting('puppetdb_global_vardir') 11 | .with( 12 | 'ensure' => 'present', 13 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/config.ini', 14 | 'section' => 'global', 15 | 'setting' => 'vardir', 16 | 'value' => '/opt/puppetlabs/server/data/puppetdb', 17 | ) 18 | } 19 | it { 20 | is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/config.ini') 21 | .with( 22 | 'ensure' => 'file', 23 | 'owner' => 'root', 24 | 'group' => 'puppetdb', 25 | 'mode' => '0640', 26 | ) 27 | } 28 | end 29 | 30 | describe 'when using a legacy puppetdb version' do 31 | let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } 32 | 33 | it { 34 | is_expected.to contain_ini_setting('puppetdb_global_vardir') 35 | .with( 36 | 'ensure' => 'present', 37 | 'path' => '/etc/puppetdb/conf.d/config.ini', 38 | 'section' => 'global', 39 | 'setting' => 'vardir', 40 | 'value' => '/var/lib/puppetdb', 41 | ) 42 | } 43 | 44 | it { 45 | is_expected.to contain_file('/etc/puppetdb/conf.d/config.ini') 46 | .with( 47 | 'ensure' => 'file', 48 | 'owner' => 'root', 49 | 'group' => 'puppetdb', 50 | 'mode' => '0640', 51 | ) 52 | } 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/unit/classes/server/jetty_ini_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::jetty', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | it { is_expected.to contain_class('puppetdb::server::jetty') } 7 | 8 | ['default', 'legacy'].each do |values| 9 | describe "when using #{values} values" do 10 | let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } if values == 'legacy' 11 | let(:pdbconfdir) do 12 | if values == 'legacy' 13 | '/etc/puppetdb/conf.d' 14 | else 15 | '/etc/puppetlabs/puppetdb/conf.d' 16 | end 17 | end 18 | 19 | it { 20 | is_expected.to contain_file("#{pdbconfdir}/jetty.ini") 21 | .with( 22 | 'ensure' => 'file', 23 | 'owner' => 'root', 24 | 'group' => 'puppetdb', 25 | 'mode' => '0640', 26 | ) 27 | } 28 | it { 29 | is_expected.to contain_ini_setting('puppetdb_host') 30 | .with( 31 | 'ensure' => 'present', 32 | 'path' => "#{pdbconfdir}/jetty.ini", 33 | 'section' => 'jetty', 34 | 'setting' => 'host', 35 | 'value' => 'localhost', 36 | ) 37 | } 38 | it { 39 | is_expected.to contain_ini_setting('puppetdb_port') 40 | .with( 41 | 'ensure' => 'present', 42 | 'path' => "#{pdbconfdir}/jetty.ini", 43 | 'section' => 'jetty', 44 | 'setting' => 'port', 45 | 'value' => 8080, 46 | ) 47 | } 48 | it { 49 | is_expected.to contain_ini_setting('puppetdb_sslhost') 50 | .with( 51 | 'ensure' => 'present', 52 | 'path' => "#{pdbconfdir}/jetty.ini", 53 | 'section' => 'jetty', 54 | 'setting' => 'ssl-host', 55 | 'value' => '0.0.0.0', 56 | ) 57 | } 58 | it { 59 | is_expected.to contain_ini_setting('puppetdb_sslport') 60 | .with( 61 | 'ensure' => 'present', 62 | 'path' => "#{pdbconfdir}/jetty.ini", 63 | 'section' => 'jetty', 64 | 'setting' => 'ssl-port', 65 | 'value' => 8081, 66 | ) 67 | } 68 | it { is_expected.not_to contain_ini_setting('puppetdb_sslprotocols') } 69 | end 70 | end 71 | 72 | describe 'when disabling ssl' do 73 | let(:params) do 74 | { 75 | 'disable_ssl' => true, 76 | } 77 | end 78 | 79 | it { 80 | is_expected.to contain_ini_setting('puppetdb_host') 81 | .with( 82 | 'ensure' => 'present', 83 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 84 | 'section' => 'jetty', 85 | 'setting' => 'host', 86 | 'value' => 'localhost', 87 | ) 88 | } 89 | it { 90 | is_expected.to contain_ini_setting('puppetdb_port') 91 | .with( 92 | 'ensure' => 'present', 93 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 94 | 'section' => 'jetty', 95 | 'setting' => 'port', 96 | 'value' => 8080, 97 | ) 98 | } 99 | it { 100 | is_expected.to contain_ini_setting('puppetdb_sslhost') 101 | .with( 102 | 'ensure' => 'absent', 103 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 104 | 'section' => 'jetty', 105 | 'setting' => 'ssl-host', 106 | ) 107 | } 108 | it { 109 | is_expected.to contain_ini_setting('puppetdb_sslport') 110 | .with( 111 | 'ensure' => 'absent', 112 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 113 | 'section' => 'jetty', 114 | 'setting' => 'ssl-port', 115 | ) 116 | } 117 | end 118 | 119 | describe 'when setting max_threads' do 120 | let(:params) do 121 | { 122 | 'max_threads' => 150, 123 | } 124 | end 125 | 126 | it { 127 | is_expected.to contain_ini_setting('puppetdb_max_threads') 128 | .with( 129 | 'ensure' => 'present', 130 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 131 | 'section' => 'jetty', 132 | 'setting' => 'max-threads', 133 | 'value' => '150', 134 | ) 135 | } 136 | end 137 | 138 | describe 'when setting ssl_protocols' do 139 | context 'to a valid string' do 140 | let(:params) { { 'ssl_protocols' => 'TLSv1, TLSv1.1, TLSv1.2' } } 141 | 142 | it { 143 | is_expected.to contain_ini_setting('puppetdb_sslprotocols').with( 144 | 'ensure' => 'present', 145 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 146 | 'section' => 'jetty', 147 | 'setting' => 'ssl-protocols', 148 | 'value' => 'TLSv1, TLSv1.1, TLSv1.2', 149 | ) 150 | } 151 | end 152 | 153 | context 'to an invalid type (non-string)' do 154 | let(:params) { { 'ssl_protocols' => ['invalid', 'type'] } } 155 | 156 | it 'fails' do 157 | expect { 158 | is_expected.to contain_class('puppetdb::server::jetty') 159 | }.to raise_error(Puppet::Error) 160 | end 161 | end 162 | end 163 | 164 | describe 'when setting cipher_suites' do 165 | context 'to a valid string' do 166 | let(:params) do 167 | { 168 | 'cipher_suites' => 'SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA384, SSL_RSA_WITH_AES_256_CBC_SHA256', 169 | } 170 | end 171 | 172 | it { 173 | is_expected.to contain_ini_setting('puppetdb_cipher-suites') 174 | .with( 175 | 'ensure' => 'present', 176 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 177 | 'section' => 'jetty', 178 | 'setting' => 'cipher-suites', 179 | 'value' => 'SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA384, SSL_RSA_WITH_AES_256_CBC_SHA256', 180 | ) 181 | } 182 | end 183 | end 184 | 185 | describe 'when disabling the cleartext HTTP port' do 186 | let(:params) do 187 | { 188 | 'disable_cleartext' => true, 189 | } 190 | end 191 | 192 | it { 193 | is_expected.to contain_ini_setting('puppetdb_host') 194 | .with( 195 | 'ensure' => 'absent', 196 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 197 | 'section' => 'jetty', 198 | 'setting' => 'host', 199 | 'value' => 'localhost', 200 | ) 201 | } 202 | it { 203 | is_expected.to contain_ini_setting('puppetdb_port') 204 | .with( 205 | 'ensure' => 'absent', 206 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/jetty.ini', 207 | 'section' => 'jetty', 208 | 'setting' => 'port', 209 | 'value' => 8080, 210 | ) 211 | } 212 | end 213 | end 214 | -------------------------------------------------------------------------------- /spec/unit/classes/server/puppetdb_ini_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::puppetdb', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | it { is_expected.to contain_class('puppetdb::server::puppetdb') } 7 | 8 | describe 'when using default values' do 9 | it { 10 | is_expected.to contain_ini_setting('puppetdb-connections-from-master-only') 11 | .with( 12 | 'ensure' => 'absent', 13 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/puppetdb.ini', 14 | 'section' => 'puppetdb', 15 | 'setting' => 'certificate-whitelist', 16 | 'value' => '/etc/puppetlabs/puppetdb/certificate-whitelist', 17 | ) 18 | } 19 | it { 20 | is_expected.to contain_file('/etc/puppetlabs/puppetdb/certificate-whitelist') 21 | .with( 22 | 'ensure' => 'absent', 23 | 'owner' => 0, 24 | 'group' => 0, 25 | 'mode' => '0644', 26 | 'content' => '', 27 | ) 28 | } 29 | it { 30 | is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/puppetdb.ini') 31 | .with( 32 | 'ensure' => 'file', 33 | 'owner' => 'root', 34 | 'group' => 'puppetdb', 35 | 'mode' => '0640', 36 | ) 37 | } 38 | it { 39 | is_expected.to contain_ini_setting('puppetdb_disable_update_checking') 40 | .with( 41 | 'ensure' => 'absent', 42 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/puppetdb.ini', 43 | 'section' => 'puppetdb', 44 | 'setting' => 'disable-update-checking', 45 | ) 46 | } 47 | end 48 | 49 | describe 'when restricting access to puppetdb' do 50 | let(:params) do 51 | { 52 | 'certificate_whitelist' => ['puppetmaster'], 53 | } 54 | end 55 | 56 | it { 57 | is_expected.to contain_ini_setting('puppetdb-connections-from-master-only') 58 | .with( 59 | 'ensure' => 'present', 60 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/puppetdb.ini', 61 | 'section' => 'puppetdb', 62 | 'setting' => 'certificate-whitelist', 63 | 'value' => '/etc/puppetlabs/puppetdb/certificate-whitelist', 64 | ) 65 | } 66 | it { 67 | is_expected.to contain_file('/etc/puppetlabs/puppetdb/certificate-whitelist') 68 | .with( 69 | 'ensure' => 'present', 70 | 'owner' => 0, 71 | 'group' => 0, 72 | 'mode' => '0644', 73 | 'content' => "puppetmaster\n", 74 | ) 75 | } 76 | end 77 | 78 | describe 'when enable disable-update-checking' do 79 | let(:params) do 80 | { 81 | 'disable_update_checking' => true, 82 | } 83 | end 84 | 85 | it { 86 | is_expected.to contain_ini_setting('puppetdb_disable_update_checking') 87 | .with( 88 | 'ensure' => 'present', 89 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/puppetdb.ini', 90 | 'section' => 'puppetdb', 91 | 'setting' => 'disable-update-checking', 92 | 'value' => 'true', 93 | ) 94 | } 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/unit/classes/server/read_database_ini_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server::read_database', type: :class do 4 | let(:facts) { on_supported_os.take(1).first[1] } 5 | 6 | it { is_expected.to contain_class('puppetdb::server::read_database') } 7 | 8 | describe 'when using default values' do 9 | it { is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/read_database.ini').with('ensure' => 'absent') } 10 | end 11 | 12 | describe 'when using minimum working values' do 13 | let(:params) do 14 | { 15 | 'read_database_host' => 'puppetdb', 16 | } 17 | end 18 | 19 | it { 20 | is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/read_database.ini') 21 | .with( 22 | 'ensure' => 'file', 23 | 'owner' => 'root', 24 | 'group' => 'puppetdb', 25 | 'mode' => '0640', 26 | ) 27 | } 28 | it { 29 | is_expected.to contain_ini_setting('puppetdb_read_database_username') 30 | .with( 31 | 'ensure' => 'present', 32 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 33 | 'section' => 'read-database', 34 | 'setting' => 'username', 35 | 'value' => 'puppetdb-read', 36 | ) 37 | } 38 | it { 39 | is_expected.to contain_ini_setting('puppetdb_read_database_password') 40 | .with( 41 | 'ensure' => 'present', 42 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 43 | 'section' => 'read-database', 44 | 'setting' => 'password', 45 | 'value' => 'puppetdb-read', 46 | 'show_diff' => false, 47 | ) 48 | } 49 | it { 50 | is_expected.to contain_ini_setting('puppetdb_read_pgs') 51 | .with( 52 | 'ensure' => 'present', 53 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 54 | 'section' => 'read-database', 55 | 'setting' => 'syntax_pgs', 56 | 'value' => true, 57 | ) 58 | } 59 | it { 60 | is_expected.to contain_ini_setting('puppetdb_read_subname') 61 | .with( 62 | 'ensure' => 'present', 63 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 64 | 'section' => 'read-database', 65 | 'setting' => 'subname', 66 | 'value' => '//puppetdb:5432/puppetdb', 67 | ) 68 | } 69 | it { 70 | is_expected.to contain_ini_setting('puppetdb_read_conn_max_age') 71 | .with( 72 | 'ensure' => 'present', 73 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 74 | 'section' => 'read-database', 75 | 'setting' => 'conn-max-age', 76 | 'value' => '60', 77 | ) 78 | } 79 | it { 80 | is_expected.to contain_ini_setting('puppetdb_read_conn_lifetime') 81 | .with( 82 | 'ensure' => 'present', 83 | 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 84 | 'section' => 'read-database', 85 | 'setting' => 'conn-lifetime', 86 | 'value' => '0', 87 | ) 88 | } 89 | 90 | context 'when using ssl communication' do 91 | let(:params) do 92 | { 93 | read_database_host: 'puppetdb', 94 | postgresql_ssl_on: true, 95 | ssl_key_pk8_path: '/tmp/private_key.pk8', 96 | } 97 | end 98 | 99 | it 'configures subname correctly' do 100 | is_expected.to contain_ini_setting('puppetdb_read_subname') 101 | .with( 102 | ensure: 'present', 103 | path: '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 104 | section: 'read-database', 105 | setting: 'subname', 106 | value: '//puppetdb:5432/puppetdb?' \ 107 | 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ 108 | 'sslmode=verify-full&' \ 109 | 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ 110 | 'sslkey=/tmp/private_key.pk8&' \ 111 | 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', 112 | ) 113 | end 114 | 115 | context 'when setting jdbc_ssl_properties as well' do 116 | let(:params) do 117 | { 118 | read_database_host: 'puppetdb', 119 | jdbc_ssl_properties: '?ssl=true', 120 | postgresql_ssl_on: true, 121 | } 122 | end 123 | 124 | it 'raises an error' do 125 | is_expected.to compile 126 | .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) 127 | end 128 | end 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /spec/unit/classes/server/validate_db_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | # FIXME: the connection validator resource in this code was deprecated and 6 | # removed from the postgres module long ago. 7 | # although the class is included, the resource is never added to 8 | # the catalog, masking the unknown resource error, because 9 | # jdbc_ssl_properties returns '' instead of false. 10 | describe 'puppetdb::server::validate_db', type: :class do 11 | let(:facts) { on_supported_os.take(1).first[1] } 12 | 13 | context 'with default params' do 14 | it { 15 | is_expected.to contain_class('puppetdb::server::validate_db') 16 | .with( 17 | database_host: 'localhost', 18 | database_port: '5432', 19 | database_username: 'puppetdb', 20 | database_password: 'puppetdb', 21 | database_name: 'puppetdb', 22 | jdbc_ssl_properties: '', 23 | ) 24 | } 25 | 26 | it { is_expected.not_to contain_postgresql_conn_validateor('validate puppetdb postgres connection') } 27 | end 28 | 29 | context 'with parameter tests' do 30 | let(:params) { { jdbc_ssl_properties: false } } 31 | 32 | context 'with jdbc_ssl_properties set false' do 33 | it { 34 | is_expected.to contain_postgresql_conn_validator('validate puppetdb postgres connection') 35 | .with( 36 | host: 'localhost', 37 | port: '5432', 38 | db_username: 'puppetdb', 39 | db_password: 'puppetdb', 40 | db_name: 'puppetdb', 41 | ) 42 | } 43 | end 44 | 45 | context 'without database password' do 46 | let(:params) { { database_password: nil } } 47 | 48 | it { is_expected.not_to contain_postgresql_conn_validator('validate puppetdb postgres connection') } 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/unit/classes/server/validate_read_db_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | # FIXME: the connection validator resource in this code was deprecated and 6 | # removed from the postgres module long ago. 7 | # although the class is included, the resource is never added to 8 | # the catalog, masking the unknown resource error, because 9 | # jdbc_ssl_properties returns '' instead of false. 10 | describe 'puppetdb::server::validate_read_db', type: :class do 11 | let(:facts) { on_supported_os.take(1).first[1] } 12 | 13 | context 'with default params' do 14 | it { 15 | is_expected.to contain_class('puppetdb::server::validate_read_db') 16 | .with( 17 | database_host: 'localhost', 18 | database_port: '5432', 19 | database_username: 'puppetdb', 20 | database_password: 'puppetdb', 21 | database_name: 'puppetdb', 22 | jdbc_ssl_properties: '', 23 | ) 24 | } 25 | 26 | it { is_expected.not_to contain_postgresql_conn_validator('validate puppetdb postgres (read) connection') } 27 | end 28 | 29 | context 'with parameter tests' do 30 | let(:params) { { jdbc_ssl_properties: false } } 31 | 32 | context 'with jdbc_ssl_properties set false' do 33 | it { 34 | is_expected.to contain_postgresql_conn_validator('validate puppetdb postgres (read) connection') 35 | .with( 36 | host: 'localhost', 37 | port: '5432', 38 | db_username: 'puppetdb', 39 | db_password: 'puppetdb', 40 | db_name: 'puppetdb', 41 | ) 42 | } 43 | end 44 | 45 | context 'without database password' do 46 | let(:params) { { database_password: nil } } 47 | 48 | it { is_expected.not_to contain_postgresql_conn_validator('validate puppetdb postgres (read) connection') } 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/unit/classes/server_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'puppetdb::server', type: :class do 4 | let :node do 5 | 'test.domain.local' 6 | end 7 | 8 | let(:pathdir) do 9 | case facts[:os]['family'] 10 | when 'Debian' 11 | '/etc/default/puppetdb' 12 | else 13 | '/etc/sysconfig/puppetdb' 14 | end 15 | end 16 | 17 | on_supported_os.each do |os, facts| 18 | context "on #{os}" do 19 | let(:facts) { facts } 20 | 21 | describe 'when using default values' do 22 | it { is_expected.to contain_class('puppetdb::server') } 23 | it { is_expected.to contain_class('puppetdb::server::global') } 24 | it { is_expected.to contain_class('puppetdb::server::command_processing') } 25 | it { is_expected.to contain_class('puppetdb::server::database') } 26 | it { is_expected.to contain_class('puppetdb::server::read_database') } 27 | it { is_expected.to contain_class('puppetdb::server::jetty') } 28 | it { is_expected.to contain_class('puppetdb::server::puppetdb') } 29 | 30 | it { 31 | is_expected.to contain_package('puppetdb') 32 | .that_notifies('Service[puppetdb]') 33 | } 34 | 35 | it { 36 | is_expected.to contain_service('puppetdb') 37 | .with_ensure('running') 38 | .with_enable(true) 39 | } 40 | end 41 | 42 | describe 'when not specifying JAVA_ARGS' do 43 | it { is_expected.not_to contain_ini_subsetting('Xms') } 44 | end 45 | 46 | describe 'when specifying JAVA_ARGS' do 47 | let(:params) do 48 | { 49 | 'java_args' => { 50 | '-Xms' => '2g', 51 | }, 52 | } 53 | end 54 | 55 | it { 56 | is_expected.to contain_ini_subsetting("'-Xms'") 57 | .with( 58 | 'ensure' => 'present', 59 | 'path' => pathdir.to_s, 60 | 'section' => '', 61 | 'key_val_separator' => '=', 62 | 'setting' => 'JAVA_ARGS', 63 | 'subsetting' => '-Xms', 64 | 'value' => '2g', 65 | ) 66 | } 67 | end 68 | 69 | describe 'when specifying JAVA_ARGS with merge_default_java_args false' do 70 | let(:params) do 71 | { 72 | 'java_args' => { '-Xms' => '2g' }, 73 | 'merge_default_java_args' => false, 74 | } 75 | end 76 | 77 | context 'on standard PuppetDB' do 78 | it { 79 | is_expected.to contain_ini_setting('java_args') 80 | .with( 81 | 'ensure' => 'present', 82 | 'path' => pathdir.to_s, 83 | 'section' => '', 84 | 'setting' => 'JAVA_ARGS', 85 | 'value' => '"-Xms2g"', 86 | ) 87 | } 88 | end 89 | end 90 | 91 | context 'when systemd is available' do 92 | let(:facts) do 93 | super().merge(systemd: true) 94 | end 95 | 96 | describe 'by default dlo cleanup service is enabled' do 97 | it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.service').with_content(%r{/opt/puppetlabs/server/data/puppetdb/stockpile/discard/}) } 98 | it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer').with_enable(true).with_active(true) } 99 | 100 | it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } 101 | end 102 | 103 | describe 'dlo cleanup service can be disabled by params' do 104 | let(:params) do 105 | { 106 | 'automatic_dlo_cleanup' => false, 107 | } 108 | end 109 | 110 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } 111 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } 112 | it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } 113 | end 114 | 115 | describe 'dlo directory is customized by $vardir to $vardir/stockpile/discard' do 116 | let(:params) do 117 | { 118 | 'vardir' => '/var/custom/path', 119 | } 120 | end 121 | 122 | it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.service').with_content(%r{/var/custom/path/stockpile/discard/}) } 123 | it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer').with_enable(true).with_active(true) } 124 | 125 | it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } 126 | end 127 | end 128 | 129 | context 'when systemd is not available' do 130 | describe 'by default dlo cleanup is set up with cron' do 131 | it { is_expected.to contain_cron('puppetdb-dlo-cleanup').with_ensure('present').with(command: %r{/opt/puppetlabs/server/data/puppetdb/stockpile/discard/}) } 132 | 133 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } 134 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } 135 | end 136 | 137 | describe 'dlo cleanup can be disabled by params' do 138 | let(:params) do 139 | { 140 | 'automatic_dlo_cleanup' => false, 141 | } 142 | end 143 | 144 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } 145 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } 146 | it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } 147 | end 148 | 149 | describe 'dlo directory is customized by $vardir to $vardir/stockpile/discard' do 150 | let(:params) do 151 | { 152 | 'vardir' => '/var/custom/path', 153 | } 154 | end 155 | 156 | it { is_expected.to contain_cron('puppetdb-dlo-cleanup').with_ensure('present').with(command: %r{/var/custom/path/stockpile/discard/}) } 157 | 158 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } 159 | it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } 160 | end 161 | end 162 | 163 | context 'when not managing the database password' do 164 | let(:params) do 165 | { 166 | 'manage_db_password' => false, 167 | 'manage_read_db_password' => false, 168 | 'read_database_host' => '10.0.0.1', # Make sure the read_database class is enforced. 169 | } 170 | end 171 | 172 | describe 'ini_setting entries for the password will not exist' do 173 | it { is_expected.to contain_class('puppetdb::server::database').with('manage_db_password' => false) } 174 | it { is_expected.to contain_class('puppetdb::server::read_database').with('manage_db_password' => false) } 175 | 176 | it { is_expected.not_to contain_ini__setting('puppetdb_psdatabase_password') } 177 | it { is_expected.not_to contain_ini__setting('puppetdb_read_database_password') } 178 | end 179 | end 180 | 181 | context 'when managing ssl communication' do 182 | let(:params) do 183 | { 184 | postgresql_ssl_on: true, 185 | } 186 | end 187 | let(:key_path) { '/etc/puppetlabs/puppetdb/ssl/private.pem' } 188 | let(:key_pk8_path) { '/etc/puppetlabs/puppetdb/ssl/private.pk8' } 189 | 190 | context 'ini_setting entries for the ssl configuration will exist' do 191 | it { is_expected.to contain_class('puppetdb::server::database').with('postgresql_ssl_on' => true) } 192 | it { is_expected.to contain_class('puppetdb::server::database').with(ssl_key_pk8_path: key_pk8_path) } 193 | 194 | it { is_expected.to contain_class('puppetdb::server::read_database').with('postgresql_ssl_on' => true) } 195 | it { is_expected.to contain_class('puppetdb::server::read_database').with(ssl_key_pk8_path: key_pk8_path) } 196 | end 197 | 198 | context 'private key file is converted from .pem to .pk8 format' do 199 | it 'runs exec command' do 200 | is_expected.to contain_exec(key_pk8_path) 201 | .with( 202 | path: ['/opt/puppetlabs/puppet/bin', facts[:path]], 203 | command: "openssl pkcs8 -topk8 -inform PEM -outform DER -in #{key_path} -out #{key_pk8_path} -nocrypt", 204 | onlyif: "test ! -e '#{key_pk8_path}' -o '#{key_pk8_path}' -ot '#{key_path}'", 205 | before: "File[#{key_pk8_path}]", 206 | ) 207 | end 208 | 209 | it 'contains file private.pk8' do 210 | is_expected.to contain_file('/etc/puppetlabs/puppetdb/ssl/private.pk8') 211 | .with( 212 | ensure: 'file', 213 | owner: 'root', 214 | group: 'puppetdb', 215 | mode: '0640', 216 | ) 217 | end 218 | end 219 | end 220 | end 221 | end 222 | end 223 | -------------------------------------------------------------------------------- /spec/unit/facter/puppetdb_version_spec.rb: -------------------------------------------------------------------------------- 1 | require 'facter' 2 | 3 | describe 'puppetdb_version' do 4 | before(:each) do 5 | Facter.clear 6 | end 7 | 8 | context 'when puppetdb is available' do 9 | before(:each) do 10 | allow(Facter::Util::Resolution).to receive(:which).with('puppetdb').and_return('/usr/bin/puppetdb') 11 | end 12 | 13 | context 'on a default system' do 14 | it 'returns the correct version from puppetdb --version' do 15 | expect(Facter::Core::Execution).to receive(:execute) 16 | .with('puppetdb --version') 17 | .and_return('puppetdb version: 7.19.0') 18 | 19 | expect(Facter.fact(:puppetdb_version).value).to eq('7.19.0') 20 | end 21 | 22 | it 'returns nil if the command execution fails' do 23 | allow(Facter::Core::Execution).to receive(:execute).with('puppetdb --version').and_raise(Facter::Core::Execution::ExecutionFailure) 24 | 25 | expect(Facter.fact(:puppetdb_version).value).to be_nil 26 | end 27 | end 28 | end 29 | 30 | context 'when puppetdb is not available' do 31 | before(:each) do 32 | allow(Facter::Util::Resolution).to receive(:which).with('puppetdb').and_return(nil) 33 | end 34 | 35 | it 'returns nil' do 36 | expect(Facter.fact(:puppetdb_version).value).to be_nil 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/unit/util/puppetdb_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'puppet/util/puppetdb_validator' 3 | 4 | describe 'Puppet::Util::PuppetdbValidator' do 5 | before(:each) do 6 | nethttpok = Net::HTTPOK.new('1.1', 200, 'OK') 7 | notfound = Net::HTTPNotFound.new('1.1', 404, 'Not found') 8 | 9 | url = '/pdb/meta/v1/version' 10 | if Puppet::PUPPETVERSION.to_f < 7 11 | conn_ok = double 12 | allow(conn_ok).to receive(:get).with(url, 'Accept' => 'application/json').and_return(nethttpok) 13 | allow(conn_ok).to receive(:read_timeout=).with(2) 14 | allow(conn_ok).to receive(:open_timeout=).with(2) 15 | 16 | conn_not_found = double 17 | allow(conn_not_found).to receive(:get).with('/pdb/meta/v1/version', 'Accept' => 'application/json').and_return(notfound) 18 | 19 | allow(Puppet::Network::HttpPool).to receive(:http_instance).and_raise('Unknown host') 20 | allow(Puppet::Network::HttpPool).to receive(:http_instance).with('mypuppetdb.com', 8080, true).and_raise('Connection refused') 21 | allow(Puppet::Network::HttpPool).to receive(:http_instance).with('mypuppetdb.com', 8080, false).and_return(conn_ok) 22 | allow(Puppet::Network::HttpPool).to receive(:http_instance).with('mypuppetdb.com', 8081, true).and_return(conn_ok) 23 | allow(Puppet::Network::HttpPool).to receive(:http_instance).with('wrongserver.com', 8081, true).and_return(conn_not_found) 24 | else 25 | http = double 26 | allow(Puppet::HTTP::Client).to receive(:new).and_return(http) 27 | 28 | allow(http).to receive(:get) do |uri, _opts| 29 | raise(Puppet::HTTP::HTTPError, 'Connection refused') if uri.hostname == 'mypuppetdb.com' && uri.port == 8080 && uri.scheme == 'https' 30 | raise Puppet::HTTP::ResponseError, Puppet::HTTP::ResponseNetHTTP.new(url, notfound) if uri.hostname == 'wrongserver.com' && uri.port == 8081 && uri.scheme == 'https' 31 | raise Puppet::HTTP::HTTPError, 'Unknown host' if uri.hostname == 'non-existing.com' && uri.scheme == 'https' 32 | 33 | if uri.hostname == 'mypuppetdb.com' && uri.port == 8080 && uri.scheme == 'http' 34 | Puppet::HTTP::ResponseNetHTTP.new(url, nethttpok) 35 | elsif uri.hostname == 'mypuppetdb.com' && uri.port == 8081 && uri.scheme == 'https' 36 | Puppet::HTTP::ResponseNetHTTP.new(url, nethttpok) 37 | end 38 | end 39 | end 40 | end 41 | 42 | it 'returns true if connection succeeds' do 43 | validator = Puppet::Util::PuppetdbValidator.new('mypuppetdb.com', 8081) 44 | expect(validator.attempt_connection).to be true 45 | end 46 | 47 | it 'stills validate without ssl' do 48 | validator = Puppet::Util::PuppetdbValidator.new('mypuppetdb.com', 8080, false) 49 | expect(validator.attempt_connection).to be true 50 | end 51 | 52 | it 'returns false and issues an appropriate notice if connection is refused' do 53 | puppetdb_server = 'mypuppetdb.com' 54 | puppetdb_port = 8080 55 | validator = Puppet::Util::PuppetdbValidator.new(puppetdb_server, puppetdb_port) 56 | expect(Puppet).to receive(:notice).with("Unable to connect to puppetdb server (https://#{puppetdb_server}:#{puppetdb_port}): Connection refused") 57 | expect(validator.attempt_connection).to be false 58 | end 59 | 60 | it 'returns false and issues an appropriate notice if connection succeeds but puppetdb is not available' do 61 | puppetdb_server = 'wrongserver.com' 62 | puppetdb_port = 8081 63 | validator = Puppet::Util::PuppetdbValidator.new(puppetdb_server, puppetdb_port) 64 | expect(Puppet).to receive(:notice).with("Unable to connect to puppetdb server (https://#{puppetdb_server}:#{puppetdb_port}): [404] Not found") 65 | expect(validator.attempt_connection).to be false 66 | end 67 | 68 | it 'returns false and issues an appropriate notice if host:port is unreachable or does not exist' do 69 | puppetdb_server = 'non-existing.com' 70 | puppetdb_port = nil 71 | validator = Puppet::Util::PuppetdbValidator.new(puppetdb_server, puppetdb_port) 72 | expect(Puppet).to receive(:notice).with("Unable to connect to puppetdb server (https://#{puppetdb_server}:#{puppetdb_port}): Unknown host") 73 | expect(validator.attempt_connection).to be false 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /templates/certificate-whitelist.erb: -------------------------------------------------------------------------------- 1 | <% @certificate_whitelist.each do |cn| -%> 2 | <%= cn %> 3 | <% end -%> 4 | -------------------------------------------------------------------------------- /templates/puppetdb-DLO-cleanup.service.epp: -------------------------------------------------------------------------------- 1 | <%- | String[1] $puppetdb_user, 2 | String[1] $puppetdb_group, 3 | String[1] $vardir, 4 | Integer[1] $dlo_max_age 5 | | -%> 6 | [Unit] 7 | Description=Cleanup old discarded puppetdb reports 8 | 9 | [Service] 10 | Type=oneshot 11 | User=<%= $puppetdb_user %> 12 | Group=<%= $puppetdb_group %> 13 | ExecStart=/usr/bin/find <%= $vardir %>/stockpile/discard/ -type f -mtime +<%= $dlo_max_age %> -delete 14 | -------------------------------------------------------------------------------- /templates/puppetdb-DLO-cleanup.timer.epp: -------------------------------------------------------------------------------- 1 | <%- | String[1] $cleanup_timer_interval 2 | | -%> 3 | [Unit] 4 | Description=Timer for puppetdb-DLO-cleanup 5 | 6 | [Timer] 7 | # Daily at 8am 8 | OnCalendar=<%= $cleanup_timer_interval %> 9 | Persistent=True 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /templates/routes.yaml.erb: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by the puppetdb module. 2 | 3 | <%= @routes_real.to_yaml %> 4 | -------------------------------------------------------------------------------- /types/ttl.pp: -------------------------------------------------------------------------------- 1 | type Puppetdb::Ttl = Pattern[/^\d+(d|h|m|s|ms)$/] 2 | --------------------------------------------------------------------------------