From ef01b7da9c613bacd652b0550590f60cc511ef16 Mon Sep 17 00:00:00 2001 From: Josh Partlow Date: Mon, 2 Dec 2024 23:26:56 +0000 Subject: [PATCH 1/3] (PE-39352) Update backup/restore plans for hac database PE 2023.7.0 added the host-action-collector service and the backup/restore plans need to be made aware of the pe-hac database. This patch adds a version test, best on the addition of pe_version check of /opt/puppetlabs/server/pe_build in the peadm::get_peadm_config task. If >= 2023.7, then pe-hac is added to the defaults returned by the various recover_opts functions that define which resource backup/restore should wrangle. The patch does not attempt to version test the user's custom override hash of selections, on the assumption that they know, or should be allowed to specify whatever is needed. If pe_version is not found (damaged cluster, missing from peadm_config.json), the patch defaults to assuming earliest version, which will skip pe-hac. This favors the plans running without error at the cost of possibly missing pe-hac in a newer installation. Alternately, we could reverse this and incur failures in damaged older clusters requiring use of $custom to work around. Finally there is an edge case it does not address which is the case of newer pe versions with pe-hac restoring tarballs that were intended to include all databases, but which were created with peadm predating this patch. These will fail the pg-restore pe-hac commands, since pe-hac won't be in the backup, and again require use of $custom to work around. --- .../amend_recovery_defaults_by_pe_version.pp | 18 +++ functions/migration_opts_default.pp | 7 +- functions/recovery_opts_all.pp | 7 +- functions/recovery_opts_default.pp | 7 +- ...validated_pe_version_for_backup_restore.pp | 22 ++++ plans/backup.pp | 10 +- plans/restore.pp | 14 +- spec/fixtures/peadm_config.json | 1 + spec/fixtures/peadm_config.no_pe_version.json | 3 + ...nd_recovery_defaults_by_pe_version_spec.rb | 15 +++ spec/functions/migration_opts_default_spec.rb | 34 +++++ spec/functions/recovery_opts_all_spec.rb | 34 +++++ spec/functions/recovery_opts_default_spec.rb | 34 +++++ spec/plans/backup_spec.rb | 93 +++++++++---- spec/plans/restore_spec.rb | 124 ++++++++++++++++-- types/recovery_opts.pp | 1 + 16 files changed, 372 insertions(+), 52 deletions(-) create mode 100644 functions/amend_recovery_defaults_by_pe_version.pp create mode 100644 functions/validated_pe_version_for_backup_restore.pp create mode 100644 spec/fixtures/peadm_config.no_pe_version.json create mode 100644 spec/functions/amend_recovery_defaults_by_pe_version_spec.rb create mode 100644 spec/functions/migration_opts_default_spec.rb create mode 100644 spec/functions/recovery_opts_all_spec.rb create mode 100644 spec/functions/recovery_opts_default_spec.rb diff --git a/functions/amend_recovery_defaults_by_pe_version.pp b/functions/amend_recovery_defaults_by_pe_version.pp new file mode 100644 index 00000000..881fd0c8 --- /dev/null +++ b/functions/amend_recovery_defaults_by_pe_version.pp @@ -0,0 +1,18 @@ +function peadm::amend_recovery_defaults_by_pe_version ( + Hash $base_opts, + Peadm::Pe_version $pe_version, + Boolean $opt_value, +) { + # work around puppet-lint check_unquoted_string_in_case + $semverrange = SemVerRange('>= 2023.7') + case $pe_version { + $semverrange: { + $base_opts + { + 'hac' => $opt_value, + } + } + default: { + $base_opts + } + } +} diff --git a/functions/migration_opts_default.pp b/functions/migration_opts_default.pp index 99b57e55..2b770a40 100644 --- a/functions/migration_opts_default.pp +++ b/functions/migration_opts_default.pp @@ -1,5 +1,7 @@ -function peadm::migration_opts_default () { - { +function peadm::migration_opts_default ( + Peadm::Pe_version $pe_version, +) { + $base_opts = { 'activity' => true, 'ca' => true, 'classifier' => true, @@ -9,4 +11,5 @@ function peadm::migration_opts_default () { 'puppetdb' => true, 'rbac' => true, } + peadm::amend_recovery_defaults_by_pe_version($base_opts, $pe_version, true) } diff --git a/functions/recovery_opts_all.pp b/functions/recovery_opts_all.pp index e738ab5e..6f6f59c0 100644 --- a/functions/recovery_opts_all.pp +++ b/functions/recovery_opts_all.pp @@ -1,5 +1,7 @@ -function peadm::recovery_opts_all () { - { +function peadm::recovery_opts_all ( + Peadm::Pe_version $pe_version, +) { + $base_opts = { 'activity' => true, 'ca' => true, 'classifier' => true, @@ -9,4 +11,5 @@ function peadm::recovery_opts_all () { 'puppetdb' => true, 'rbac' => true, } + peadm::amend_recovery_defaults_by_pe_version($base_opts, $pe_version, true) } diff --git a/functions/recovery_opts_default.pp b/functions/recovery_opts_default.pp index 5e4b2f4d..5c9bf57c 100644 --- a/functions/recovery_opts_default.pp +++ b/functions/recovery_opts_default.pp @@ -1,5 +1,7 @@ -function peadm::recovery_opts_default () { - { +function peadm::recovery_opts_default ( + Peadm::Pe_version $pe_version, +) { + $base_opts = { 'activity' => false, 'ca' => true, 'classifier' => false, @@ -9,4 +11,5 @@ function peadm::recovery_opts_default () { 'puppetdb' => true, 'rbac' => false, } + peadm::amend_recovery_defaults_by_pe_version($base_opts, $pe_version, false) } diff --git a/functions/validated_pe_version_for_backup_restore.pp b/functions/validated_pe_version_for_backup_restore.pp new file mode 100644 index 00000000..c84677de --- /dev/null +++ b/functions/validated_pe_version_for_backup_restore.pp @@ -0,0 +1,22 @@ +# Verify that *pe_version* string is a valid SemVer. +# If not, warn, and return "0.0.0" as a permissive default. +function peadm::validated_pe_version_for_backup_restore( + Optional[String] $pe_version, +) { + # work around puppet-lint check_unquoted_string_in_case + $semverrange = SemVerRange('>=0.0.0') + case $pe_version { + # Validate that the value is a SemVer value. + $semverrange: { + $pe_version + } + default: { + $msg = @("WARN") + WARNING: Retrieved a missing or unparseable PE version of '${pe_version}'. + The host_action_collector database will be skipped from defaults. + |-WARN + out::message($msg) + '0.0.0' + } + } +} diff --git a/plans/backup.pp b/plans/backup.pp index 80835eb0..cb15f77e 100644 --- a/plans/backup.pp +++ b/plans/backup.pp @@ -35,10 +35,12 @@ getvar('cluster.params.compiler_hosts'), ) + $pe_version = peadm::validated_pe_version_for_backup_restore(getvar('cluster.pe_version')) + $recovery_opts = $backup_type? { - 'recovery' => peadm::recovery_opts_default(), - 'migration' => peadm::migration_opts_default(), - 'custom' => peadm::recovery_opts_all() + $backup, + 'recovery' => peadm::recovery_opts_default($pe_version), + 'migration' => peadm::migration_opts_default($pe_version), + 'custom' => peadm::recovery_opts_all($pe_version) + $backup, } $timestamp = Timestamp.new().strftime('%Y-%m-%dT%H%M%SZ') @@ -55,6 +57,8 @@ 'activity' => $primary_target, 'rbac' => $primary_target, 'puppetdb' => $puppetdb_postgresql_target, + # (host-action-collector db will be filtered for pe version by recovery_opts) + 'hac' => $primary_target, }.filter |$key,$_| { $recovery_opts[$key] == true } diff --git a/plans/restore.pp b/plans/restore.pp index 453bf8e5..518d08c0 100644 --- a/plans/restore.pp +++ b/plans/restore.pp @@ -34,7 +34,7 @@ # try to load the cluster configuration by running peadm::get_peadm_config, but allow for errors to happen $_cluster = run_task('peadm::get_peadm_config', $targets, { '_catch_errors' => true }).first.value - if $_cluster == undef or getvar('_cluster.params') == undef { + if $_cluster == undef or getvar('_cluster.params') == undef or getvar('_cluster.pe_version') == undef { # failed to get cluster config, load from backup out::message('Failed to get cluster configuration, loading from backup...') $result = download_file("${recovery_directory}/peadm/peadm_config.json", 'peadm_config.json', $targets).first.value @@ -59,11 +59,13 @@ getvar('cluster.params.compiler_hosts'), ) + $pe_version = peadm::validated_pe_version_for_backup_restore(getvar('cluster.pe_version')) + $recovery_opts = $restore_type? { - 'recovery' => peadm::recovery_opts_default(), + 'recovery' => peadm::recovery_opts_default($pe_version), 'recovery-db' => { 'puppetdb' => true, }, - 'migration' => peadm::migration_opts_default(), - 'custom' => peadm::recovery_opts_all() + $restore, + 'migration' => peadm::migration_opts_default($pe_version), + 'custom' => peadm::recovery_opts_all($pe_version) + $restore, } $primary_target = peadm::get_targets(getvar('cluster.params.primary_host'), 1) @@ -97,6 +99,8 @@ 'activity' => [$primary_target], 'rbac' => [$primary_target], 'puppetdb' => $puppetdb_postgresql_targets, + # (host-action-collector db will be filtered for pe version by recovery_opts) + 'hac' => $primary_target, }.filter |$key,$_| { $recovery_opts[$key] == true } @@ -203,7 +207,7 @@ if getvar('recovery_opts.orchestrator') { out::message('# Restoring orchestrator secret keys') run_command(@("CMD"/L), $primary_target) - cp -rp ${shellquote($recovery_directory)}/orchestrator/secrets/* /etc/puppetlabs/orchestration-services/conf.d/secrets/ + cp -rp ${shellquote($recovery_directory)}/orchestrator/secrets/* /etc/puppetlabs/orchestration-services/conf.d/secrets/ | CMD } # lint:endignore diff --git a/spec/fixtures/peadm_config.json b/spec/fixtures/peadm_config.json index cbd5db76..de2c0a5a 100644 --- a/spec/fixtures/peadm_config.json +++ b/spec/fixtures/peadm_config.json @@ -1,3 +1,4 @@ { + "pe_version" : "2023.7.0", "params": { "primary_host": "primary", "primary_postgresql_host": "postgres" } } diff --git a/spec/fixtures/peadm_config.no_pe_version.json b/spec/fixtures/peadm_config.no_pe_version.json new file mode 100644 index 00000000..cbd5db76 --- /dev/null +++ b/spec/fixtures/peadm_config.no_pe_version.json @@ -0,0 +1,3 @@ +{ + "params": { "primary_host": "primary", "primary_postgresql_host": "postgres" } +} diff --git a/spec/functions/amend_recovery_defaults_by_pe_version_spec.rb b/spec/functions/amend_recovery_defaults_by_pe_version_spec.rb new file mode 100644 index 00000000..6bd5d418 --- /dev/null +++ b/spec/functions/amend_recovery_defaults_by_pe_version_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe 'peadm::amend_recovery_defaults_by_pe_version' do + it 'just returns the base opts if version < 2023.7' do + is_expected.to run.with_params({}, '2023.6.0', true).and_return({}) + end + + it 'adds hac if version >= 2023.7' do + is_expected.to run.with_params({}, '2023.7.0', true).and_return({ 'hac' => true }) + end + + it 'adds hac false based on opt_value' do + is_expected.to run.with_params({}, '2023.7.0', false).and_return({ 'hac' => false }) + end +end diff --git a/spec/functions/migration_opts_default_spec.rb b/spec/functions/migration_opts_default_spec.rb new file mode 100644 index 00000000..066b3443 --- /dev/null +++ b/spec/functions/migration_opts_default_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'peadm::migration_opts_default' do + it 'returns pre 2023.7 defaults' do + is_expected.to run.with_params('2023.6.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => false, + 'config' => false, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + }, + ) + end + + it 'returns 2023.7+ defaults with hac' do + is_expected.to run.with_params('2023.7.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => false, + 'config' => false, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + 'hac' => true, + }, + ) + end +end diff --git a/spec/functions/recovery_opts_all_spec.rb b/spec/functions/recovery_opts_all_spec.rb new file mode 100644 index 00000000..ca4f5547 --- /dev/null +++ b/spec/functions/recovery_opts_all_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'peadm::recovery_opts_all' do + it 'returns pre 2023.7 defaults' do + is_expected.to run.with_params('2023.6.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => true, + 'config' => true, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + }, + ) + end + + it 'returns 2023.7+ defaults with hac' do + is_expected.to run.with_params('2023.7.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => true, + 'config' => true, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + 'hac' => true, + }, + ) + end +end diff --git a/spec/functions/recovery_opts_default_spec.rb b/spec/functions/recovery_opts_default_spec.rb new file mode 100644 index 00000000..7e5b0aba --- /dev/null +++ b/spec/functions/recovery_opts_default_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'peadm::recovery_opts_default' do + it 'returns pre 2023.7 defaults' do + is_expected.to run.with_params('2023.6.0').and_return( + { + 'activity' => false, + 'ca' => true, + 'classifier' => false, + 'code' => true, + 'config' => true, + 'orchestrator' => false, + 'puppetdb' => true, + 'rbac' => false, + }, + ) + end + + it 'returns 2023.7+ defaults with hac' do + is_expected.to run.with_params('2023.7.0').and_return( + { + 'activity' => false, + 'ca' => true, + 'classifier' => false, + 'code' => true, + 'config' => true, + 'orchestrator' => false, + 'puppetdb' => true, + 'rbac' => false, + 'hac' => false, + }, + ) + end +end diff --git a/spec/plans/backup_spec.rb b/spec/plans/backup_spec.rb index d6b2ff75..7f948cc2 100644 --- a/spec/plans/backup_spec.rb +++ b/spec/plans/backup_spec.rb @@ -20,6 +20,7 @@ 'orchestrator' => false, 'puppetdb' => false, 'rbac' => false, + 'hac' => false, } } end @@ -30,6 +31,16 @@ 'backup' => {} # set all to true } end + let(:pe_version) { '2023.7.0' } + let(:cluster) do + { + 'pe_version' => pe_version, + 'params' => { + 'primary_host' => 'primary', + 'primary_postgresql_host' => 'postgres', + } + } + end before(:each) do # define a zero timestamp @@ -40,12 +51,7 @@ allow_apply - expect_task('peadm::get_peadm_config').always_return({ - 'params' => { - 'primary_host' => 'primary', - 'primary_postgresql_host' => 'postgres', - } - }) + expect_task('peadm::get_peadm_config').always_return(cluster) end it 'runs with backup type recovery' do @@ -89,27 +95,64 @@ expect(run_plan('peadm::backup', classifier_only)).to be_ok end - it 'runs with backup type custom, all backup params set to true' do - expect_task('peadm::backup_classification').with_params({ 'directory' => '/tmp/pe-backup-1970-01-01T000000Z/classifier' }) + shared_context('all 2023.6.0 backups') do + before(:each) do + expect_task('peadm::backup_classification').with_params({ 'directory' => '/tmp/pe-backup-1970-01-01T000000Z/classifier' }) + + expect_out_message.with_params('# Backing up classification') + expect_out_message.with_params('# Backing up database pe-orchestrator') + expect_out_message.with_params('# Backing up database pe-activity') + expect_out_message.with_params('# Backing up database pe-rbac') + expect_out_message.with_params('# Backing up database pe-puppetdb') + + expect_command("/opt/puppetlabs/bin/puppet-backup create --dir=/tmp/pe-backup-1970-01-01T000000Z/ca --scope=certs\n") + expect_command("/opt/puppetlabs/bin/puppet-backup create --dir=/tmp/pe-backup-1970-01-01T000000Z/code --scope=code\n") + expect_command('chown pe-postgres /tmp/pe-backup-1970-01-01T000000Z/config') + expect_command("/opt/puppetlabs/bin/puppet-backup create --dir=/tmp/pe-backup-1970-01-01T000000Z/config --scope=config\n") + expect_command("test -f /etc/puppetlabs/console-services/conf.d/secrets/keys.json && cp -rp /etc/puppetlabs/console-services/conf.d/secrets /tmp/pe-backup-1970-01-01T000000Z/rbac/ || echo secret ldap key doesnt exist\n") + expect_command("cp -rp /etc/puppetlabs/orchestration-services/conf.d/secrets /tmp/pe-backup-1970-01-01T000000Z/orchestrator/\n") + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/orchestrator/pe-orchestrator.dump.d "sslmode=verify-ca host=primary user=pe-orchestrator sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-orchestrator"' + "\n") + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/activity/pe-activity.dump.d "sslmode=verify-ca host=primary user=pe-activity sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-activity"' + "\n") + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/rbac/pe-rbac.dump.d "sslmode=verify-ca host=primary user=pe-rbac sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-rbac"' + "\n") + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/puppetdb/pe-puppetdb.dump.d "sslmode=verify-ca host=postgres user=pe-puppetdb sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-puppetdb"' + "\n") + expect_command('umask 0077 && cd /tmp && tar -czf /tmp/pe-backup-1970-01-01T000000Z.tar.gz pe-backup-1970-01-01T000000Z && rm -rf /tmp/pe-backup-1970-01-01T000000Z' + "\n") + end + end - expect_out_message.with_params('# Backing up classification') - expect_out_message.with_params('# Backing up database pe-orchestrator') - expect_out_message.with_params('# Backing up database pe-activity') - expect_out_message.with_params('# Backing up database pe-rbac') - expect_out_message.with_params('# Backing up database pe-puppetdb') + context '>= 2023.7.0' do + include_context('all 2023.6.0 backups') - expect_command("/opt/puppetlabs/bin/puppet-backup create --dir=/tmp/pe-backup-1970-01-01T000000Z/ca --scope=certs\n") - expect_command("/opt/puppetlabs/bin/puppet-backup create --dir=/tmp/pe-backup-1970-01-01T000000Z/code --scope=code\n") - expect_command('chown pe-postgres /tmp/pe-backup-1970-01-01T000000Z/config') - expect_command("/opt/puppetlabs/bin/puppet-backup create --dir=/tmp/pe-backup-1970-01-01T000000Z/config --scope=config\n") - expect_command("test -f /etc/puppetlabs/console-services/conf.d/secrets/keys.json && cp -rp /etc/puppetlabs/console-services/conf.d/secrets /tmp/pe-backup-1970-01-01T000000Z/rbac/ || echo secret ldap key doesnt exist\n") - expect_command("cp -rp /etc/puppetlabs/orchestration-services/conf.d/secrets /tmp/pe-backup-1970-01-01T000000Z/orchestrator/\n") - expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/orchestrator/pe-orchestrator.dump.d "sslmode=verify-ca host=primary user=pe-orchestrator sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-orchestrator"' + "\n") - expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/activity/pe-activity.dump.d "sslmode=verify-ca host=primary user=pe-activity sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-activity"' + "\n") - expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/rbac/pe-rbac.dump.d "sslmode=verify-ca host=primary user=pe-rbac sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-rbac"' + "\n") - expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/puppetdb/pe-puppetdb.dump.d "sslmode=verify-ca host=postgres user=pe-puppetdb sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-puppetdb"' + "\n") - expect_command('umask 0077 && cd /tmp && tar -czf /tmp/pe-backup-1970-01-01T000000Z.tar.gz pe-backup-1970-01-01T000000Z && rm -rf /tmp/pe-backup-1970-01-01T000000Z' + "\n") + it 'runs with backup type custom, all backup params set to true' do + expect_out_message.with_params('# Backing up database pe-hac') + + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/hac/pe-hac.dump.d "sslmode=verify-ca host=primary user=pe-hac sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-hac"' + "\n") + + expect(run_plan('peadm::backup', all_backup_options)).to be_ok + end + end + + context '< 2023.7.0' do + let(:pe_version) { '2023.6.0' } + + include_context('all 2023.6.0 backups') + + it 'ignores hac' do + expect(run_plan('peadm::backup', all_backup_options)).to be_ok + end + end + + context 'pe_version unknown' do + let(:pe_version) { nil } + + include_context('all 2023.6.0 backups') + + it 'warns that hac is ignored' do + expect_out_message.with_params(<<~MSG.strip) + WARNING: Retrieved a missing or unparseable PE version of ''. + The host_action_collector database will be skipped from defaults. + MSG - expect(run_plan('peadm::backup', all_backup_options)).to be_ok + expect(run_plan('peadm::backup', all_backup_options)).to be_ok + end end end diff --git a/spec/plans/restore_spec.rb b/spec/plans/restore_spec.rb index 52754b8e..81359b41 100644 --- a/spec/plans/restore_spec.rb +++ b/spec/plans/restore_spec.rb @@ -24,6 +24,13 @@ 'restore_type' => 'recovery-db' } end + let(:all_recovery_options) do + { + 'targets' => 'primary', + 'input_file' => backup_tarball, + 'restore_type' => 'custom', # defaults to all + } + end let(:classifier_only_params) do { 'targets' => 'primary', @@ -42,7 +49,16 @@ } end - let(:cluster) { { 'params' => { 'primary_host' => 'primary', 'primary_postgresql_host' => 'postgres' } } } + let(:pe_version) { '2023.7.0' } + let(:cluster) do + { + 'pe_version' => pe_version, + 'params' => { + 'primary_host' => 'primary', + 'primary_postgresql_host' => 'postgres', + }, + } + end before(:each) do allow_apply @@ -57,20 +73,26 @@ expect_task('peadm::get_peadm_config').always_return(cluster) end + def expect_restore_for_db(name, server) + database = "pe-#{name}" + expect_out_message.with_params("# Restoring database #{database}") + + expect_command(%(su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql --tuples-only -d '#{database}' -c 'DROP SCHEMA IF EXISTS pglogical CASCADE;'"\n)).be_called_times(2) + expect_command(%(su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d '#{database}' -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"\n)) + expect_command(%(su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d '#{database}' -c 'ALTER USER \\"#{database}\\" WITH SUPERUSER;'"\n)) + expect_command(%(/opt/puppetlabs/server/bin/pg_restore -j 4 -d "sslmode=verify-ca host=#{server} sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=#{database} user=#{database}" -Fd /input/file/#{name}/#{database}.dump.d\n)) + expect_command(%(su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d '#{database}' -c 'ALTER USER \\"#{database}\\" WITH NOSUPERUSER;'"\n)) + expect_command(%(su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d '#{database}' -c 'DROP EXTENSION IF EXISTS pglogical CASCADE;'"\n)) + end + it 'runs with recovery params', valid_cluster: true do - expect_out_message.with_params('# Restoring database pe-puppetdb') expect_out_message.with_params('# Restoring ca, certs, code and config for recovery') expect_command("umask 0077 && cd /input && tar -xzf /input/file.tar.gz\n") expect_command("/opt/puppetlabs/bin/puppet-backup restore --scope=certs,code,config --tempdir=/input/file --force /input/file/recovery/pe_backup-*tgz\n") expect_command("systemctl stop pe-console-services pe-nginx pxp-agent pe-puppetserver pe-orchestration-services puppet pe-puppetdb\n") expect_command("test -f /input/file/rbac/keys.json && cp -rp /input/file/keys.json /etc/puppetlabs/console-services/conf.d/secrets/ || echo secret ldap key doesnt exist\n") - expect_command("su - pe-postgres -s /bin/bash -c \"/opt/puppetlabs/server/bin/psql --tuples-only -d 'pe-puppetdb' -c 'DROP SCHEMA IF EXISTS pglogical CASCADE;'\"\n").be_called_times(2) - expect_command("su - pe-postgres -s /bin/bash -c \"/opt/puppetlabs/server/bin/psql -d 'pe-puppetdb' -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'\"\n") - expect_command('su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d \'pe-puppetdb\' -c \'ALTER USER \\"pe-puppetdb\\" WITH SUPERUSER;\'"' + "\n") - expect_command('/opt/puppetlabs/server/bin/pg_restore -j 4 -d "sslmode=verify-ca host=postgres sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-puppetdb user=pe-puppetdb" -Fd /input/file/puppetdb/pe-puppetdb.dump.d' + "\n") - expect_command('su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d \'pe-puppetdb\' -c \'ALTER USER \\"pe-puppetdb\\" WITH NOSUPERUSER;\'"' + "\n") - expect_command('su - pe-postgres -s /bin/bash -c "/opt/puppetlabs/server/bin/psql -d \'pe-puppetdb\' -c \'DROP EXTENSION IF EXISTS pglogical CASCADE;\'"' + "\n") + expect_restore_for_db('puppetdb', 'postgres') expect_command("/opt/puppetlabs/bin/puppet-infrastructure configure --no-recover\n") expect(run_plan('peadm::restore', recovery_params)).to be_ok @@ -104,21 +126,97 @@ expect(run_plan('peadm::restore', classifier_only_params)).to be_ok end - it 'runs with recovery params, no valid cluster', valid_cluster: false do - allow_any_command - + def expect_peadm_config_fallback(backup_dir, file) # simulate a failure to get the cluster configuration expect_task('peadm::get_peadm_config').always_return({}) expect_out_message.with_params('Failed to get cluster configuration, loading from backup...') - # download mocked to return the path to the file fixtures/peadm_config.json + # download mocked to return the path to a fixtures file expect_download("#{backup_dir}/peadm/peadm_config.json").return do |targets, _source, _destination, _params| results = targets.map do |target| - Bolt::Result.new(target, value: { 'path' => File.expand_path(File.join(fixtures, 'peadm_config.json')) }) + Bolt::Result.new(target, value: { 'path' => File.expand_path(File.join(fixtures, file)) }) end Bolt::ResultSet.new(results) end + end + + it 'runs with recovery params, no valid cluster', valid_cluster: false do + allow_any_command + + expect_peadm_config_fallback(backup_dir, 'peadm_config.json') + expect(run_plan('peadm::restore', recovery_params)).to be_ok end + + shared_context('all 2023.6.0 backups') do + before(:each) do + expect_out_message.with_params('# Restoring ca and ssl certificates') + expect_out_message.with_params('# Restoring code') + expect_out_message.with_params('# Restoring config') + + expect_command("umask 0077 && cd /input && tar -xzf /input/file.tar.gz\n") + expect_task('peadm::restore_classification').with_params( + { + 'classification_file' => "#{backup_dir}/classifier/classification_backup.json", + }, + ) + expect_command("/opt/puppetlabs/bin/puppet-backup restore --scope=certs --tempdir=/input/file --force /input/file/ca/pe_backup-*tgz\n") + expect_command("/opt/puppetlabs/bin/puppet-backup restore --scope=code --tempdir=/input/file --force /input/file/code/pe_backup-*tgz\n") + expect_command("/opt/puppetlabs/bin/puppet-backup restore --scope=config --tempdir=/input/file --force /input/file/config/pe_backup-*tgz\n") + expect_command("systemctl stop pe-console-services pe-nginx pxp-agent pe-puppetserver pe-orchestration-services puppet pe-puppetdb\n") + expect_command("cp -rp /input/file/orchestrator/secrets/* /etc/puppetlabs/orchestration-services/conf.d/secrets/\n") + expect_command("test -f /input/file/rbac/keys.json && cp -rp /input/file/keys.json /etc/puppetlabs/console-services/conf.d/secrets/ || echo secret ldap key doesnt exist\n") + expect_restore_for_db('activity', 'primary') + expect_restore_for_db('orchestrator', 'primary') + expect_restore_for_db('puppetdb', 'postgres') + expect_restore_for_db('rbac', 'primary') + expect_command("/opt/puppetlabs/bin/puppet-infrastructure configure --no-recover\n") + end + end + + context '>= 2023.7.0' do + include_context('all 2023.6.0 backups') + + it 'runs with backup type custom, all params set to true', valid_cluster: true do + expect_restore_for_db('hac', 'primary') + + expect(run_plan('peadm::restore', all_recovery_options)).to be_ok + end + end + + context '< 2023.7.0' do + let(:pe_version) { '2023.6.0' } + + include_context('all 2023.6.0 backups') + + it 'ignores hac', valid_cluster: true do + expect(run_plan('peadm::restore', all_recovery_options)).to be_ok + end + end + + # restoring an older backup that does not have the pe_version in it + context 'no valid cluster, pe_version missing from recovery params (older backup)' do + let(:cluster) do + { + 'params' => { + 'primary_host' => 'primary', + 'primary_postgresql_host' => 'postgres', + }, + } + end + + include_context('all 2023.6.0 backups') + + it 'warns that hac is ignored', valid_cluster: false do + expect_out_message.with_params(<<~MSG.strip) + WARNING: Retrieved a missing or unparseable PE version of ''. + The host_action_collector database will be skipped from defaults. + MSG + + expect_peadm_config_fallback(backup_dir, 'peadm_config.no_pe_version.json') + + expect(run_plan('peadm::restore', all_recovery_options)).to be_ok + end + end end diff --git a/types/recovery_opts.pp b/types/recovery_opts.pp index eb392752..1c20db3f 100644 --- a/types/recovery_opts.pp +++ b/types/recovery_opts.pp @@ -7,4 +7,5 @@ 'orchestrator' => Optional[Boolean], 'puppetdb' => Optional[Boolean], 'rbac' => Optional[Boolean], + 'hac' => Optional[Boolean], }] From 0e9b5678644436dc90f32218e7d262c827e38d4f Mon Sep 17 00:00:00 2001 From: Josh Partlow Date: Thu, 12 Dec 2024 21:01:34 +0000 Subject: [PATCH 2/3] (PE-39352) Adding patching service database to backup/restore plans 2025.0 adds the pe-patching-service and pe-patching database. This commit updates the recovery metadata to account for the pe-patching database in 2025.0+ versions. --- .../amend_recovery_defaults_by_pe_version.pp | 11 +++++-- ...validated_pe_version_for_backup_restore.pp | 3 +- plans/backup.pp | 2 ++ plans/restore.pp | 2 ++ spec/functions/migration_opts_default_spec.rb | 17 ++++++++++ spec/functions/recovery_opts_all_spec.rb | 33 +++++++++++++++++++ spec/functions/recovery_opts_default_spec.rb | 17 ++++++++++ spec/plans/backup_spec.rb | 24 ++++++++++++-- spec/plans/restore_spec.rb | 22 +++++++++++-- types/recovery_opts.pp | 1 + 10 files changed, 125 insertions(+), 7 deletions(-) diff --git a/functions/amend_recovery_defaults_by_pe_version.pp b/functions/amend_recovery_defaults_by_pe_version.pp index 881fd0c8..d6de2cb1 100644 --- a/functions/amend_recovery_defaults_by_pe_version.pp +++ b/functions/amend_recovery_defaults_by_pe_version.pp @@ -4,9 +4,16 @@ function peadm::amend_recovery_defaults_by_pe_version ( Boolean $opt_value, ) { # work around puppet-lint check_unquoted_string_in_case - $semverrange = SemVerRange('>= 2023.7') + $pe_2025_0 = SemVerRange('>= 2025.0') + $pe_2023_7 = SemVerRange('>= 2023.7') case $pe_version { - $semverrange: { + $pe_2025_0: { + $base_opts + { + 'hac' => $opt_value, + 'patching' => $opt_value, + } + } + $pe_2023_7: { $base_opts + { 'hac' => $opt_value, } diff --git a/functions/validated_pe_version_for_backup_restore.pp b/functions/validated_pe_version_for_backup_restore.pp index c84677de..73efc781 100644 --- a/functions/validated_pe_version_for_backup_restore.pp +++ b/functions/validated_pe_version_for_backup_restore.pp @@ -13,7 +13,8 @@ function peadm::validated_pe_version_for_backup_restore( default: { $msg = @("WARN") WARNING: Retrieved a missing or unparseable PE version of '${pe_version}'. - The host_action_collector database will be skipped from defaults. + Newer service databases released in 2023.7+ will be skipped from defaults. + (host-action-collector, patching) |-WARN out::message($msg) '0.0.0' diff --git a/plans/backup.pp b/plans/backup.pp index cb15f77e..4e3e15a6 100644 --- a/plans/backup.pp +++ b/plans/backup.pp @@ -59,6 +59,8 @@ 'puppetdb' => $puppetdb_postgresql_target, # (host-action-collector db will be filtered for pe version by recovery_opts) 'hac' => $primary_target, + # (patching db will be filtered for pe version by recovery_opts) + 'patching' => $primary_target, }.filter |$key,$_| { $recovery_opts[$key] == true } diff --git a/plans/restore.pp b/plans/restore.pp index 518d08c0..8e8975f6 100644 --- a/plans/restore.pp +++ b/plans/restore.pp @@ -101,6 +101,8 @@ 'puppetdb' => $puppetdb_postgresql_targets, # (host-action-collector db will be filtered for pe version by recovery_opts) 'hac' => $primary_target, + # (patching db will be filtered for pe version by recovery_opts) + 'patching' => $primary_target, }.filter |$key,$_| { $recovery_opts[$key] == true } diff --git a/spec/functions/migration_opts_default_spec.rb b/spec/functions/migration_opts_default_spec.rb index 066b3443..c9df7743 100644 --- a/spec/functions/migration_opts_default_spec.rb +++ b/spec/functions/migration_opts_default_spec.rb @@ -31,4 +31,21 @@ }, ) end + + it 'returns 2025.0+ defaults with hac and patching' do + is_expected.to run.with_params('2025.0.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => false, + 'config' => false, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + 'hac' => true, + 'patching' => true, + }, + ) + end end diff --git a/spec/functions/recovery_opts_all_spec.rb b/spec/functions/recovery_opts_all_spec.rb index ca4f5547..7d12ebda 100644 --- a/spec/functions/recovery_opts_all_spec.rb +++ b/spec/functions/recovery_opts_all_spec.rb @@ -31,4 +31,37 @@ }, ) end + + it 'returns 2023.7+ defaults with hac if >2023.7 <2025.0' do + is_expected.to run.with_params('2024.9999.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => true, + 'config' => true, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + 'hac' => true, + }, + ) + end + + it 'returns 2025.0+ defaults with hac and patching' do + is_expected.to run.with_params('2025.0.0').and_return( + { + 'activity' => true, + 'ca' => true, + 'classifier' => true, + 'code' => true, + 'config' => true, + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + 'hac' => true, + 'patching' => true, + }, + ) + end end diff --git a/spec/functions/recovery_opts_default_spec.rb b/spec/functions/recovery_opts_default_spec.rb index 7e5b0aba..7a775456 100644 --- a/spec/functions/recovery_opts_default_spec.rb +++ b/spec/functions/recovery_opts_default_spec.rb @@ -31,4 +31,21 @@ }, ) end + + it 'returns 2025.0+ defaults with hac and patching' do + is_expected.to run.with_params('2025.0.0').and_return( + { + 'activity' => false, + 'ca' => true, + 'classifier' => false, + 'code' => true, + 'config' => true, + 'orchestrator' => false, + 'puppetdb' => true, + 'rbac' => false, + 'hac' => false, + 'patching' => false, + }, + ) + end end diff --git a/spec/plans/backup_spec.rb b/spec/plans/backup_spec.rb index 7f948cc2..20243f45 100644 --- a/spec/plans/backup_spec.rb +++ b/spec/plans/backup_spec.rb @@ -21,6 +21,7 @@ 'puppetdb' => false, 'rbac' => false, 'hac' => false, + 'patching' => false, } } end @@ -119,7 +120,25 @@ end end - context '>= 2023.7.0' do + context '>= 2025.0.0' do + let(:pe_version) { '2025.0.0' } + + include_context('all 2023.6.0 backups') + + it 'runs with backup type custom, all backup params set to true' do + expect_out_message.with_params('# Backing up database pe-hac') + expect_out_message.with_params('# Backing up database pe-patching') + + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/hac/pe-hac.dump.d "sslmode=verify-ca host=primary user=pe-hac sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-hac"' + "\n") + expect_command('/opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 -f /tmp/pe-backup-1970-01-01T000000Z/patching/pe-patching.dump.d "sslmode=verify-ca host=primary user=pe-patching sslcert=/etc/puppetlabs/puppetdb/ssl/primary.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/primary.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-patching"' + "\n") + + expect(run_plan('peadm::backup', all_backup_options)).to be_ok + end + end + + context '>= 2023.7.0 < 2025.0' do + let(:pe_version) { '2023.7.0' } + include_context('all 2023.6.0 backups') it 'runs with backup type custom, all backup params set to true' do @@ -149,7 +168,8 @@ it 'warns that hac is ignored' do expect_out_message.with_params(<<~MSG.strip) WARNING: Retrieved a missing or unparseable PE version of ''. - The host_action_collector database will be skipped from defaults. + Newer service databases released in 2023.7+ will be skipped from defaults. + (host-action-collector, patching) MSG expect(run_plan('peadm::backup', all_backup_options)).to be_ok diff --git a/spec/plans/restore_spec.rb b/spec/plans/restore_spec.rb index 81359b41..960e49f0 100644 --- a/spec/plans/restore_spec.rb +++ b/spec/plans/restore_spec.rb @@ -45,6 +45,8 @@ 'orchestrator' => false, 'puppetdb' => false, 'rbac' => false, + 'hac' => false, + 'patching' => false, } } end @@ -175,7 +177,22 @@ def expect_peadm_config_fallback(backup_dir, file) end end - context '>= 2023.7.0' do + context '>= 2025.0.0' do + let(:pe_version) { '2025.0.0' } + + include_context('all 2023.6.0 backups') + + it 'runs with backup type custom, all params set to true', valid_cluster: true do + expect_restore_for_db('hac', 'primary') + expect_restore_for_db('patching', 'primary') + + expect(run_plan('peadm::restore', all_recovery_options)).to be_ok + end + end + + context '>= 2023.7.0 < 2025.0' do + let(:pe_version) { '2023.7.0' } + include_context('all 2023.6.0 backups') it 'runs with backup type custom, all params set to true', valid_cluster: true do @@ -211,7 +228,8 @@ def expect_peadm_config_fallback(backup_dir, file) it 'warns that hac is ignored', valid_cluster: false do expect_out_message.with_params(<<~MSG.strip) WARNING: Retrieved a missing or unparseable PE version of ''. - The host_action_collector database will be skipped from defaults. + Newer service databases released in 2023.7+ will be skipped from defaults. + (host-action-collector, patching) MSG expect_peadm_config_fallback(backup_dir, 'peadm_config.no_pe_version.json') diff --git a/types/recovery_opts.pp b/types/recovery_opts.pp index 1c20db3f..eacfd532 100644 --- a/types/recovery_opts.pp +++ b/types/recovery_opts.pp @@ -8,4 +8,5 @@ 'puppetdb' => Optional[Boolean], 'rbac' => Optional[Boolean], 'hac' => Optional[Boolean], + 'patching' => Optional[Boolean], }] From 93adb9109bfa740c21a5539092aa457e1b465a8f Mon Sep 17 00:00:00 2001 From: Josh Partlow Date: Thu, 12 Dec 2024 00:18:53 +0000 Subject: [PATCH 3/3] (PE-39352) Update REFERENCE.md for new functions. Also updates the peadm::recovery_opts type doc. --- REFERENCE.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/REFERENCE.md b/REFERENCE.md index 2951060f..b8735c23 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -16,6 +16,7 @@ ### Functions +* [`peadm::amend_recovery_defaults_by_pe_version`](#peadm--amend_recovery_defaults_by_pe_version) * [`peadm::assert_supported_architecture`](#peadm--assert_supported_architecture): Assert that the architecture given is a supported one * [`peadm::assert_supported_bolt_version`](#peadm--assert_supported_bolt_version): Assert that the Bolt executable running PEAdm is a supported version * [`peadm::assert_supported_pe_version`](#peadm--assert_supported_pe_version): Assert that the PE version given is supported by PEAdm @@ -39,6 +40,7 @@ * [`peadm::recovery_opts_all`](#peadm--recovery_opts_all) * [`peadm::recovery_opts_default`](#peadm--recovery_opts_default) * [`peadm::update_pe_conf`](#peadm--update_pe_conf): Update the pe.conf file on a target with the provided hash +* [`peadm::validated_pe_version_for_backup_restore`](#peadm--validated_pe_version_for_backup_restore): Verify that *pe_version* string is a valid SemVer. If not, warn, and return "0.0.0" as a permissive default. * [`peadm::wait_until_service_ready`](#peadm--wait_until_service_ready): A convenience function to help remember port numbers for services and handle running the wait_until_service_ready task ### Data types @@ -139,6 +141,36 @@ Supported use cases: ## Functions +### `peadm::amend_recovery_defaults_by_pe_version` + +Type: Puppet Language + +The peadm::amend_recovery_defaults_by_pe_version function. + +#### `peadm::amend_recovery_defaults_by_pe_version(Hash $base_opts, Peadm::Pe_version $pe_version, Boolean $opt_value)` + +The peadm::amend_recovery_defaults_by_pe_version function. + +Returns: `Any` + +##### `base_opts` + +Data type: `Hash` + + + +##### `pe_version` + +Data type: `Peadm::Pe_version` + + + +##### `opt_value` + +Data type: `Boolean` + + + ### `peadm::assert_supported_architecture` Type: Puppet Language @@ -787,12 +819,18 @@ Type: Puppet Language The peadm::migration_opts_default function. -#### `peadm::migration_opts_default()` +#### `peadm::migration_opts_default(Peadm::Pe_version $pe_version)` The peadm::migration_opts_default function. Returns: `Any` +##### `pe_version` + +Data type: `Peadm::Pe_version` + + + ### `peadm::node_manager_yaml_location` Type: Ruby 4.x API @@ -853,24 +891,36 @@ Type: Puppet Language The peadm::recovery_opts_all function. -#### `peadm::recovery_opts_all()` +#### `peadm::recovery_opts_all(Peadm::Pe_version $pe_version)` The peadm::recovery_opts_all function. Returns: `Any` +##### `pe_version` + +Data type: `Peadm::Pe_version` + + + ### `peadm::recovery_opts_default` Type: Puppet Language The peadm::recovery_opts_default function. -#### `peadm::recovery_opts_default()` +#### `peadm::recovery_opts_default(Peadm::Pe_version $pe_version)` The peadm::recovery_opts_default function. Returns: `Any` +##### `pe_version` + +Data type: `Peadm::Pe_version` + + + ### `peadm::update_pe_conf` Type: Puppet Language @@ -895,6 +945,26 @@ Data type: `Hash` The hash to update the pe.conf file with +### `peadm::validated_pe_version_for_backup_restore` + +Type: Puppet Language + +Verify that *pe_version* string is a valid SemVer. +If not, warn, and return "0.0.0" as a permissive default. + +#### `peadm::validated_pe_version_for_backup_restore(Optional[String] $pe_version)` + +Verify that *pe_version* string is a valid SemVer. +If not, warn, and return "0.0.0" as a permissive default. + +Returns: `Any` + +##### `pe_version` + +Data type: `Optional[String]` + + + ### `peadm::wait_until_service_ready` Type: Puppet Language @@ -1014,6 +1084,8 @@ Struct[{ 'orchestrator' => Optional[Boolean], 'puppetdb' => Optional[Boolean], 'rbac' => Optional[Boolean], + 'hac' => Optional[Boolean], + 'patching' => Optional[Boolean], }] ```