diff --git a/metadata.json b/metadata.json index be6ef4f5..fd72c829 100644 --- a/metadata.json +++ b/metadata.json @@ -30,7 +30,7 @@ }, { "name": "puppetlabs/service", - "version_requirement": ">= 1.3.0 < 2.0.0" + "version_requirement": ">= 1.3.0 < 3.0.0" } ], "operatingsystem_support": [ diff --git a/plans/backup.pp b/plans/backup.pp new file mode 100644 index 00000000..90209c6e --- /dev/null +++ b/plans/backup.pp @@ -0,0 +1,87 @@ +# @summary Backup the core user settings for puppet infrastructure +# +# This plan can backup data as outlined at insert doc +# +plan peadm::backup ( + # Standard + Peadm::SingleTargetSpec $primary_host, + Optional[Peadm::SingleTargetSpec] $replica_host = undef, + + # Large + Optional[TargetSpec] $compiler_hosts = undef, + + # Extra Large + Optional[Peadm::SingleTargetSpec] $primary_postgresql_host = undef, + Optional[Peadm::SingleTargetSpec] $replica_postgresql_host = undef, + + # 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', +){ + + $timestamp = Timestamp.new().strftime('%F_%T') + $backup_directory = "${output_directory}/pe-backup-${timestamp}" + # Create backup folder + apply_prep($primary_host) + apply($primary_host){ + file { $backup_directory : + ensure => 'directory', + owner => 'root', + group => 'pe-postgres', + mode => '0770' + } + } + # 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' ] + + peadm::assert_supported_bolt_version() + + # Ensure input valid for a supported architecture + $arch = peadm::assert_supported_architecture( + $primary_host, + $replica_host, + $primary_postgresql_host, + $replica_postgresql_host, + $compiler_hosts, + ) + + if $backup_classification { + out::message('# Backing up classification') + run_task('peadm::backup_classification', $primary_host, + directory => $backup_directory, + ) + } + + if $backup_ca_ssl { + out::message('# Backing up ca and ssl certificates') + run_command("/opt/puppetlabs/bin/puppet-backup create --dir=${backup_directory} --scope=certs", $primary_host) + } + + # 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 backing up orchestrator back up the secrets too /etc/puppetlabs/orchestration-services/conf.d/secrets/ + if $backup_orchestrator { + out::message('# Backing up orchestrator secret keys') + run_command("cp -rp /etc/puppetlabs/orchestration-services/conf.d/secrets ${backup_directory}/", $primary_host) + } + + $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 $primary_postgresql_host { + run_command("sudo -u pe-puppetdb /opt/puppetlabs/server/bin/pg_dump \"sslmode=verify-ca host=${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 + } + } + } +} diff --git a/plans/install.pp b/plans/install.pp index 59f58dfd..de321069 100644 --- a/plans/install.pp +++ b/plans/install.pp @@ -26,7 +26,7 @@ # Common Configuration String $console_password, - String $version = '2019.8.5', + String $version = '2019.8.8', Optional[Array[String]] $dns_alt_names = undef, Optional[String] $compiler_pool_address = undef, Optional[String] $internal_compiler_a_pool_address = undef, diff --git a/spec/fixtures/plans/failed_table.txt b/spec/fixtures/plans/failed_table.txt index 02bc47e7..e2f580d2 100644 --- a/spec/fixtures/plans/failed_table.txt +++ b/spec/fixtures/plans/failed_table.txt @@ -1,4 +1,4 @@ -+-----------------+------------------+--------------------------+--------+ ++------------------------------------------------------------------------+ | Failed Service Status | +-----------------+------------------+--------------------------+--------+ | Cluster | Service | Url | Status | diff --git a/spec/fixtures/plans/passed_table.txt b/spec/fixtures/plans/passed_table.txt index 0cda33c6..15c76417 100644 --- a/spec/fixtures/plans/passed_table.txt +++ b/spec/fixtures/plans/passed_table.txt @@ -1,4 +1,4 @@ -+-----------------+---------------------------+------------------+-------------+ ++------------------------------------------------------------------------------+ | Operational Service Status | +-----------------+---------------------------+------------------+-------------+ | Cluster | Service | Url | Status | diff --git a/spec/fixtures/plans/summary_table.txt b/spec/fixtures/plans/summary_table.txt index 216a23cf..b50dc77a 100644 --- a/spec/fixtures/plans/summary_table.txt +++ b/spec/fixtures/plans/summary_table.txt @@ -1,4 +1,4 @@ -+-----------------+----------+ ++----------------------------+ | Overall Status: degraded | +-----------------+----------+ | Cluster | Status | diff --git a/spec/plans/backup_spec.rb b/spec/plans/backup_spec.rb new file mode 100644 index 00000000..46bd157c --- /dev/null +++ b/spec/plans/backup_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe 'peadm::backup' do + include BoltSpec::Plans + let(:params) { { 'primary_host' => 'primary' } } + + it 'runs with default params' do + allow_apply_prep + allow_apply + 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 + allow_any_command + 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 classification') + expect_task('peadm::backup_classification') + expect(run_plan('peadm::backup', params)).to be_ok + end +end diff --git a/tasks/backup_classification.json b/tasks/backup_classification.json new file mode 100644 index 00000000..442893ad --- /dev/null +++ b/tasks/backup_classification.json @@ -0,0 +1,13 @@ +{ + "puppet_task_version": 1, + "supports_noop": false, + "description": "A task to call the classification api and write to file", + "parameters": { + "directory": { + "type": "String", + "description": "The directory to write the classification output to. Directory must exist", + "default": "/tmp" + } + }, + "input_method": "stdin" +} diff --git a/tasks/backup_classification.rb b/tasks/backup_classification.rb new file mode 100755 index 00000000..6ddeeba2 --- /dev/null +++ b/tasks/backup_classification.rb @@ -0,0 +1,45 @@ +#!/opt/puppetlabs/puppet/bin/ruby + +# Puppet Task Name: backup_classification +require 'net/https' +require 'uri' +require 'json' +require 'puppet' + +# BackupClassiciation task class +class BackupClassification + def initialize(params) + @params = params + end + + def execute! + File.write("#{@params['directory']}/classification_backup.json", return_classification) + puts "Classification written to #{@params['directory']}/classification_backup.json" + end + + private + + def https_client + client = Net::HTTP.new('localhost', '4433') + client.use_ssl = true + client.cert = @cert ||= OpenSSL::X509::Certificate.new(File.read(Puppet.settings[:hostcert])) + client.key = @key ||= OpenSSL::PKey::RSA.new(File.read(Puppet.settings[:hostprivkey])) + client.verify_mode = OpenSSL::SSL::VERIFY_NONE + client + end + + def return_classification + classification = https_client + classification_request = Net::HTTP::Get.new('/classifier-api/v1/groups') + + classification.request(classification_request).body + end +end +# Run the task unless an environment flag has been set, signaling not to. The +# environment flag is used to disable auto-execution and enable Ruby unit +# testing of this task. +unless ENV['RSPEC_UNIT_TEST_MODE'] + Puppet.initialize_settings + task = BackupClassification.new(JSON.parse(STDIN.read)) + task.execute! +end