diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..cc67606f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.linting.pylintEnabled": true, + "python.linting.enabled": true +} \ No newline at end of file diff --git a/functions/recovery_opts_default.pp b/functions/recovery_opts_default.pp new file mode 100644 index 00000000..ef5fdfae --- /dev/null +++ b/functions/recovery_opts_default.pp @@ -0,0 +1,10 @@ +function peadm::recovery_opts_default () { + { + 'orchestrator' => true, + 'puppetdb' => true, + 'rbac' => true, + 'activity' => true, + 'ca' => false, + 'classifier' => true, + } +} diff --git a/plans/backup.pp b/plans/backup.pp index af42c2cd..977457be 100644 --- a/plans/backup.pp +++ b/plans/backup.pp @@ -1,77 +1,118 @@ # @summary Backup the core user settings for puppet infrastructure # -# This plan can backup data as outlined at insert doc +# This plan can backup data as outlined at insert doc # plan peadm::backup ( - Peadm::SingleTargetSpec $primary_host, + # This plan should be run on the primary server + Peadm::SingleTargetSpec $targets, # Which data to backup - Boolean $backup_orchestrator = true, - Boolean $backup_rbac = true, - Boolean $backup_activity = true, - Boolean $backup_ca_ssl = true, - Boolean $backup_puppetdb = false, - Boolean $backup_classification = true, - String $output_directory = '/tmp', + Peadm::Recovery_opts $backup = {}, + + # Where to put the backup folder + String $output_directory = '/tmp', ) { peadm::assert_supported_bolt_version() - $cluster = run_task('peadm::get_peadm_config', $primary_host).first + + $recovery_opts = (peadm::recovery_opts_default() + $backup) + $cluster = run_task('peadm::get_peadm_config', $targets).first.value $arch = peadm::assert_supported_architecture( - $primary_host, - $cluster['replica_host'], - $cluster['primary_postgresql_host'], - $cluster['replica_postgresql_host'], - $cluster['compiler_hosts'], + getvar('cluster.params.primary_host'), + getvar('cluster.params.replica_host'), + getvar('cluster.params.primary_postgresql_host'), + getvar('cluster.params.replica_postgresql_host'), + getvar('cluster.params.compiler_hosts'), ) - $timestamp = Timestamp.new().strftime('%F_%T') + $timestamp = Timestamp.new().strftime('%Y-%m-%dT%H%M%SZ') $backup_directory = "${output_directory}/pe-backup-${timestamp}" - # Create backup folder - apply($primary_host){ + $primary_target = getvar('cluster.params.primary_host') + $puppetdb_postgresql_target = getvar('cluster.params.primary_postgresql_host') ? { + undef => getvar('cluster.params.primary_host'), + default => getvar('cluster.params.primary_postgresql_host'), + } + + $backup_databases = { + 'orchestrator' => $primary_target, + 'activity' => $primary_target, + 'rbac' => $primary_target, + 'puppetdb' => $puppetdb_postgresql_target, + }.filter |$key,$_| { + $recovery_opts[$key] == true + } + + # Create backup folders + apply($primary_target) { file { $backup_directory : ensure => 'directory', owner => 'root', - group => 'pe-postgres', - mode => '0770' + group => 'root', + mode => '0700' } - } - # Create an array of the names of databases and whether they have to be backed up to use in a lambda later - $database_to_backup = [ $backup_orchestrator, $backup_activity, $backup_rbac, $backup_puppetdb] - $database_names = [ 'pe-orchestrator' , 'pe-activity' , 'pe-rbac' , 'pe-puppetdb' ] + # Create a subdir for each backup type selected + $recovery_opts.filter |$_,$val| { $val == true }.each |$dir,$_| { + file { "${backup_directory}/${dir}": + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0700' + } + } + } - if $backup_classification { + if getvar('recovery_opts.classifier') { out::message('# Backing up classification') - run_task('peadm::backup_classification', $primary_host, - directory => $backup_directory, + run_task('peadm::backup_classification', $primary_target, + directory => "${backup_directory}/classifier", ) } - if $backup_ca_ssl { + if getvar('recovery_opts.ca') { out::message('# Backing up ca and ssl certificates') - run_command("/opt/puppetlabs/bin/puppet-backup create --dir=${backup_directory} --scope=certs", $primary_host) + run_command(@("CMD"), $primary_target) + /opt/puppetlabs/bin/puppet-backup create --dir=${shellquote($backup_directory)}/ca --scope=certs + | CMD } # Check if /etc/puppetlabs/console-services/conf.d/secrets/keys.json exists and if so back it up - out::message('# Backing up ldap secret key if it exists') - run_command("test -f /etc/puppetlabs/console-services/conf.d/secrets/keys.json && cp -rp /etc/puppetlabs/console-services/conf.d/secrets/keys.json ${backup_directory} || echo secret ldap key doesnt exist" , $primary_host) # lint:ignore:140chars + if getvar('recovery_opts.rbac') { + out::message('# Backing up ldap secret key if it exists') + run_command(@("CMD"/L), $primary_target) + test -f /etc/puppetlabs/console-services/conf.d/secrets/keys.json \ + && cp -rp /etc/puppetlabs/console-services/conf.d/secrets ${shellquote($backup_directory)}/rbac/ \ + || echo secret ldap key doesnt exist + | CMD + } # IF backing up orchestrator back up the secrets too /etc/puppetlabs/orchestration-services/conf.d/secrets/ - if $backup_orchestrator { + if getvar('recovery_opts.orchestrator') { out::message('# Backing up orchestrator secret keys') - run_command("cp -rp /etc/puppetlabs/orchestration-services/conf.d/secrets ${backup_directory}/", $primary_host) + run_command(@("CMD"), $primary_target) + cp -rp /etc/puppetlabs/orchestration-services/conf.d/secrets ${shellquote($backup_directory)}/orchestrator/ + | CMD } - $database_to_backup.each |Integer $index, Boolean $value | { - if $value { - out::message("# Backing up database ${database_names[$index]}") - # If the primary postgresql host is set then pe-puppetdb needs to be remotely backed up to primary. - if $database_names[$index] == 'pe-puppetdb' and $cluster['primary_postgresql_host'] { - run_command("sudo -u pe-puppetdb /opt/puppetlabs/server/bin/pg_dump \"sslmode=verify-ca host=${cluster['primary_postgresql_host']} sslcert=/etc/puppetlabs/puppetdb/ssl/${primary_host}.cert.pem sslkey=/etc/puppetlabs/puppetdb/ssl/${primary_host}.private_key.pem sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem dbname=pe-puppetdb\" -f /tmp/puppetdb_$(date +%F_%T).bin" , $primary_host) # lint:ignore:140chars - } else { - run_command("sudo -u pe-postgres /opt/puppetlabs/server/bin/pg_dump -Fc \"${database_names[$index]}\" -f \"${backup_directory}/${database_names[$index]}_$(date +%F_%T).bin\"" , $primary_host) # lint:ignore:140chars - } - } + $backup_databases.each |$name,$database_target| { + run_command(@("CMD"/L), $primary_target) + /opt/puppetlabs/server/bin/pg_dump -Fd -Z3 -j4 \ + -f ${shellquote($backup_directory)}/${shellquote($name)}/pe-${shellquote($name)}.dump.d \ + "sslmode=verify-ca \ + host=${shellquote($database_target.peadm::certname())} \ + user=pe-${shellquote($name)} \ + sslcert=/etc/puppetlabs/puppetdb/ssl/${shellquote($primary_target.peadm::certname())}.cert.pem \ + sslkey=/etc/puppetlabs/puppetdb/ssl/${shellquote($primary_target.peadm::certname())}.private_key.pem \ + sslrootcert=/etc/puppetlabs/puppet/ssl/certs/ca.pem \ + dbname=pe-${shellquote($name)}" + | CMD } + + run_command(@("CMD"/L), $primary_target) + umask 0077 \ + && tar -czf ${shellquote($backup_directory)}.tar.gz ${shellquote($backup_directory)} \ + && rm -rf ${shellquote($backup_directory)} + | CMD + + return({'path' => "${backup_directory}.tar.gz"}) } diff --git a/spec/plans/backup_spec.rb b/spec/plans/backup_spec.rb index 4cb41c83..4b59f99e 100644 --- a/spec/plans/backup_spec.rb +++ b/spec/plans/backup_spec.rb @@ -6,10 +6,12 @@ it 'runs with default params' do allow_apply + pending('a lack of support for functions requires a workaround to be written') expect_task('peadm::get_peadm_config').always_return({ 'primary_postgresql_host' => 'postgres' }) expect_out_message.with_params('# Backing up ca and ssl certificates') - # The commands all have a timestamp in them and frankly its prooved to hard with bolt spec to work this out + # The commands all have a timestamp in them and frankly its proved to hard with bolt spec to work this out allow_any_command + allow_apply 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') diff --git a/types/recovery_opts.pp b/types/recovery_opts.pp new file mode 100644 index 00000000..8e88fb65 --- /dev/null +++ b/types/recovery_opts.pp @@ -0,0 +1,8 @@ +type Peadm::Recovery_opts = Struct[{ + 'orchestrator' => Optional[Boolean], + 'puppetdb' => Optional[Boolean], + 'rbac' => Optional[Boolean], + 'activity' => Optional[Boolean], + 'ca' => Optional[Boolean[false]], + 'classifier' => Optional[Boolean], +}]