diff --git a/Gemfile b/Gemfile index 2defaae..0d3a975 100644 --- a/Gemfile +++ b/Gemfile @@ -1,78 +1,78 @@ source ENV['GEM_SOURCE'] || 'https://rubygems.org' def location_for(place_or_version, fake_version = nil) git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} file_url_regex = %r{\Afile:\/\/(?.*)} if place_or_version && (git_url = place_or_version.match(git_url_regex)) [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] else [place_or_version, { require: false }] end end ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments minor_version = ruby_version_segments[0..1].join('.') group :development do gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 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)) gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "puppet-module-posix-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] gem "puppet-module-posix-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] gem "puppet-module-win-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "puppet-module-win-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] end group :system_tests do - gem "puppet-module-posix-system-r#{minor_version}", require: false, platforms: [:ruby] - gem "puppet-module-win-system-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-posix-system-r#{minor_version}", '~> 0.5', require: false, platforms: [:ruby] + gem "puppet-module-win-system-r#{minor_version}", '~> 0.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "nokogiri", require: false, platforms: [:ruby] gem "serverspec", require: false, platforms: [:ruby] end puppet_version = ENV['PUPPET_GEM_VERSION'] facter_version = ENV['FACTER_GEM_VERSION'] hiera_version = ENV['HIERA_GEM_VERSION'] gems = {} gems['puppet'] = location_for(puppet_version) # If facter or hiera versions have been specified via the environment # variables gems['facter'] = location_for(facter_version) if facter_version gems['hiera'] = location_for(hiera_version) if hiera_version if Gem.win_platform? && puppet_version =~ %r{^(file:///|git://)} # If we're using a Puppet gem on Windows which handles its own win32-xxx gem # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). gems['win32-dir'] = ['<= 0.4.9', require: false] gems['win32-eventlog'] = ['<= 0.6.5', require: false] gems['win32-process'] = ['<= 0.7.5', require: false] gems['win32-security'] = ['<= 0.2.5', require: false] gems['win32-service'] = ['0.8.8', require: false] end gems.each do |gem_name, gem_params| gem gem_name, *gem_params end # Evaluate Gemfile.local and ~/.gemfile if they exist extra_gemfiles = [ "#{__FILE__}.local", File.join(Dir.home, '.gemfile'), ] extra_gemfiles.each do |gemfile| if File.file?(gemfile) && File.readable?(gemfile) eval(File.read(gemfile), binding) end end # vim: syntax=ruby diff --git a/lib/puppet/type/puppetdb_conn_validator.rb b/lib/puppet/type/puppetdb_conn_validator.rb index 7d40020..e6eef59 100644 --- a/lib/puppet/type/puppetdb_conn_validator.rb +++ b/lib/puppet/type/puppetdb_conn_validator.rb @@ -1,47 +1,47 @@ Puppet::Type.newtype(:puppetdb_conn_validator) do @doc = "Verify that a connection can be successfully established between a node and the puppetdb server. Its primary use is as a precondition to prevent configuration changes from being applied if the puppetdb server cannot be reached, but it could potentially be used for other purposes such as monitoring." ensurable do defaultvalues defaultto :present end newparam(:name, namevar: true) do desc 'An arbitrary name used as the identity of the resource.' end newparam(:puppetdb_server) do desc 'The DNS name or IP address of the server where puppetdb should be running.' end newparam(:puppetdb_port) do desc 'The port that the puppetdb server should be listening on.' end newparam(:use_ssl) do - desc 'Whether the connection will be attemped using https' + desc 'Whether the connection will be attempted using https' defaultto true end newparam(:test_url) do desc 'URL to use for testing if the PuppetDB database is up' end newparam(:timeout) do 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.' defaultto 15 validate do |value| # This will raise an error if the string is not convertible to an integer Integer(value) end munge do |value| Integer(value) end end end diff --git a/manifests/database/postgresql.pp b/manifests/database/postgresql.pp index 3d60869..b432b38 100644 --- a/manifests/database/postgresql.pp +++ b/manifests/database/postgresql.pp @@ -1,48 +1,64 @@ # Class for creating the PuppetDB postgresql database. See README.md for more # information. class puppetdb::database::postgresql( - $listen_addresses = $puppetdb::params::database_host, - $database_name = $puppetdb::params::database_name, - $database_username = $puppetdb::params::database_username, - $database_password = $puppetdb::params::database_password, - $database_port = $puppetdb::params::database_port, - $manage_database = $puppetdb::params::manage_database, - $manage_server = $puppetdb::params::manage_dbserver, - $manage_package_repo = $puppetdb::params::manage_pg_repo, - $postgres_version = $puppetdb::params::postgres_version, + $listen_addresses = $puppetdb::params::database_host, + $database_name = $puppetdb::params::database_name, + $database_username = $puppetdb::params::database_username, + $database_password = $puppetdb::params::database_password, + $database_port = $puppetdb::params::database_port, + $manage_database = $puppetdb::params::manage_database, + $manage_server = $puppetdb::params::manage_dbserver, + $manage_package_repo = $puppetdb::params::manage_pg_repo, + $postgres_version = $puppetdb::params::postgres_version, + $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, + $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, + $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, + $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path ) inherits puppetdb::params { if $manage_server { class { '::postgresql::globals': manage_package_repo => $manage_package_repo, version => $postgres_version, } # get the pg server up and running class { '::postgresql::server': ip_mask_allow_all_users => '0.0.0.0/0', listen_addresses => $listen_addresses, port => scanf($database_port, '%i')[0], } + # configure PostgreSQL communication with Puppet Agent SSL certificates if + # postgresql_ssl_on is set to true + if $postgresql_ssl_on { + class { 'puppetdb::database::ssl_configuration': + database_name => $database_name, + database_username => $database_username, + postgresql_ssl_key_path => $postgresql_ssl_key_path, + postgresql_ssl_cert_path => $postgresql_ssl_cert_path, + postgresql_ssl_ca_cert_path => $postgresql_ssl_ca_cert_path + } + } + # Only install pg_trgm extension, if database it is actually managed by the module if $manage_database { # get the pg contrib to use pg_trgm extension class { '::postgresql::server::contrib': } postgresql::server::extension { 'pg_trgm': database => $database_name, require => Postgresql::Server::Db[$database_name], } } } if $manage_database { # create the puppetdb database postgresql::server::db { $database_name: user => $database_username, password => $database_password, grant => 'all', } } -} +} \ No newline at end of file diff --git a/manifests/database/ssl_configuration.pp b/manifests/database/ssl_configuration.pp new file mode 100644 index 0000000..6d0bcc9 --- /dev/null +++ b/manifests/database/ssl_configuration.pp @@ -0,0 +1,80 @@ +# Class for configuring SSL connection for the PuppetDB postgresql database. See README.md for more +# information. +class puppetdb::database::ssl_configuration( + $database_name = $puppetdb::params::database_name, + $database_username = $puppetdb::params::database_username, + $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, + $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, + $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path +) inherits puppetdb::params { + + file {'postgres private key': + ensure => present, + path => "${postgresql::server::datadir}/server.key", + source => $postgresql_ssl_key_path, + owner => 'postgres', + mode => '0600', + require => Package['postgresql-server'], + } + + file {'postgres public key': + ensure => present, + path => "${postgresql::server::datadir}/server.crt", + source => $postgresql_ssl_cert_path, + owner => 'postgres', + mode => '0600', + require => Package['postgresql-server'], + } + + postgresql::server::config_entry {'ssl': + ensure => present, + value => 'on', + require => [File['postgres private key'], File['postgres public key']] + } + + postgresql::server::config_entry {'ssl_cert_file': + ensure => present, + value => "${postgresql::server::datadir}/server.crt", + require => [File['postgres private key'], File['postgres public key']] + } + + postgresql::server::config_entry {'ssl_key_file': + ensure => present, + value => "${postgresql::server::datadir}/server.key", + require => [File['postgres private key'], File['postgres public key']] + } + + postgresql::server::config_entry {'ssl_ca_file': + ensure => present, + value => $postgresql_ssl_ca_cert_path, + require => [File['postgres private key'], File['postgres public key']] + } + + $identity_map_key = "${database_name}-${database_username}-map" + + postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv4)": + type => 'hostssl', + database => $database_name, + user => $database_username, + address => '0.0.0.0/0', + auth_method => 'cert', + order => 0, + auth_option => "map=${identity_map_key} clientcert=1" + } + + postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv6)": + type => 'hostssl', + database => $database_name, + user => $database_username, + address => '::0/0', + auth_method => 'cert', + order => 0, + auth_option => "map=${identity_map_key} clientcert=1" + } + + postgresql::server::pg_ident_rule {"Map the SSL certificate of the server as a ${database_username} user": + map_name => $identity_map_key, + system_username => $::fqdn, + database_username => $database_username, + } +} diff --git a/manifests/init.pp b/manifests/init.pp index 734374b..4803340 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,189 +1,198 @@ # All in one class for setting up a PuppetDB instance. See README.md for more # details. class puppetdb ( $listen_address = $puppetdb::params::listen_address, $listen_port = $puppetdb::params::listen_port, $disable_cleartext = $puppetdb::params::disable_cleartext, $open_listen_port = $puppetdb::params::open_listen_port, $ssl_listen_address = $puppetdb::params::ssl_listen_address, $ssl_listen_port = $puppetdb::params::ssl_listen_port, $disable_ssl = $puppetdb::params::disable_ssl, $open_ssl_listen_port = $puppetdb::params::open_ssl_listen_port, $ssl_dir = $puppetdb::params::ssl_dir, $ssl_set_cert_paths = $puppetdb::params::ssl_set_cert_paths, $ssl_cert_path = $puppetdb::params::ssl_cert_path, $ssl_key_path = $puppetdb::params::ssl_key_path, + $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path, $ssl_deploy_certs = $puppetdb::params::ssl_deploy_certs, $ssl_key = $puppetdb::params::ssl_key, $ssl_cert = $puppetdb::params::ssl_cert, $ssl_ca_cert = $puppetdb::params::ssl_ca_cert, $ssl_protocols = $puppetdb::params::ssl_protocols, + $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, + $postgresql_ssl_folder = $puppetdb::params::postgresql_ssl_folder, + $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, + $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, + $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path, $cipher_suites = $puppetdb::params::cipher_suites, $migrate = $puppetdb::params::migrate, $manage_dbserver = $puppetdb::params::manage_dbserver, $manage_database = $puppetdb::params::manage_database, $manage_package_repo = $puppetdb::params::manage_pg_repo, $postgres_version = $puppetdb::params::postgres_version, $database = $puppetdb::params::database, $database_host = $puppetdb::params::database_host, $database_port = $puppetdb::params::database_port, $database_username = $puppetdb::params::database_username, $database_password = $puppetdb::params::database_password, $database_name = $puppetdb::params::database_name, $manage_db_password = $puppetdb::params::manage_db_password, $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, $database_listen_address = $puppetdb::params::postgres_listen_addresses, $database_validate = $puppetdb::params::database_validate, $database_embedded_path = $puppetdb::params::database_embedded_path, $node_ttl = $puppetdb::params::node_ttl, $node_purge_ttl = $puppetdb::params::node_purge_ttl, $report_ttl = $puppetdb::params::report_ttl, Optional[Array] $facts_blacklist = $puppetdb::params::facts_blacklist, $gc_interval = $puppetdb::params::gc_interval, $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, $log_slow_statements = $puppetdb::params::log_slow_statements, $conn_max_age = $puppetdb::params::conn_max_age, $conn_keep_alive = $puppetdb::params::conn_keep_alive, $conn_lifetime = $puppetdb::params::conn_lifetime, $puppetdb_package = $puppetdb::params::puppetdb_package, $puppetdb_service = $puppetdb::params::puppetdb_service, $puppetdb_service_status = $puppetdb::params::puppetdb_service_status, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $read_database = $puppetdb::params::read_database, $read_database_host = $puppetdb::params::read_database_host, $read_database_port = $puppetdb::params::read_database_port, $read_database_username = $puppetdb::params::read_database_username, $read_database_password = $puppetdb::params::read_database_password, $read_database_name = $puppetdb::params::read_database_name, $manage_read_db_password = $puppetdb::params::manage_read_db_password, $read_database_jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, $read_database_validate = $puppetdb::params::read_database_validate, $read_log_slow_statements = $puppetdb::params::read_log_slow_statements, $read_conn_max_age = $puppetdb::params::read_conn_max_age, $read_conn_keep_alive = $puppetdb::params::read_conn_keep_alive, $read_conn_lifetime = $puppetdb::params::read_conn_lifetime, $confdir = $puppetdb::params::confdir, $vardir = $puppetdb::params::vardir, $manage_firewall = $puppetdb::params::manage_firewall, $java_args = $puppetdb::params::java_args, $merge_default_java_args = $puppetdb::params::merge_default_java_args, $max_threads = $puppetdb::params::max_threads, $command_threads = $puppetdb::params::command_threads, $concurrent_writes = $puppetdb::params::concurrent_writes, $store_usage = $puppetdb::params::store_usage, $temp_usage = $puppetdb::params::temp_usage, $disable_update_checking = $puppetdb::params::disable_update_checking, $certificate_whitelist_file = $puppetdb::params::certificate_whitelist_file, $certificate_whitelist = $puppetdb::params::certificate_whitelist, $database_max_pool_size = $puppetdb::params::database_max_pool_size, $read_database_max_pool_size = $puppetdb::params::read_database_max_pool_size, Boolean $automatic_dlo_cleanup = $puppetdb::params::automatic_dlo_cleanup, String[1] $cleanup_timer_interval = $puppetdb::params::cleanup_timer_interval, Integer[1] $dlo_max_age = $puppetdb::params::dlo_max_age, Optional[Stdlib::Absolutepath] $java_bin = $puppetdb::params::java_bin, ) inherits puppetdb::params { class { '::puppetdb::server': listen_address => $listen_address, listen_port => $listen_port, disable_cleartext => $disable_cleartext, open_listen_port => $open_listen_port, ssl_listen_address => $ssl_listen_address, ssl_listen_port => $ssl_listen_port, disable_ssl => $disable_ssl, open_ssl_listen_port => $open_ssl_listen_port, ssl_dir => $ssl_dir, ssl_set_cert_paths => $ssl_set_cert_paths, ssl_cert_path => $ssl_cert_path, ssl_key_path => $ssl_key_path, + ssl_key_pk8_path => $ssl_key_pk8_path, ssl_ca_cert_path => $ssl_ca_cert_path, ssl_deploy_certs => $ssl_deploy_certs, ssl_key => $ssl_key, ssl_cert => $ssl_cert, ssl_ca_cert => $ssl_ca_cert, ssl_protocols => $ssl_protocols, + postgresql_ssl_on => $postgresql_ssl_on, cipher_suites => $cipher_suites, migrate => $migrate, database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, manage_db_password => $manage_db_password, jdbc_ssl_properties => $jdbc_ssl_properties, database_validate => $database_validate, database_embedded_path => $database_embedded_path, node_ttl => $node_ttl, node_purge_ttl => $node_purge_ttl, report_ttl => $report_ttl, facts_blacklist => $facts_blacklist, gc_interval => $gc_interval, node_purge_gc_batch_limit => $node_purge_gc_batch_limit, log_slow_statements => $log_slow_statements, conn_max_age => $conn_max_age, conn_keep_alive => $conn_keep_alive, conn_lifetime => $conn_lifetime, puppetdb_package => $puppetdb_package, puppetdb_service => $puppetdb_service, puppetdb_service_status => $puppetdb_service_status, confdir => $confdir, vardir => $vardir, java_args => $java_args, merge_default_java_args => $merge_default_java_args, max_threads => $max_threads, read_database => $read_database, read_database_host => $read_database_host, read_database_port => $read_database_port, read_database_username => $read_database_username, read_database_password => $read_database_password, read_database_name => $read_database_name, manage_read_db_password => $manage_read_db_password, read_database_jdbc_ssl_properties => $read_database_jdbc_ssl_properties, read_database_validate => $read_database_validate, read_log_slow_statements => $read_log_slow_statements, read_conn_max_age => $read_conn_max_age, read_conn_keep_alive => $read_conn_keep_alive, read_conn_lifetime => $read_conn_lifetime, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, manage_firewall => $manage_firewall, command_threads => $command_threads, concurrent_writes => $concurrent_writes, store_usage => $store_usage, temp_usage => $temp_usage, disable_update_checking => $disable_update_checking, certificate_whitelist_file => $certificate_whitelist_file, certificate_whitelist => $certificate_whitelist, database_max_pool_size => $database_max_pool_size, read_database_max_pool_size => $read_database_max_pool_size, automatic_dlo_cleanup => $automatic_dlo_cleanup, cleanup_timer_interval => $cleanup_timer_interval, dlo_max_age => $dlo_max_age, java_bin => $java_bin, } if ($database == 'postgres') { $database_before = str2bool($database_validate) ? { false => Class['::puppetdb::server'], default => [Class['::puppetdb::server'], Class['::puppetdb::server::validate_db']], } class { '::puppetdb::database::postgresql': listen_addresses => $database_listen_address, database_name => $database_name, database_username => $database_username, database_password => $database_password, database_port => $database_port, manage_server => $manage_dbserver, manage_database => $manage_database, manage_package_repo => $manage_package_repo, postgres_version => $postgres_version, + postgresql_ssl_on => $postgresql_ssl_on, before => $database_before } } } diff --git a/manifests/params.pp b/manifests/params.pp index 8d278a9..235122b 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,209 +1,220 @@ # PRIVATE CLASS - do not use directly # # The puppetdb default configuration settings. class puppetdb::params inherits puppetdb::globals { $listen_address = 'localhost' $listen_port = '8080' $disable_cleartext = false $open_listen_port = false $ssl_listen_address = '0.0.0.0' $ssl_listen_port = '8081' $ssl_protocols = undef $disable_ssl = false $cipher_suites = undef $open_ssl_listen_port = undef $postgres_listen_addresses = 'localhost' $puppetdb_version = $puppetdb::globals::version $database = $puppetdb::globals::database $manage_dbserver = true $manage_database = true if $::osfamily =~ /RedHat|Debian/ { $manage_pg_repo = true } else { $manage_pg_repo = false } $postgres_version = '9.6' # The remaining database settings are not used for an embedded database $database_host = 'localhost' $database_port = '5432' $database_name = 'puppetdb' $database_username = 'puppetdb' $database_password = 'puppetdb' $manage_db_password = true $jdbc_ssl_properties = '' $database_validate = true $database_max_pool_size = undef # These settings manage the various auto-deactivation and auto-purge settings $node_ttl = '7d' $node_purge_ttl = '14d' $report_ttl = '14d' $facts_blacklist = undef $gc_interval = '60' $node_purge_gc_batch_limit = '25' $log_slow_statements = '10' $conn_max_age = '60' $conn_keep_alive = '45' $conn_lifetime = '0' $max_threads = undef $migrate = true # These settings are for the read database $read_database = 'postgres' $read_database_host = undef $read_database_port = '5432' $read_database_name = 'puppetdb' $read_database_username = 'puppetdb' $read_database_password = 'puppetdb' $manage_read_db_password = true $read_database_jdbc_ssl_properties = '' $read_database_validate = true $read_log_slow_statements = '10' $read_conn_max_age = '60' $read_conn_keep_alive = '45' $read_conn_lifetime = '0' $read_database_max_pool_size = undef $manage_firewall = true $java_args = {} $merge_default_java_args = true $puppetdb_package = 'puppetdb' $puppetdb_service = 'puppetdb' $masterless = false if !($puppetdb_version in ['latest','present','absent']) and versioncmp($puppetdb_version, '3.0.0') < 0 { case $::osfamily { 'RedHat', 'Suse', 'Archlinux','Debian': { $etcdir = '/etc/puppetdb' $vardir = '/var/lib/puppetdb' $database_embedded_path = "${vardir}/db/db" $puppet_confdir = pick($settings::confdir,'/etc/puppet') $puppet_service_name = 'puppetmaster' } 'OpenBSD': { $etcdir = '/etc/puppetdb' $vardir = '/var/db/puppetdb' $database_embedded_path = "${vardir}/db/db" $puppet_confdir = pick($settings::confdir,'/etc/puppet') $puppet_service_name = 'puppetmasterd' } 'FreeBSD': { $etcdir = '/usr/local/etc/puppetdb' $vardir = '/var/db/puppetdb' $database_embedded_path = "${vardir}/db/db" $puppet_confdir = pick($settings::confdir,'/usr/local/etc/puppet') $puppet_service_name = 'puppetmaster' } default: { fail("The fact 'osfamily' is set to ${::osfamily} which is not supported by the puppetdb module.") } } $terminus_package = 'puppetdb-terminus' $test_url = '/v3/version' } else { case $::osfamily { 'RedHat', 'Suse', 'Archlinux','Debian': { $etcdir = '/etc/puppetlabs/puppetdb' $puppet_confdir = pick($settings::confdir,'/etc/puppetlabs/puppet') $puppet_service_name = 'puppetserver' } 'OpenBSD': { $etcdir = '/etc/puppetlabs/puppetdb' $puppet_confdir = pick($settings::confdir,'/etc/puppetlabs/puppet') $puppet_service_name = undef } 'FreeBSD': { $etcdir = '/usr/local/etc/puppetlabs/puppetdb' $puppet_confdir = pick($settings::confdir,'/usr/local/etc/puppetlabs/puppet') $puppet_service_name = undef } default: { fail("The fact 'osfamily' is set to ${::osfamily} which is not supported by the puppetdb module.") } } $terminus_package = 'puppetdb-termini' $test_url = '/pdb/meta/v1/version' $vardir = '/opt/puppetlabs/server/data/puppetdb' $database_embedded_path = "${vardir}/db/db" } $confdir = "${etcdir}/conf.d" $ssl_dir = "${etcdir}/ssl" case $::osfamily { 'RedHat', 'Suse', 'Archlinux': { $puppetdb_user = 'puppetdb' $puppetdb_group = 'puppetdb' $puppetdb_initconf = '/etc/sysconfig/puppetdb' } 'Debian': { $puppetdb_user = 'puppetdb' $puppetdb_group = 'puppetdb' $puppetdb_initconf = '/etc/default/puppetdb' } 'OpenBSD': { $puppetdb_user = '_puppetdb' $puppetdb_group = '_puppetdb' $puppetdb_initconf = undef } 'FreeBSD': { $puppetdb_user = 'puppetdb' $puppetdb_group = 'puppetdb' $puppetdb_initconf = undef } default: { fail("The fact 'osfamily' is set to ${::osfamily} which is not supported by the puppetdb module.") } } $puppet_conf = "${puppet_confdir}/puppet.conf" $puppetdb_startup_timeout = 120 $puppetdb_service_status = 'running' $command_threads = undef $concurrent_writes = undef $store_usage = undef $temp_usage = undef $disable_update_checking = undef # reports of failed actions: https://puppet.com/docs/puppetdb/5.2/maintain_and_tune.html#clean-up-the-dead-letter-office $automatic_dlo_cleanup = true # any value for a systemd timer is valid: https://www.freedesktop.org/software/systemd/man/systemd.time.html $cleanup_timer_interval = "*-*-* ${fqdn_rand(24)}:${fqdn_rand(60)}:00" $dlo_max_age = 90 + # certificats used for PostgreSQL SSL configuration. Puppet certificates are used + $postgresql_ssl_on = false + $postgresql_ssl_folder = "${puppet_confdir}/ssl" + $postgresql_ssl_cert_path = "${postgresql_ssl_folder}/certs/${trusted['certname']}.pem" + $postgresql_ssl_key_path = "${postgresql_ssl_folder}/private_keys/${trusted['certname']}.pem" + $postgresql_ssl_ca_cert_path = "${postgresql_ssl_folder}/certs/ca.pem" + + # certificats used for Jetty configuration $ssl_set_cert_paths = false $ssl_cert_path = "${ssl_dir}/public.pem" $ssl_key_path = "${ssl_dir}/private.pem" $ssl_ca_cert_path = "${ssl_dir}/ca.pem" $ssl_deploy_certs = false $ssl_key = undef $ssl_cert = undef $ssl_ca_cert = undef + # certificate used by PuppetDB SSL Configuration + $ssl_key_pk8_path = regsubst($ssl_key_path, '.pem', '.pk8') + $certificate_whitelist_file = "${etcdir}/certificate-whitelist" # the default is free access for now $certificate_whitelist = [ ] # change to this to only allow access by the puppet master by default: #$certificate_whitelist = [ $::servername ] # Get the parameter name for the database connection pool tuning if $puppetdb_version in ['latest','present'] or versioncmp($puppetdb_version, '4.0.0') >= 0 { $database_max_pool_size_setting_name = 'maximum-pool-size' } elsif versioncmp($puppetdb_version, '2.8.0') >= 0 { $database_max_pool_size_setting_name = 'partition-conn-max' } else { $database_max_pool_size_setting_name = undef } # java binary path for PuppetDB. If undef, default will be used. $java_bin = undef } diff --git a/manifests/server.pp b/manifests/server.pp index 105e5e8..09823dc 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,370 +1,400 @@ # Class to configure a PuppetDB server. See README.md for more details. class puppetdb::server ( $listen_address = $puppetdb::params::listen_address, $listen_port = $puppetdb::params::listen_port, $disable_cleartext = $puppetdb::params::disable_cleartext, $open_listen_port = $puppetdb::params::open_listen_port, $ssl_listen_address = $puppetdb::params::ssl_listen_address, $ssl_listen_port = $puppetdb::params::ssl_listen_port, $disable_ssl = $puppetdb::params::disable_ssl, $open_ssl_listen_port = $puppetdb::params::open_ssl_listen_port, Stdlib::Absolutepath $ssl_dir = $puppetdb::params::ssl_dir, Boolean $ssl_set_cert_paths = $puppetdb::params::ssl_set_cert_paths, Stdlib::Absolutepath $ssl_cert_path = $puppetdb::params::ssl_cert_path, Stdlib::Absolutepath $ssl_key_path = $puppetdb::params::ssl_key_path, + Stdlib::Absolutepath $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, Stdlib::Absolutepath $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path, Boolean $ssl_deploy_certs = $puppetdb::params::ssl_deploy_certs, $ssl_key = $puppetdb::params::ssl_key, $ssl_cert = $puppetdb::params::ssl_cert, $ssl_ca_cert = $puppetdb::params::ssl_ca_cert, $ssl_protocols = $puppetdb::params::ssl_protocols, + $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, $cipher_suites = $puppetdb::params::cipher_suites, $migrate = $puppetdb::params::migrate, $database = $puppetdb::params::database, $database_host = $puppetdb::params::database_host, $database_port = $puppetdb::params::database_port, $database_username = $puppetdb::params::database_username, $database_password = $puppetdb::params::database_password, $database_name = $puppetdb::params::database_name, $manage_db_password = $puppetdb::params::manage_db_password, $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, $database_validate = $puppetdb::params::database_validate, $database_embedded_path = $puppetdb::params::database_embedded_path, $node_ttl = $puppetdb::params::node_ttl, $node_purge_ttl = $puppetdb::params::node_purge_ttl, $report_ttl = $puppetdb::params::report_ttl, Optional[Array] $facts_blacklist = $puppetdb::params::facts_blacklist, $gc_interval = $puppetdb::params::gc_interval, $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, $log_slow_statements = $puppetdb::params::log_slow_statements, $conn_max_age = $puppetdb::params::conn_max_age, $conn_keep_alive = $puppetdb::params::conn_keep_alive, $conn_lifetime = $puppetdb::params::conn_lifetime, $puppetdb_package = $puppetdb::params::puppetdb_package, $puppetdb_service = $puppetdb::params::puppetdb_service, $puppetdb_service_status = $puppetdb::params::puppetdb_service_status, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $read_database = $puppetdb::params::read_database, $read_database_host = $puppetdb::params::read_database_host, $read_database_port = $puppetdb::params::read_database_port, $read_database_username = $puppetdb::params::read_database_username, $read_database_password = $puppetdb::params::read_database_password, $read_database_name = $puppetdb::params::read_database_name, $manage_read_db_password = $puppetdb::params::manage_read_db_password, $read_database_jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, $read_database_validate = $puppetdb::params::read_database_validate, $read_log_slow_statements = $puppetdb::params::read_log_slow_statements, $read_conn_max_age = $puppetdb::params::read_conn_max_age, $read_conn_keep_alive = $puppetdb::params::read_conn_keep_alive, $read_conn_lifetime = $puppetdb::params::read_conn_lifetime, $confdir = $puppetdb::params::confdir, $vardir = $puppetdb::params::vardir, $manage_firewall = $puppetdb::params::manage_firewall, $java_args = $puppetdb::params::java_args, $merge_default_java_args = $puppetdb::params::merge_default_java_args, $max_threads = $puppetdb::params::max_threads, $command_threads = $puppetdb::params::command_threads, $concurrent_writes = $puppetdb::params::concurrent_writes, $store_usage = $puppetdb::params::store_usage, $temp_usage = $puppetdb::params::temp_usage, $disable_update_checking = $puppetdb::params::disable_update_checking, $certificate_whitelist_file = $puppetdb::params::certificate_whitelist_file, $certificate_whitelist = $puppetdb::params::certificate_whitelist, $database_max_pool_size = $puppetdb::params::database_max_pool_size, $read_database_max_pool_size = $puppetdb::params::read_database_max_pool_size, Boolean $automatic_dlo_cleanup = $puppetdb::params::automatic_dlo_cleanup, String[1] $cleanup_timer_interval = $puppetdb::params::cleanup_timer_interval, Integer[1] $dlo_max_age = $puppetdb::params::dlo_max_age, Optional[Stdlib::Absolutepath] $java_bin = $puppetdb::params::java_bin, ) inherits puppetdb::params { # Apply necessary suffix if zero is specified. # Can we drop this in the next major release? if $node_ttl == '0' { $_node_ttl_real = '0s' } else { $_node_ttl_real = downcase($node_ttl) } # Validate node_ttl $node_ttl_real = assert_type(Puppetdb::Ttl, $_node_ttl_real) # Apply necessary suffix if zero is specified. # Can we drop this in the next major release? if $node_purge_ttl == '0' { $_node_purge_ttl_real = '0s' } else { $_node_purge_ttl_real = downcase($node_purge_ttl) } # Validate node_purge_ttl $node_purge_ttl_real = assert_type(Puppetdb::Ttl, $_node_purge_ttl_real) # Apply necessary suffix if zero is specified. # Can we drop this in the next major release? if $report_ttl == '0' { $_report_ttl_real = '0s' } else { $_report_ttl_real = downcase($report_ttl) } # Validate report_ttl $repor_ttl_real = assert_type(Puppetdb::Ttl, $_report_ttl_real) # Validate puppetdb_service_status $service_enabled = $puppetdb_service_status ? { /(running|true)/ => true, /(stopped|false)/ => false, default => fail("puppetdb_service_status valid values are 'true', 'running', 'false', and 'stopped'. You provided '${puppetdb_service_status}'"), } # Validate database type (Currently only postgres and embedded are supported) if !($database in ['postgres', 'embedded']) { fail("database must must be 'postgres' or 'embedded'. You provided '${database}'") } # Validate read-database type (Currently only postgres is supported) if !($read_database in ['postgres']) { fail("read_database must be 'postgres'. You provided '${read_database}'") } package { $puppetdb_package: ensure => $puppetdb::params::puppetdb_version, notify => Service[$puppetdb_service], } if $manage_firewall { class { 'puppetdb::server::firewall': http_port => $listen_port, open_http_port => $open_listen_port, ssl_port => $ssl_listen_port, open_ssl_port => $open_ssl_listen_port, } } class { 'puppetdb::server::global': vardir => $vardir, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, notify => Service[$puppetdb_service], } class { 'puppetdb::server::command_processing': command_threads => $command_threads, concurrent_writes => $concurrent_writes, store_usage => $store_usage, temp_usage => $temp_usage, confdir => $confdir, notify => Service[$puppetdb_service], } class { 'puppetdb::server::database': database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, manage_db_password => $manage_db_password, + postgresql_ssl_on => $postgresql_ssl_on, + ssl_key_pk8_path => $ssl_key_pk8_path, + ssl_cert_path => $ssl_cert_path, + ssl_ca_cert_path => $ssl_ca_cert_path, database_max_pool_size => $database_max_pool_size, jdbc_ssl_properties => $jdbc_ssl_properties, database_validate => $database_validate, database_embedded_path => $database_embedded_path, node_ttl => $node_ttl, node_purge_ttl => $node_purge_ttl, report_ttl => $report_ttl, facts_blacklist => $facts_blacklist, gc_interval => $gc_interval, node_purge_gc_batch_limit => $node_purge_gc_batch_limit, log_slow_statements => $log_slow_statements, conn_max_age => $conn_max_age, conn_keep_alive => $conn_keep_alive, conn_lifetime => $conn_lifetime, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, migrate => $migrate, notify => Service[$puppetdb_service], } class { 'puppetdb::server::read_database': database => $read_database, database_host => $read_database_host, database_port => $read_database_port, database_username => $read_database_username, database_password => $read_database_password, database_name => $read_database_name, manage_db_password => $manage_read_db_password, + postgresql_ssl_on => $postgresql_ssl_on, + ssl_key_pk8_path => $ssl_key_pk8_path, + ssl_cert_path => $ssl_cert_path, + ssl_ca_cert_path => $ssl_ca_cert_path, jdbc_ssl_properties => $read_database_jdbc_ssl_properties, database_validate => $read_database_validate, log_slow_statements => $read_log_slow_statements, conn_max_age => $read_conn_max_age, conn_keep_alive => $read_conn_keep_alive, conn_lifetime => $read_conn_lifetime, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, notify => Service[$puppetdb_service], database_max_pool_size => $read_database_max_pool_size, } if $ssl_deploy_certs { file { $ssl_dir: ensure => directory, owner => $puppetdb_user, group => $puppetdb_group, mode => '0700'; $ssl_key_path: ensure => file, content => $ssl_key, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service]; $ssl_cert_path: ensure => file, content => $ssl_cert, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service]; $ssl_ca_cert_path: ensure => file, content => $ssl_ca_cert, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service]; } } + if $postgresql_ssl_on { + exec { $ssl_key_pk8_path: + path => [ '/opt/puppetlabs/puppet/bin', $facts['path'] ], + command => "openssl pkcs8 -topk8 -inform PEM -outform DER -in ${ssl_key_path} -out ${ssl_key_pk8_path} -nocrypt", + # Generate a .pk8 key if one doesn't exist or is older than the .pem input. + # NOTE: bash file time checks, like -ot, can't always discern sub-second + # differences. + onlyif => "test ! -e '${ssl_key_pk8_path}' -o '${ssl_key_pk8_path}' -ot '${ssl_key_path}'", + before => File[$ssl_key_pk8_path] + } + + file { $ssl_key_pk8_path: + ensure => present, + owner => $puppetdb_user, + group => $puppetdb_group, + mode => '0600', + notify => Service[$puppetdb_service] + } + } + class { 'puppetdb::server::jetty': listen_address => $listen_address, listen_port => $listen_port, disable_cleartext => $disable_cleartext, ssl_listen_address => $ssl_listen_address, ssl_listen_port => $ssl_listen_port, ssl_set_cert_paths => $ssl_set_cert_paths, ssl_key_path => $ssl_key_path, ssl_cert_path => $ssl_cert_path, ssl_ca_cert_path => $ssl_ca_cert_path, ssl_protocols => $ssl_protocols, cipher_suites => $cipher_suites, disable_ssl => $disable_ssl, confdir => $confdir, max_threads => $max_threads, notify => Service[$puppetdb_service], puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, } class { 'puppetdb::server::puppetdb': certificate_whitelist_file => $certificate_whitelist_file, certificate_whitelist => $certificate_whitelist, disable_update_checking => $disable_update_checking, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, notify => Service[$puppetdb_service], } if !empty($java_args) { if $merge_default_java_args { create_resources( 'ini_subsetting', puppetdb::create_subsetting_resource_hash( $java_args, { ensure => present, section => '', key_val_separator => '=', path => $puppetdb::params::puppetdb_initconf, setting => 'JAVA_ARGS', require => Package[$puppetdb_package], notify => Service[$puppetdb_service], })) } else { ini_setting { 'java_args': ensure => present, section => '', path => $puppetdb::params::puppetdb_initconf, setting => 'JAVA_ARGS', require => Package[$puppetdb_package], notify => Service[$puppetdb_service], value => puppetdb::flatten_java_args($java_args), } } } # java binary path for PuppetDB. If undef, default will be used. if $java_bin { ini_setting{'java': ensure => 'present', section => '', path => $puppetdb::params::puppetdb_initconf, setting => 'JAVA_BIN', require => Package[$puppetdb_package], notify => Service[$puppetdb_service], value => $java_bin, } } if $automatic_dlo_cleanup { if $facts['systemd'] { # deploy a systemd timer + service to cleanup old reports # https://puppet.com/docs/puppetdb/5.2/maintain_and_tune.html#clean-up-the-dead-letter-office systemd::unit_file{'puppetdb-dlo-cleanup.service': content => epp("${module_name}/puppetdb-DLO-cleanup.service.epp", { 'puppetdb_user' => $puppetdb_user, 'puppetdb_group' => $puppetdb_group, 'vardir' => $vardir, 'dlo_max_age' => $dlo_max_age }), } -> systemd::unit_file{'puppetdb-dlo-cleanup.timer': content => epp("${module_name}/puppetdb-DLO-cleanup.timer.epp", {'cleanup_timer_interval' => $cleanup_timer_interval}), enable => true, active => true, } } else { cron { 'puppetdb-dlo-cleanup': ensure => 'present', minute => fqdn_rand(60), hour => fqdn_rand(24), monthday => '*', month => '*', weekday => '*', command => "/usr/bin/find ${vardir}/stockpile/discard/ -type f -mtime ${dlo_max_age} -delete", user => $puppetdb_user, } } } service { $puppetdb_service: ensure => $puppetdb_service_status, enable => $service_enabled, } if $manage_firewall { Package[$puppetdb_package] -> Class['puppetdb::server::firewall'] -> Class['puppetdb::server::global'] -> Class['puppetdb::server::command_processing'] -> Class['puppetdb::server::database'] -> Class['puppetdb::server::read_database'] -> Class['puppetdb::server::jetty'] -> Class['puppetdb::server::puppetdb'] -> Service[$puppetdb_service] } else { Package[$puppetdb_package] -> Class['puppetdb::server::global'] -> Class['puppetdb::server::command_processing'] -> Class['puppetdb::server::database'] -> Class['puppetdb::server::read_database'] -> Class['puppetdb::server::jetty'] -> Class['puppetdb::server::puppetdb'] -> Service[$puppetdb_service] } } diff --git a/manifests/server/database.pp b/manifests/server/database.pp index 68f89d7..1ba0234 100644 --- a/manifests/server/database.pp +++ b/manifests/server/database.pp @@ -1,201 +1,221 @@ # PRIVATE CLASS - do not use directly class puppetdb::server::database ( $database = $puppetdb::params::database, $database_host = $puppetdb::params::database_host, $database_port = $puppetdb::params::database_port, $database_username = $puppetdb::params::database_username, $database_password = $puppetdb::params::database_password, $database_name = $puppetdb::params::database_name, $manage_db_password = $puppetdb::params::manage_db_password, $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, $database_validate = $puppetdb::params::database_validate, $database_embedded_path = $puppetdb::params::database_embedded_path, $node_ttl = $puppetdb::params::node_ttl, $node_purge_ttl = $puppetdb::params::node_purge_ttl, $report_ttl = $puppetdb::params::report_ttl, $facts_blacklist = $puppetdb::params::facts_blacklist, $gc_interval = $puppetdb::params::gc_interval, $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, $log_slow_statements = $puppetdb::params::log_slow_statements, $conn_max_age = $puppetdb::params::conn_max_age, $conn_keep_alive = $puppetdb::params::conn_keep_alive, $conn_lifetime = $puppetdb::params::conn_lifetime, $confdir = $puppetdb::params::confdir, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $database_max_pool_size = $puppetdb::params::database_max_pool_size, $migrate = $puppetdb::params::migrate, + $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, + $ssl_cert_path = $puppetdb::params::ssl_cert_path, + $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, + $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path ) inherits puppetdb::params { if str2bool($database_validate) { # Validate the database connection. If we can't connect, we want to fail # and skip the rest of the configuration, so that we don't leave puppetdb # in a broken state. # # NOTE: # Because of a limitation in the postgres module this will break with # a duplicate declaration if read and write database host+name are the # same. class { 'puppetdb::server::validate_db': database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, } } $database_ini = "${confdir}/database.ini" file { $database_ini: ensure => file, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', } $file_require = File[$database_ini] $ini_setting_require = str2bool($database_validate) ? { false => $file_require, default => [$file_require, Class['puppetdb::server::validate_db']], } # Set the defaults Ini_setting { path => $database_ini, ensure => present, section => 'database', require => $ini_setting_require } if $database == 'embedded' { $classname = 'org.hsqldb.jdbcDriver' $subprotocol = 'hsqldb' $subname = "file:${database_embedded_path};hsqldb.tx=mvcc;sql.syntax_pgs=true" } elsif $database == 'postgres' { $classname = 'org.postgresql.Driver' $subprotocol = 'postgresql' if !empty($jdbc_ssl_properties) { $database_suffix = $jdbc_ssl_properties } else { $database_suffix = '' } - $subname = "//${database_host}:${database_port}/${database_name}${database_suffix}" + $subname_default = "//${database_host}:${database_port}/${database_name}${database_suffix}" + + if $postgresql_ssl_on and !empty($jdbc_ssl_properties) + { + fail("Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!") + } + + if $postgresql_ssl_on { + $subname = @("EOT"/L) + ${subname_default}?\ + ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ + sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ + sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ + | EOT + } else { + $subname = $subname_default + } ##Only setup for postgres ini_setting {'puppetdb_psdatabase_username': setting => 'username', value => $database_username, } if $database_password != undef and $manage_db_password { ini_setting {'puppetdb_psdatabase_password': setting => 'password', value => $database_password, } } } ini_setting { 'puppetdb_classname': setting => 'classname', value => $classname, } ini_setting { 'puppetdb_subprotocol': setting => 'subprotocol', value => $subprotocol, } ini_setting { 'puppetdb_pgs': setting => 'syntax_pgs', value => true, } ini_setting { 'puppetdb_subname': setting => 'subname', value => $subname, } ini_setting { 'puppetdb_gc_interval': setting => 'gc-interval', value => $gc_interval, } ini_setting { 'puppetdb_node_purge_gc_batch_limit': setting => 'node-purge-gc-batch-limit', value => $node_purge_gc_batch_limit, } ini_setting { 'puppetdb_node_ttl': setting => 'node-ttl', value => $node_ttl, } ini_setting { 'puppetdb_node_purge_ttl': setting => 'node-purge-ttl', value => $node_purge_ttl, } ini_setting { 'puppetdb_report_ttl': setting => 'report-ttl', value => $report_ttl, } ini_setting { 'puppetdb_log_slow_statements': setting => 'log-slow-statements', value => $log_slow_statements, } ini_setting { 'puppetdb_conn_max_age': setting => 'conn-max-age', value => $conn_max_age, } ini_setting { 'puppetdb_conn_keep_alive': setting => 'conn-keep-alive', value => $conn_keep_alive, } ini_setting { 'puppetdb_conn_lifetime': setting => 'conn-lifetime', value => $conn_lifetime, } ini_setting { 'puppetdb_migrate': setting => 'migrate', value => $migrate, } if $puppetdb::params::database_max_pool_size_setting_name != undef { if $database_max_pool_size == 'absent' { ini_setting { 'puppetdb_database_max_pool_size': ensure => absent, setting => $puppetdb::params::database_max_pool_size_setting_name, } } elsif $database_max_pool_size != undef { ini_setting { 'puppetdb_database_max_pool_size': setting => $puppetdb::params::database_max_pool_size_setting_name, value => $database_max_pool_size, } } } if ($facts_blacklist) and length($facts_blacklist) != 0 { $joined_facts_blacklist = join($facts_blacklist, ', ') ini_setting { 'puppetdb_facts_blacklist': setting => 'facts-blacklist', value => $joined_facts_blacklist, } } else { ini_setting { 'puppetdb_facts_blacklist': ensure => absent, setting => 'facts-blacklist', } } } diff --git a/manifests/server/read_database.pp b/manifests/server/read_database.pp index a51a68b..093627e 100644 --- a/manifests/server/read_database.pp +++ b/manifests/server/read_database.pp @@ -1,149 +1,169 @@ # PRIVATE CLASS - do not use directly class puppetdb::server::read_database ( $database = $puppetdb::params::read_database, $database_host = $puppetdb::params::read_database_host, $database_port = $puppetdb::params::read_database_port, $database_username = $puppetdb::params::read_database_username, $database_password = $puppetdb::params::read_database_password, $database_name = $puppetdb::params::read_database_name, $manage_db_password = $puppetdb::params::manage_read_db_password, $jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, $database_validate = $puppetdb::params::read_database_validate, $log_slow_statements = $puppetdb::params::read_log_slow_statements, $conn_max_age = $puppetdb::params::read_conn_max_age, $conn_keep_alive = $puppetdb::params::read_conn_keep_alive, $conn_lifetime = $puppetdb::params::read_conn_lifetime, $confdir = $puppetdb::params::confdir, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $database_max_pool_size = $puppetdb::params::read_database_max_pool_size, + $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, + $ssl_cert_path = $puppetdb::params::ssl_cert_path, + $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, + $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path ) inherits puppetdb::params { # Only add the read database configuration if database host is defined. if $database_host != undef { if str2bool($database_validate) { # Validate the database connection. If we can't connect, we want to fail # and skip the rest of the configuration, so that we don't leave puppetdb # in a broken state. # # NOTE: # Because of a limitation in the postgres module this will break with # a duplicate declaration if read and write database host+name are the # same. class { 'puppetdb::server::validate_read_db': database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, } } $read_database_ini = "${confdir}/read_database.ini" file { $read_database_ini: ensure => file, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', } $file_require = File[$read_database_ini] $ini_setting_require = str2bool($database_validate) ? { false => $file_require, default => [$file_require, Class['puppetdb::server::validate_read_db']], } # Set the defaults Ini_setting { path => $read_database_ini, ensure => present, section => 'read-database', require => $ini_setting_require, } if $database == 'postgres' { $classname = 'org.postgresql.Driver' $subprotocol = 'postgresql' if !empty($jdbc_ssl_properties) { $database_suffix = $jdbc_ssl_properties } else { $database_suffix = '' } - $subname = "//${database_host}:${database_port}/${database_name}${database_suffix}" + $subname_default = "//${database_host}:${database_port}/${database_name}${database_suffix}" + + if $postgresql_ssl_on and !empty($jdbc_ssl_properties) + { + fail("Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!") + } + + if $postgresql_ssl_on { + $subname = @("EOT"/L) + ${subname_default}?\ + ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ + sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ + sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ + | EOT + } else { + $subname = $subname_default + } ini_setting { 'puppetdb_read_database_username': setting => 'username', value => $database_username, } if $database_password != undef and $manage_db_password { ini_setting { 'puppetdb_read_database_password': setting => 'password', value => $database_password, } } } ini_setting { 'puppetdb_read_classname': setting => 'classname', value => $classname, } ini_setting { 'puppetdb_read_subprotocol': setting => 'subprotocol', value => $subprotocol, } ini_setting { 'puppetdb_read_pgs': setting => 'syntax_pgs', value => true, } ini_setting { 'puppetdb_read_subname': setting => 'subname', value => $subname, } ini_setting { 'puppetdb_read_log_slow_statements': setting => 'log-slow-statements', value => $log_slow_statements, } ini_setting { 'puppetdb_read_conn_max_age': setting => 'conn-max-age', value => $conn_max_age, } ini_setting { 'puppetdb_read_conn_keep_alive': setting => 'conn-keep-alive', value => $conn_keep_alive, } ini_setting { 'puppetdb_read_conn_lifetime': setting => 'conn-lifetime', value => $conn_lifetime, } if $puppetdb::params::database_max_pool_size_setting_name != undef { if $database_max_pool_size == 'absent' { ini_setting { 'puppetdb_read_database_max_pool_size': ensure => absent, setting => $puppetdb::params::database_max_pool_size_setting_name, } } elsif $database_max_pool_size != undef { ini_setting { 'puppetdb_read_database_max_pool_size': setting => $puppetdb::params::database_max_pool_size_setting_name, value => $database_max_pool_size, } } } } else { file { "${confdir}/read_database.ini": ensure => absent, } } } diff --git a/spec/acceptance/basic_spec.rb b/spec/acceptance/basic_spec.rb index 9ae27b5..57e2779 100644 --- a/spec/acceptance/basic_spec.rb +++ b/spec/acceptance/basic_spec.rb @@ -1,48 +1,80 @@ require 'beaker-puppet' require 'beaker-pe' require 'spec_helper_acceptance' describe 'basic tests:' do it 'make sure we have copied the module across' do # No point diagnosing any more if the module wasn't copied properly shell('ls /etc/puppetlabs/code/modules/puppetdb') do |r| r.exit_code.should be_zero r.stdout.should =~ %r{metadata\.json} r.stderr.should == '' end end describe 'single node setup' do pp = <<-EOS # Single node setup class { 'puppetdb': disable_ssl => true, } -> class { 'puppetdb::master::config': puppetdb_port => '8080', puppetdb_server => 'localhost' } EOS it 'make sure it runs without error' do apply_manifest(pp, catch_errors: true) apply_manifest(pp, catch_changes: true) end end + describe 'single node with ssl' do + ssl_config = <<-EOS + class { 'puppetdb': postgresql_ssl_on => true, + database_listen_address => '0.0.0.0', + database_host => $facts['fqdn'],} + EOS + + it 'make sure it runs without error' do + apply_manifest(ssl_config, catch_errors: true) + apply_manifest(ssl_config, catch_changes: true) + end + + change_password = <<-EOS + ini_setting { "puppetdb password": + ensure => present, + path => '/etc/puppetlabs/puppetdb/conf.d/database.ini', + section => 'database', + setting => 'password', + value => 'random_password', + notify => Service[puppetdb] + } + + service { 'puppetdb': + ensure => 'running', + } + EOS + it 'make sure it starts with wrong password' do + apply_manifest(change_password, catch_errors: true) + apply_manifest(change_password, catch_changes: true) + end + end + describe 'enabling report processor' do pp = <<-EOS class { 'puppetdb': disable_ssl => true, } -> class { 'puppetdb::master::config': puppetdb_port => '8080', manage_report_processor => true, enable_reports => true, puppetdb_server => 'localhost' } EOS it 'adds the puppetdb report processor to puppet.conf' do apply_manifest(pp, catch_errors: true) apply_manifest(pp, catch_changes: true) shell('cat /etc/puppetlabs/puppet/puppet.conf') do |r| expect(r.stdout).to match(%r{^reports\s*=\s*([^,]+,)*puppetdb(,[^,]+)*$}) end end end end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index 61ab992..6658795 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,126 +1,127 @@ require 'beaker-rspec' require 'beaker-puppet' require 'beaker/puppet_install_helper' require 'beaker/module_install_helper' def use_puppet4? (ENV['PUPPET_INSTALL_VERSION'] =~ %r{^2016}) ? true : false end def use_puppet5? (ENV['BEAKER_PUPPET_COLLECTION'] =~ %r{^puppet5}) ? true : false end def use_puppet6? (ENV['BEAKER_PUPPET_COLLECTION'] =~ %r{^puppet6}) ? true : false end def use_puppet7? (ENV['BEAKER_PUPPET_COLLECTION'] =~ %r{^puppet7}) ? true : false end def build_url(platform) if use_puppet4? url4 = 'http://%{mngr}.puppetlabs.com/puppetlabs-release-pc1%{plat}' case platform when 'el' then url4 % { mngr: 'yum', plat: '-el-' } when 'fedora' then url4 % { mngr: 'yum', plat: '-fedora-' } when 'debian', 'ubuntu' then url4 % { mngr: 'apt', plat: '-' } else raise "build_url() called with unsupported platform '#{platform}'" end elsif use_puppet5? url5 = 'http://%{mngr}.puppetlabs.com/%{dir}puppet5-release%{plat}' case platform when 'el' then url5 % { mngr: 'yum', dir: 'puppet5/', plat: '-el-' } when 'fedora' then url5 % { mngr: 'yum', dir: 'puppet5/', plat: '-fedora-' } when 'debian', 'ubuntu' then url5 % { mngr: 'apt', dir: '', plat: '-' } else raise "build_url() called with unsupported platform '#{platform}'" end elsif use_puppet6? url6 = 'http://%{mngr}.puppetlabs.com/%{dir}puppet6-release%{plat}' case platform when 'el' then url6 % { mngr: 'yum', dir: 'puppet6/', plat: '-el-' } when 'fedora' then url6 % { mngr: 'yum', dir: 'puppet6/', plat: '-fedora-' } when 'debian', 'ubuntu' then url6 % { mngr: 'apt', dir: '', plat: '-' } else raise "build_url() called with unsupported platform '#{platform}'" end else url7 = 'http://%{mngr}.puppetlabs.com/%{dir}puppet7-release%{plat}' case platform when 'el' then url7 % { mngr: 'yum', dir: 'puppet7/', plat: '-el-' } when 'fedora' then url7 % { mngr: 'yum', dir: 'puppet7/', plat: '-fedora-' } when 'debian', 'ubuntu' then url7 % { mngr: 'apt', dir: '', plat: '-' } else raise "build_url() called with unsupported platform '#{platform}'" end end end hosts.each do |host| if host['platform'] =~ %r{debian} on host, 'echo \'export PATH=/var/lib/gems/1.8/bin/:${PATH}\' >> ~/.bashrc' end # install_puppet if host['platform'] =~ %r{el-(5|6|7)} relver = Regexp.last_match(1) on host, "rpm -ivh #{build_url('el')}#{relver}.noarch.rpm" on host, 'yum install -y puppetserver' elsif host['platform'] =~ %r{fedora-(\d+)} relver = Regexp.last_match(1) on host, "rpm -ivh #{build_url('fedora')}#{relver}.noarch.rpm" on host, 'yum install -y puppetserver' elsif host['platform'] =~ %r{(ubuntu|debian)} unless host.check_for_package 'curl' on host, 'apt-get install -y curl' end # For openjdk8 if host['platform'].version == '8' && !use_puppet4? create_remote_file(host, '/etc/apt/sources.list.d/jessie-backports.list', 'deb https://artifactory.delivery.puppetlabs.net/artifactory/debian_archive__remote/ jessie-backports main') on host, 'apt-get -y -m update' install_package(host, 'openjdk-8-jre-headless') end on host, 'apt-get install apt-transport-https --assume-yes' on host, "curl -O #{build_url('debian')}$(lsb_release -c -s).deb" if use_puppet4? on host, 'dpkg -i puppetlabs-release-pc1-$(lsb_release -c -s).deb' elsif use_puppet5? on host, 'dpkg -i puppet5-release-$(lsb_release -c -s).deb' elsif use_puppet6? on host, 'dpkg -i puppet6-release-$(lsb_release -c -s).deb' else on host, 'dpkg -i puppet7-release-$(lsb_release -c -s).deb' end on host, 'apt-get -y -m update' on host, 'apt-get install -y puppetserver' + on host, '/opt/puppetlabs/bin/puppetserver ca setup' else raise "install_puppet() called for unsupported platform '#{host['platform']}' on '#{host.name}'" end end opts = { puppet_agent_version: 'latest' } opts[:puppet_collection] = if use_puppet5? 'puppet5' elsif use_puppet6? 'puppet6' elsif use_puppet7? 'puppet7' end install_puppet_agent_on(hosts, opts) unless ENV['BEAKER_provision'] == 'no' install_ca_certs unless ENV['PUPPET_INSTALL_TYPE'] =~ %r{pe}i install_module_on(hosts) install_module_dependencies_on(hosts) RSpec.configure do |c| # Readable test descriptions c.formatter = :documentation hosts.each do |host| if host[:platform] =~ %r{el-7-x86_64} && host[:hypervisor] =~ %r{docker} on(host, "sed -i '/nodocs/d' /etc/yum.conf") end end end diff --git a/spec/unit/classes/database/postgresql_spec.rb b/spec/unit/classes/database/postgresql_spec.rb new file mode 100644 index 0000000..d53066e --- /dev/null +++ b/spec/unit/classes/database/postgresql_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'puppetdb::database::postgresql', type: :class do + context 'on a supported platform' do + let(:facts) do + { + osfamily: 'RedHat', + operatingsystem: 'RedHat', + puppetversion: Puppet.version, + operatingsystemrelease: '7.0', + kernel: 'Linux', + selinux: true, + os: { + family: 'RedHat', + name: 'RedHat', + release: { 'full' => '7.0', 'major' => '7' }, + selinux: { 'enabled' => true }, + }, + } + end + + it { is_expected.to contain_class('puppetdb::database::postgresql') } + + context 'when ssl communication is used' do + let(:params) do + { + postgresql_ssl_on: true, + } + end + + it { is_expected.to contain_class('puppetdb::database::ssl_configuration') } + end + + context 'when ssl communication is not used' do + let(:params) do + { + postgresql_ssl_on: false, + } + end + + it { is_expected.not_to contain_class('puppetdb::database::ssl_configuration') } + end + end +end diff --git a/spec/unit/classes/database/ssl_configuration_spec.rb b/spec/unit/classes/database/ssl_configuration_spec.rb new file mode 100644 index 0000000..72af0f6 --- /dev/null +++ b/spec/unit/classes/database/ssl_configuration_spec.rb @@ -0,0 +1,122 @@ +require 'spec_helper' + +describe 'puppetdb::database::ssl_configuration', type: :class do + context 'on a supported platform' do + let(:facts) do + { + osfamily: 'RedHat', + operatingsystem: 'RedHat', + puppetversion: Puppet.version, + operatingsystemrelease: '7.0', + kernel: 'Linux', + selinux: true, + os: { + family: 'RedHat', + name: 'RedHat', + release: { 'full' => '7.0', 'major' => '7' }, + selinux: { 'enabled' => true }, + }, + fqdn: 'cheery-rime@puppet', + } + end + + let(:params) do + { + postgresql_ssl_key_path: '/puppet/ssl/key.pem', + postgresql_ssl_cert_path: '/puppet/ssl/cert.pem', + postgresql_ssl_ca_cert_path: '/puppet/cert/ca.pem', + database_name: 'puppetdb', + database_username: 'puppetdb', + } + end + + let(:identity_map) { "#{params[:database_name]}-#{params[:database_username]}-map" } + let(:datadir_path) { '/var/lib/data' } + + let(:pre_condition) do + "class { 'postgresql::server': datadir => '/var/lib/data'} " + end + + it { is_expected.to contain_class('puppetdb::database::ssl_configuration') } + it { is_expected.to compile.with_all_deps } + + it 'has server.key file' do + is_expected.to contain_file('postgres private key') + .with( + ensure: 'present', + owner: 'postgres', + mode: '0600', + path: "#{datadir_path}/server.key", + ) + .that_requires('Package[postgresql-server]') + end + + it 'has server.crt file' do + is_expected.to contain_file('postgres public key') + .with( + ensure: 'present', + owner: 'postgres', + mode: '0600', + path: "#{datadir_path}/server.crt", + ) + .that_requires('Package[postgresql-server]') + end + + it 'has ssl config attribute' do + is_expected.to contain_postgresql__server__config_entry('ssl') + .with_value('on').with_ensure('present') + .that_requires('File[postgres private key]') + .that_requires('File[postgres public key]') + end + + it 'has ssl_cert_file config attribute' do + is_expected.to contain_postgresql__server__config_entry('ssl_cert_file') + .with_value("#{datadir_path}/server.crt").with_ensure('present') + .that_requires('File[postgres private key]') + .that_requires('File[postgres public key]') + end + + it 'has ssl_key_file config attribute' do + is_expected.to contain_postgresql__server__config_entry('ssl_key_file') + .with_value("#{datadir_path}/server.key").with_ensure('present') + .that_requires('File[postgres private key]') + .that_requires('File[postgres public key]') + end + + it 'has ssl_ca_file config attribute' do + is_expected.to contain_postgresql__server__config_entry('ssl_ca_file') + .with_value(params[:postgresql_ssl_ca_cert_path]).with_ensure('present') + .that_requires('File[postgres private key]') + .that_requires('File[postgres public key]') + end + + it 'has hba rule for ipv4' do + is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:database_username]} (ipv4)") + .with_type('hostssl') + .with_database(params[:database_name]) + .with_user(params[:database_username]) + .with_address('0.0.0.0/0') + .with_auth_method('cert') + .with_order(0) + .with_auth_option("map=#{identity_map} clientcert=1") + end + + it 'has hba rule for ipv6' do + is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:database_username]} (ipv6)") + .with_type('hostssl') + .with_database(params[:database_name]) + .with_user(params[:database_username]) + .with_address('::0/0') + .with_auth_method('cert') + .with_order(0) + .with_auth_option("map=#{identity_map} clientcert=1") + end + + it 'has ident rule' do + is_expected.to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{params[:database_username]} user") + .with_map_name(identity_map) + .with_system_username(facts[:fqdn]) + .with_database_username(params[:database_name]) + end + end +end diff --git a/spec/unit/classes/init_spec.rb b/spec/unit/classes/init_spec.rb index ddc57cc..5d86731 100644 --- a/spec/unit/classes/init_spec.rb +++ b/spec/unit/classes/init_spec.rb @@ -1,98 +1,109 @@ require 'spec_helper' describe 'puppetdb', type: :class do ttl_args = ['node_ttl', 'node_purge_ttl', 'report_ttl'] on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do facts.merge(selinux: false) end describe 'when using default values for puppetdb class' do it { is_expected.to compile.with_all_deps } it { is_expected.to contain_class('puppetdb') } it { is_expected.to contain_class('puppetdb::server') } it { is_expected.to contain_class('puppetdb::database::postgresql') } it { is_expected.to contain_postgresql__server__db('puppetdb') } end describe 'without managed postgresql' do let :pre_condition do <<-HEREDOC class { 'postgresql::server': } HEREDOC end let :params do { manage_dbserver: false, } end describe 'manifest' do it { is_expected.to compile.with_all_deps } end end describe 'without managed postgresql database' do let :params do { manage_dbserver: true, manage_database: false, } end describe 'manifest' do it { is_expected.to compile.with_all_deps } it { is_expected.not_to contain_postgresql__server__db('puppetdb') } end end context 'when not managing the database password' do let(:params) do { 'manage_db_password' => false, 'manage_read_db_password' => false, 'read_database_host' => '10.0.0.1', # Make sure the read_database class is enforced. } end describe 'ini_setting entries for the password will not exist' do it { is_expected.to contain_class('puppetdb::server').with('manage_db_password' => false) } it { is_expected.to contain_class('puppetdb::server').with('manage_read_db_password' => false) } it { is_expected.not_to contain_ini__setting('puppetdb_psdatabase_password') } it { is_expected.not_to contain_ini__setting('puppetdb_read_database_password') } end end + + context 'when using ssl certificates' do + let(:params) do + { + postgresql_ssl_on: true, + } + end + + it { is_expected.to contain_class('puppetdb::server').with('postgresql_ssl_on' => true) } + it { is_expected.to contain_class('puppetdb::database::postgresql').with('postgresql_ssl_on' => true) } + end end end context 'with invalid arguments on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'Debian', puppetversion: Puppet.version, operatingsystemrelease: '6.0', kernel: 'Linux', concat_basedir: '/var/lib/puppet/concat', selinux: true, iptables_persistent_version: '0.5.7', } end ttl_args.each do |ttl_arg| let(:params) do { ttl_arg => 'invalid_value', } end it "when using a value that does not match the validation regex for #{ttl_arg} puppetdb class" do expect { is_expected.to contain_class('puppetdb') }.to raise_error(Puppet::Error) end end end end diff --git a/spec/unit/classes/master/config_spec.rb b/spec/unit/classes/master/config_spec.rb index 896cccf..17a338a 100644 --- a/spec/unit/classes/master/config_spec.rb +++ b/spec/unit/classes/master/config_spec.rb @@ -1,162 +1,162 @@ require 'spec_helper' describe 'puppetdb::master::config', type: :class do on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do facts.merge(puppetversion: Puppet.version, fqdn: 'puppetdb.example.com', selinux: true) end context 'when PuppetDB on remote server' do context 'when using default values' do it { is_expected.to compile.with_all_deps } end end context 'when PuppetDB and Puppet Master are on the same server' do context 'when using default values' do let(:pre_condition) { 'class { "puppetdb": }' } it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( puppetdb_server: 'puppetdb.example.com', puppetdb_port: '8081', use_ssl: 'true', ) } end context 'when puppetdb class is declared with disable_ssl => true' do let(:pre_condition) { 'class { "puppetdb": disable_ssl => true }' } it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( puppetdb_port: '8080', use_ssl: 'false', ) } end context 'when puppetdb_port => 1234' do let(:pre_condition) { 'class { "puppetdb": }' } let(:params) { { puppetdb_port: '1234' } } it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( puppetdb_port: '1234', use_ssl: 'true', ) } end context 'when puppetdb_port => 1234 AND the puppetdb class is declared with disable_ssl => true' do let(:pre_condition) { 'class { "puppetdb": disable_ssl => true }' } let(:params) { { puppetdb_port: '1234' } } it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with( puppetdb_port: '1234', use_ssl: 'false', ) } end context 'when using default values' do it { is_expected.to contain_package('puppetdb-termini').with(ensure: 'present') } it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with(test_url: '/pdb/meta/v1/version') } end context 'when using an older puppetdb version' do let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } it { is_expected.to contain_package('puppetdb-terminus').with(ensure: '2.2.0') } it { is_expected.to contain_puppetdb_conn_validator('puppetdb_conn').with(test_url: '/v3/version') } end end end end context 'when upgrading to from v2 to v3 of PuppetDB on RedHat' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', puppetversion: Puppet.version, operatingsystemrelease: '7.0', kernel: 'Linux', selinux: true, os: { family: 'RedHat', name: 'RedHat', release: { 'full' => '7.0' }, selinux: { 'enabled' => true }, }, } end let(:pre_condition) { 'class { "puppetdb::globals": version => "3.1.1-1.el7", }' } it { is_expected.to contain_exec('Remove puppetdb-terminus metadata for upgrade').with(command: 'rpm -e --justdb puppetdb-terminus') } end context 'when restart_puppet is true' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', puppetversion: Puppet.version, operatingsystemrelease: '7.0', kernel: 'Linux', selinux: true, os: { family: 'RedHat', name: 'RedHat', - release: { 'full' => '7.0' }, + release: { 'full' => '7.0', 'major' => '7' }, selinux: { 'enabled' => true }, }, } end let(:pre_condition) { 'class { "puppetdb": }' } context 'with create_puppet_service_resource as default' do let(:params) do { puppet_service_name: 'puppetserver', restart_puppet: true, } end it { is_expected.to contain_service('puppetserver').with(ensure: 'running') } end context 'with create_puppet_service_resource = true' do let(:params) do { create_puppet_service_resource: true, puppet_service_name: 'puppetserver', restart_puppet: true, } end it { is_expected.to contain_service('puppetserver').with(ensure: 'running') } end context 'with create_puppet_service_resource = false' do # Also setting the various parameters that notify the service to be false. Otherwise this error surfaces: # `Could not find resource 'Service[puppetserver]' for relationship from 'Class[Puppetdb::Master::Puppetdb_conf]'` let(:params) do { create_puppet_service_resource: false, manage_config: false, manage_report_processor: false, manage_routes: false, puppet_service_name: 'puppetserver', restart_puppet: true, } end it { is_expected.not_to contain_service('puppetserver') } end end end diff --git a/spec/unit/classes/server/database_ini_spec.rb b/spec/unit/classes/server/database_ini_spec.rb index 953761b..06f2865 100644 --- a/spec/unit/classes/server/database_ini_spec.rb +++ b/spec/unit/classes/server/database_ini_spec.rb @@ -1,453 +1,478 @@ require 'spec_helper' describe 'puppetdb::server::database', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', puppetversion: Puppet.version, operatingsystemrelease: '7.0', fqdn: 'test.domain.local', } end it { is_expected.to contain_class('puppetdb::server::database') } describe 'when using default values' do it { is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/database.ini') .with( 'ensure' => 'file', 'owner' => 'puppetdb', 'group' => 'puppetdb', 'mode' => '0600', ) } it { is_expected.to contain_ini_setting('puppetdb_psdatabase_username') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'username', 'value' => 'puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_psdatabase_password') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'password', 'value' => 'puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_classname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'classname', 'value' => 'org.postgresql.Driver', ) } it { is_expected.to contain_ini_setting('puppetdb_subprotocol') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'subprotocol', 'value' => 'postgresql', ) } it { is_expected.to contain_ini_setting('puppetdb_subname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'subname', 'value' => '//localhost:5432/puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_gc_interval') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'gc-interval', 'value' => '60', ) } it { is_expected.to contain_ini_setting('puppetdb_node_ttl') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'node-ttl', 'value' => '7d', ) } it { is_expected.to contain_ini_setting('puppetdb_node_purge_ttl') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'node-purge-ttl', 'value' => '14d', ) } it { is_expected.to contain_ini_setting('puppetdb_report_ttl') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'report-ttl', 'value' => '14d', ) } it { is_expected.to contain_ini_setting('puppetdb_log_slow_statements') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'log-slow-statements', 'value' => 10, ) } it { is_expected.to contain_ini_setting('puppetdb_conn_max_age') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'conn-max-age', 'value' => '60', ) } it { is_expected.to contain_ini_setting('puppetdb_conn_keep_alive') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'conn-keep-alive', 'value' => '45', ) } it { is_expected.to contain_ini_setting('puppetdb_conn_lifetime') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'conn-lifetime', 'value' => '0', ) } it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } it { is_expected.to contain_ini_setting('puppetdb_facts_blacklist') .with( 'ensure' => 'absent', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'facts-blacklist', ) } end describe 'when using facts_blacklist' do let(:params) do { 'facts_blacklist' => [ 'one_fact', 'another_fact', ], } end it { is_expected.to contain_ini_setting('puppetdb_facts_blacklist') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'facts-blacklist', 'value' => 'one_fact, another_fact', ) } end describe 'when using a legacy PuppetDB version' do let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } it { is_expected.to contain_ini_setting('puppetdb_psdatabase_username') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'username', 'value' => 'puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_psdatabase_password') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'password', 'value' => 'puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_classname') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'classname', 'value' => 'org.postgresql.Driver', ) } it { is_expected.to contain_ini_setting('puppetdb_subprotocol') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'subprotocol', 'value' => 'postgresql', ) } it { is_expected.to contain_ini_setting('puppetdb_subname') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'subname', 'value' => '//localhost:5432/puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_gc_interval') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'gc-interval', 'value' => '60', ) } it { is_expected.to contain_ini_setting('puppetdb_node_ttl') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'node-ttl', 'value' => '7d', ) } it { is_expected.to contain_ini_setting('puppetdb_node_purge_ttl') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'node-purge-ttl', 'value' => '14d', ) } it { is_expected.to contain_ini_setting('puppetdb_report_ttl') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'report-ttl', 'value' => '14d', ) } it { is_expected.to contain_ini_setting('puppetdb_log_slow_statements') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'log-slow-statements', 'value' => 10, ) } it { is_expected.to contain_ini_setting('puppetdb_conn_max_age') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'conn-max-age', 'value' => '60', ) } it { is_expected.to contain_ini_setting('puppetdb_conn_keep_alive') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'conn-keep-alive', 'value' => '45', ) } it { is_expected.to contain_ini_setting('puppetdb_conn_lifetime') .with( 'ensure' => 'present', 'path' => '/etc/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'conn-lifetime', 'value' => '0', ) } it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } end describe 'when overriding database_path for embedded' do let(:params) do { 'database' => 'embedded', 'database_embedded_path' => '/tmp/foo', } end it { is_expected.to contain_ini_setting('puppetdb_subname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'subname', 'value' => 'file:/tmp/foo;hsqldb.tx=mvcc;sql.syntax_pgs=true', ) } end describe 'when setting max pool size' do context 'on current PuppetDB' do describe 'to a numeric value' do let(:params) do { 'database_max_pool_size' => 12_345, } end it { is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'maximum-pool-size', 'value' => '12345', ) } end describe 'to absent' do let(:params) do { 'database_max_pool_size' => 'absent', } end it { is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') .with( 'ensure' => 'absent', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'maximum-pool-size', ) } end end context 'on PuppetDB 3.2' do let(:pre_condition) { 'class { "puppetdb::globals": version => "3.2.0", }' } describe 'to a numeric value' do let(:params) do { 'database_max_pool_size' => 12_345, } end it { is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'partition-conn-max', 'value' => '12345', ) } end describe 'to absent' do let(:params) do { 'database_max_pool_size' => 'absent', } end it { is_expected.to contain_ini_setting('puppetdb_database_max_pool_size') .with( 'ensure' => 'absent', 'path' => '/etc/puppetlabs/puppetdb/conf.d/database.ini', 'section' => 'database', 'setting' => 'partition-conn-max', ) } end end context 'on a legacy PuppetDB version' do let(:pre_condition) { 'class { "puppetdb::globals": version => "2.2.0", }' } describe 'to a numeric value' do let(:params) do { 'database_max_pool_size' => 12_345, } end it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } end describe 'to absent' do let(:params) do { 'database_max_pool_size' => 'absent', } end it { is_expected.not_to contain_ini_setting('puppetdb_database_max_pool_size') } end end end + + describe 'when using ssl communication' do + let(:params) do + { + 'postgresql_ssl_on' => true, + 'ssl_key_pk8_path' => '/tmp/private_key.pk8', + } + end + + it 'configures subname correctly' do + is_expected.to contain_ini_setting('puppetdb_subname') + .with( + ensure: 'present', + path: '/etc/puppetlabs/puppetdb/conf.d/database.ini', + section: 'database', + setting: 'subname', + value: '//localhost:5432/puppetdb?' \ + 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ + 'sslmode=verify-full&' \ + 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ + 'sslkey=/tmp/private_key.pk8&' \ + 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', + ) + end + end end end diff --git a/spec/unit/classes/server/db_connection_uri_spec.rb b/spec/unit/classes/server/db_connection_uri_spec.rb index 965c04a..1c949e2 100644 --- a/spec/unit/classes/server/db_connection_uri_spec.rb +++ b/spec/unit/classes/server/db_connection_uri_spec.rb @@ -1,31 +1,70 @@ require 'spec_helper' describe 'puppetdb::server::database', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', operatingsystemrelease: '7.0', fqdn: 'test.domain.local', } end describe 'when passing jdbc subparams' do let(:params) do { - 'jdbc_ssl_properties' => '?ssl=true', + jdbc_ssl_properties: '?ssl=true', } end it { is_expected.to contain_ini_setting('puppetdb_subname') .with( - 'section' => 'database', - 'setting' => 'subname', - 'value' => '//localhost:5432/puppetdb?ssl=true', + section: 'database', + setting: 'subname', + value: '//localhost:5432/puppetdb?ssl=true', ) } end + + describe 'when using ssl communication' do + let(:params) do + { + postgresql_ssl_on: true, + ssl_key_pk8_path: '/tmp/private_key.pk8', + } + end + + it 'configures subname correctly' do + is_expected.to contain_ini_setting('puppetdb_subname') + .with( + ensure: 'present', + path: '/etc/puppetlabs/puppetdb/conf.d/database.ini', + section: 'database', + setting: 'subname', + value: '//localhost:5432/puppetdb?' \ + 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ + 'sslmode=verify-full&' \ + 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ + 'sslkey=/tmp/private_key.pk8&' \ + 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', + ) + end + + context 'when setting jdbc_ssl_properties as well' do + let(:params) do + { + jdbc_ssl_properties: '?ssl=true', + postgresql_ssl_on: true, + } + end + + it 'raises an error' do + is_expected.to compile + .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) + end + end + end end end diff --git a/spec/unit/classes/server/db_read_uri_spec.rb b/spec/unit/classes/server/db_read_uri_spec.rb index 9b0fdf7..a273ff9 100644 --- a/spec/unit/classes/server/db_read_uri_spec.rb +++ b/spec/unit/classes/server/db_read_uri_spec.rb @@ -1,32 +1,73 @@ require 'spec_helper' describe 'puppetdb::server::read_database', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', operatingsystemrelease: '7.0', fqdn: 'test.domain.local', } end describe 'when passing jdbc subparams' do let(:params) do { - 'database_host' => 'localhost', - 'jdbc_ssl_properties' => '?ssl=true', + database_host: 'localhost', + jdbc_ssl_properties: '?ssl=true', } end it { is_expected.to contain_ini_setting('puppetdb_read_subname') .with( - 'section' => 'read-database', - 'setting' => 'subname', - 'value' => '//localhost:5432/puppetdb?ssl=true', + section: 'read-database', + setting: 'subname', + value: '//localhost:5432/puppetdb?ssl=true', ) } end + + describe 'when using ssl communication' do + let(:params) do + { + database_host: 'cheery-rime.puppetlabs.net', + postgresql_ssl_on: true, + ssl_key_pk8_path: '/tmp/private_key.pk8', + } + end + + it 'configures subname correctly' do + is_expected.to contain_ini_setting('puppetdb_read_subname') + .with( + ensure: 'present', + path: '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', + section: 'read-database', + setting: 'subname', + value: '//cheery-rime.puppetlabs.net:5432/puppetdb?' \ + 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ + 'sslmode=verify-full&' \ + 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ + 'sslkey=/tmp/private_key.pk8&' \ + 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', + ) + end + + context 'when setting jdbc_ssl_properties as well' do + let(:params) do + { + database_host: 'puppetdb', + jdbc_ssl_properties: '?ssl=true', + postgresql_ssl_on: true, + } + end + + it 'raises an error' do + is_expected.to compile + .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) + end + end + end end end diff --git a/spec/unit/classes/server/read_database_ini_spec.rb b/spec/unit/classes/server/read_database_ini_spec.rb index bd005c4..bfae492 100644 --- a/spec/unit/classes/server/read_database_ini_spec.rb +++ b/spec/unit/classes/server/read_database_ini_spec.rb @@ -1,129 +1,170 @@ require 'spec_helper' describe 'puppetdb::server::read_database', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', puppetversion: Puppet.version, operatingsystemrelease: '7.0', fqdn: 'test.domain.local', } end it { is_expected.to contain_class('puppetdb::server::read_database') } describe 'when using default values' do it { is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/read_database.ini').with('ensure' => 'absent') } end describe 'when using minimum working values' do let(:params) do { 'database_host' => 'puppetdb', } end it { is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/read_database.ini') .with( 'ensure' => 'file', 'owner' => 'puppetdb', 'group' => 'puppetdb', 'mode' => '0600', ) } it { is_expected.to contain_ini_setting('puppetdb_read_database_username') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'username', 'value' => 'puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_read_database_password') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'password', 'value' => 'puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_read_classname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'classname', 'value' => 'org.postgresql.Driver', ) } it { is_expected.to contain_ini_setting('puppetdb_read_subprotocol') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'subprotocol', 'value' => 'postgresql', ) } it { is_expected.to contain_ini_setting('puppetdb_read_subname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'subname', 'value' => '//puppetdb:5432/puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_read_log_slow_statements') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'log-slow-statements', 'value' => 10, ) } it { is_expected.to contain_ini_setting('puppetdb_read_conn_max_age') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'conn-max-age', 'value' => '60', ) } it { is_expected.to contain_ini_setting('puppetdb_read_conn_keep_alive') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'conn-keep-alive', 'value' => '45', ) } it { is_expected.to contain_ini_setting('puppetdb_read_conn_lifetime') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'conn-lifetime', 'value' => '0', ) } + + context 'when using ssl communication' do + let(:params) do + { + database_host: 'puppetdb', + postgresql_ssl_on: true, + ssl_key_pk8_path: '/tmp/private_key.pk8', + } + end + + it 'configures subname correctly' do + is_expected.to contain_ini_setting('puppetdb_read_subname') + .with( + ensure: 'present', + path: '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', + section: 'read-database', + setting: 'subname', + value: '//puppetdb:5432/puppetdb?' \ + 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ + 'sslmode=verify-full&' \ + 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ + 'sslkey=/tmp/private_key.pk8&' \ + 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', + ) + end + + context 'when setting jdbc_ssl_properties as well' do + let(:params) do + { + database_host: 'puppetdb', + jdbc_ssl_properties: '?ssl=true', + postgresql_ssl_on: true, + } + end + + it 'raises an error' do + is_expected.to compile + .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) + end + end + end end end end diff --git a/spec/unit/classes/server_spec.rb b/spec/unit/classes/server_spec.rb index 718dfc8..c3d2d31 100644 --- a/spec/unit/classes/server_spec.rb +++ b/spec/unit/classes/server_spec.rb @@ -1,174 +1,214 @@ require 'spec_helper' describe 'puppetdb::server', type: :class do let :node do 'test.domain.local' end on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do facts.merge(puppetversion: Puppet.version, selinux: true) end pathdir = case facts[:osfamily] when 'Debian' '/etc/default/puppetdb' else '/etc/sysconfig/puppetdb' end describe 'when using default values' do it { is_expected.to contain_class('puppetdb::server') } it { is_expected.to contain_class('puppetdb::server::global') } it { is_expected.to contain_class('puppetdb::server::command_processing') } it { is_expected.to contain_class('puppetdb::server::database') } it { is_expected.to contain_class('puppetdb::server::read_database') } it { is_expected.to contain_class('puppetdb::server::jetty') } it { is_expected.to contain_class('puppetdb::server::puppetdb') } end describe 'when not specifying JAVA_ARGS' do it { is_expected.not_to contain_ini_subsetting('Xms') } end describe 'when specifying JAVA_ARGS' do let(:params) do { 'java_args' => { '-Xms' => '2g', }, } end context 'on redhat PuppetDB' do it { is_expected.to contain_ini_subsetting("'-Xms'") .with( 'ensure' => 'present', 'path' => pathdir.to_s, 'section' => '', 'key_val_separator' => '=', 'setting' => 'JAVA_ARGS', 'subsetting' => '-Xms', 'value' => '2g', ) } end end describe 'when specifying JAVA_ARGS with merge_default_java_args false' do let(:params) do { 'java_args' => { '-Xms' => '2g' }, 'merge_default_java_args' => false, } end context 'on standard PuppetDB' do it { is_expected.to contain_ini_setting('java_args') .with( 'ensure' => 'present', 'path' => pathdir.to_s, 'section' => '', 'setting' => 'JAVA_ARGS', 'value' => '"-Xms2g"', ) } end end context 'when systemd is available' do let(:facts) do facts.merge(systemd: true) end describe 'by default dlo cleanup service is enabled' do it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.service').with_content(%r{/opt/puppetlabs/server/data/puppetdb/stockpile/discard/}) } it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer').with_enable(true).with_active(true) } it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } end describe 'dlo cleanup service can be disabled by params' do let(:params) do { 'automatic_dlo_cleanup' => false, } end it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } end describe 'dlo directory is customized by $vardir to $vardir/stockpile/discard' do let(:params) do { 'vardir' => '/var/custom/path', } end it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.service').with_content(%r{/var/custom/path/stockpile/discard/}) } it { is_expected.to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer').with_enable(true).with_active(true) } it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } end end context 'when systemd is not available' do describe 'by default dlo cleanup is set up with cron' do it { is_expected.to contain_cron('puppetdb-dlo-cleanup').with_ensure('present').with(command: %r{/opt/puppetlabs/server/data/puppetdb/stockpile/discard/}) } it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } end describe 'dlo cleanup can be disabled by params' do let(:params) do { 'automatic_dlo_cleanup' => false, } end it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } it { is_expected.not_to contain_cron('puppetdb-dlo-cleanup') } end describe 'dlo directory is customized by $vardir to $vardir/stockpile/discard' do let(:params) do { 'vardir' => '/var/custom/path', } end it { is_expected.to contain_cron('puppetdb-dlo-cleanup').with_ensure('present').with(command: %r{/var/custom/path/stockpile/discard/}) } it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.service') } it { is_expected.not_to contain_systemd__unit_file('puppetdb-dlo-cleanup.timer') } end end context 'when not managing the database password' do let(:params) do { 'manage_db_password' => false, 'manage_read_db_password' => false, 'read_database_host' => '10.0.0.1', # Make sure the read_database class is enforced. } end describe 'ini_setting entries for the password will not exist' do it { is_expected.to contain_class('puppetdb::server::database').with('manage_db_password' => false) } it { is_expected.to contain_class('puppetdb::server::read_database').with('manage_db_password' => false) } it { is_expected.not_to contain_ini__setting('puppetdb_psdatabase_password') } it { is_expected.not_to contain_ini__setting('puppetdb_read_database_password') } end end + + context 'when managing ssl communication' do + let(:params) do + { + postgresql_ssl_on: true, + } + end + let(:key_path) { '/etc/puppetlabs/puppetdb/ssl/private.pem' } + let(:key_pk8_path) { '/etc/puppetlabs/puppetdb/ssl/private.pk8' } + + context 'ini_setting entries for the ssl configuration will exist' do + it { is_expected.to contain_class('puppetdb::server::database').with('postgresql_ssl_on' => true) } + it { is_expected.to contain_class('puppetdb::server::database').with(ssl_key_pk8_path: key_pk8_path) } + + it { is_expected.to contain_class('puppetdb::server::read_database').with('postgresql_ssl_on' => true) } + it { is_expected.to contain_class('puppetdb::server::read_database').with(ssl_key_pk8_path: key_pk8_path) } + end + + context 'private key file is converted from .pem to .pk8 format' do + it 'runs exec command' do + is_expected.to contain_exec(key_pk8_path) + .with( + path: ['/opt/puppetlabs/puppet/bin', facts[:path]], + command: "openssl pkcs8 -topk8 -inform PEM -outform DER -in #{key_path} -out #{key_pk8_path} -nocrypt", + onlyif: "test ! -e '#{key_pk8_path}' -o '#{key_pk8_path}' -ot '#{key_path}'", + before: "File[#{key_pk8_path}]", + ) + end + + it 'contains file private.pk8' do + is_expected.to contain_file('/etc/puppetlabs/puppetdb/ssl/private.pk8') + .with( + ensure: 'present', + owner: 'puppetdb', + group: 'puppetdb', + mode: '0600', + ) + end + end + end end end end