From 3fce29b23bfa8f690bd6f85a2b326473451d0042 Mon Sep 17 00:00:00 2001 From: Neil Anderson Date: Mon, 16 Sep 2024 12:01:00 +0100 Subject: [PATCH 1/3] (PE-39118) Adding code manager check to add_replica --- REFERENCE.md | 7 +++ plans/add_replica.pp | 5 +++ spec/plans/add_replica_spec.rb | 12 ++++++ tasks/code_manager_enabled.json | 5 +++ tasks/code_manager_enabled.rb | 75 +++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 tasks/code_manager_enabled.json create mode 100755 tasks/code_manager_enabled.rb diff --git a/REFERENCE.md b/REFERENCE.md index 065b6d75..b649f54b 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -56,6 +56,7 @@ * [`cert_data`](#cert_data): Return certificate data related to the Puppet agent * [`cert_valid_status`](#cert_valid_status): Check primary for valid state of a certificate * [`code_manager`](#code_manager): Perform various code manager actions +* [`code_manager_enabled`](#code_manager_enabled): Run on a PE primary node to check if Code Manager is enabled. * [`code_sync_status`](#code_sync_status): A task to confirm code is in sync accross the cluster for clusters with code manager configured * [`divert_code_manager`](#divert_code_manager): Divert the code manager live-dir setting * [`download`](#download): Download a file using curl @@ -1068,6 +1069,12 @@ Data type: `String` What code manager action to perform. For example: 'deploy production'; 'flush-environment-cache'; 'file-sync commit' +### `code_manager_enabled` + +Run on a PE primary node to check if Code Manager is enabled. + +**Supports noop?** false + ### `code_sync_status` A task to confirm code is in sync accross the cluster for clusters with code manager configured diff --git a/plans/add_replica.pp b/plans/add_replica.pp index 98ec78b9..99a05b91 100644 --- a/plans/add_replica.pp +++ b/plans/add_replica.pp @@ -22,6 +22,11 @@ $replica_target = peadm::get_targets($replica_host, 1) $replica_postgresql_target = peadm::get_targets($replica_postgresql_host, 1) + $code_manager_enabled = run_task('peadm::code_manager_enabled', $primary_target).first.value['code_manager_enabled'] + if $code_manager_enabled == false { + fail('Code Manager must be enabled to add a replica. Please refer to the docs for more information on enabling Code Manager.') + } + run_command('systemctl stop puppet.service', peadm::flatten_compact([ $primary_target, $replica_postgresql_target, diff --git a/spec/plans/add_replica_spec.rb b/spec/plans/add_replica_spec.rb index ed3ae7b2..3a04beaf 100644 --- a/spec/plans/add_replica_spec.rb +++ b/spec/plans/add_replica_spec.rb @@ -11,6 +11,7 @@ def allow_standard_non_returning_calls end describe 'basic functionality' do + let(:code_manager_enabled) { { 'code_manager_enabled' => true } } let(:params) { { 'primary_host' => 'primary', 'replica_host' => 'replica' } } let(:cfg) { { 'params' => { 'primary_host' => 'primary' } } } let(:certdata) do @@ -30,6 +31,7 @@ def allow_standard_non_returning_calls it 'runs successfully when the primary does not have alt-names' do allow_standard_non_returning_calls + expect_task('peadm::code_manager_enabled').always_return(code_manager_enabled) expect_task('peadm::get_peadm_config').always_return(cfg) expect_task('peadm::cert_data').always_return(certdata).be_called_times(4) expect_task('peadm::cert_valid_status').always_return(certstatus) @@ -50,6 +52,7 @@ def allow_standard_non_returning_calls it 'runs successfully when the primary has alt-names' do allow_standard_non_returning_calls + expect_task('peadm::code_manager_enabled').always_return(code_manager_enabled) expect_task('peadm::get_peadm_config').always_return(cfg) expect_task('peadm::cert_data').always_return(certdata.merge({ 'dns-alt-names' => ['primary', 'alt'] })).be_called_times(4) expect_task('peadm::cert_valid_status').always_return(certstatus) @@ -67,5 +70,14 @@ def allow_standard_non_returning_calls expect_out_verbose.with_params('Updating classification to...') expect(run_plan('peadm::add_replica', params)).to be_ok end + + it 'fails when code manager not enabled' do + allow_standard_non_returning_calls + expect_task('peadm::code_manager_enabled').always_return({ 'code_manager_enabled' => false }) + + result = run_plan('peadm::add_replica', params) + expect(result).not_to be_ok + expect(result.value.msg).to match(%r{Code Manager must be enabled}) + end end end diff --git a/tasks/code_manager_enabled.json b/tasks/code_manager_enabled.json new file mode 100644 index 00000000..f595bb47 --- /dev/null +++ b/tasks/code_manager_enabled.json @@ -0,0 +1,5 @@ +{ + "description": "Run on a PE primary node to check if Code Manager is enabled.", + "parameters": { }, + "input_method": "stdin" +} diff --git a/tasks/code_manager_enabled.rb b/tasks/code_manager_enabled.rb new file mode 100755 index 00000000..250a5e64 --- /dev/null +++ b/tasks/code_manager_enabled.rb @@ -0,0 +1,75 @@ +#!/opt/puppetlabs/puppet/bin/ruby +# frozen_string_literal: true + +require 'json' +require 'uri' +require 'net/http' +require 'puppet' + +# GetPEAdmConfig task class +class GetPEAdmConfig + def initialize(params); end + + def execute! + code_manager_enabled = groups.dig('PE Master', 'classes', 'puppet_enterprise::profile::master', 'code_manager_auto_configure') + + puts({"code_manager_enabled" => code_manager_enabled}.to_json) + end + + # Returns a GetPEAdmConfig::NodeGroups object created from the /groups object + # returned by the classifier + def groups + @groups ||= begin + net = https(4433) + res = net.get('/classifier-api/v1/groups') + NodeGroup.new(JSON.parse(res.body)) + end + end + + def https(port) + https = Net::HTTP.new('localhost', port) + https.use_ssl = true + https.cert = @cert ||= OpenSSL::X509::Certificate.new(File.read(Puppet.settings[:hostcert])) + https.key = @key ||= OpenSSL::PKey::RSA.new(File.read(Puppet.settings[:hostprivkey])) + https.verify_mode = OpenSSL::SSL::VERIFY_NONE + https + end + + def pdb_query(query) + pdb = https(8081) + pdb_request = Net::HTTP::Get.new('/pdb/query/v4') + pdb_request.set_form_data({ 'query' => query }) + JSON.parse(pdb.request(pdb_request).body) + end + + # Utility class to aid in retrieving useful information from the node group + # data + class NodeGroup + attr_reader :data + + def initialize(data) + @data = data + end + + # Aids in digging into node groups by name, rather than UUID + def dig(name, *args) + group = @data.find { |obj| obj['name'] == name } + if group.nil? + nil + elsif args.empty? + group + else + group.dig(*args) + end + end + 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 = GetPEAdmConfig.new(JSON.parse(STDIN.read)) + task.execute! +end From a81be253c3327ec65c17c9a692f96bf4f5c5184d Mon Sep 17 00:00:00 2001 From: Neil Anderson Date: Mon, 16 Sep 2024 17:03:04 +0100 Subject: [PATCH 2/3] Fixing lint, and changing null return to false --- tasks/code_manager_enabled.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tasks/code_manager_enabled.rb b/tasks/code_manager_enabled.rb index 250a5e64..ba606422 100755 --- a/tasks/code_manager_enabled.rb +++ b/tasks/code_manager_enabled.rb @@ -12,8 +12,10 @@ def initialize(params); end def execute! code_manager_enabled = groups.dig('PE Master', 'classes', 'puppet_enterprise::profile::master', 'code_manager_auto_configure') - - puts({"code_manager_enabled" => code_manager_enabled}.to_json) + + code_manager_enabled_value = code_manager_enabled == true + + puts({ 'code_manager_enabled' => code_manager_enabled_value }.to_json) end # Returns a GetPEAdmConfig::NodeGroups object created from the /groups object From 423621970af432095a7a6603861ce00b6437fb2a Mon Sep 17 00:00:00 2001 From: Neil Anderson Date: Tue, 17 Sep 2024 19:33:11 +0100 Subject: [PATCH 3/3] Adding VERIFY_PEER --- REFERENCE.md | 8 ++++++++ plans/add_replica.pp | 5 ++++- tasks/code_manager_enabled.json | 7 ++++++- tasks/code_manager_enabled.rb | 20 ++++++++------------ 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/REFERENCE.md b/REFERENCE.md index b649f54b..250da3cf 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -1075,6 +1075,14 @@ Run on a PE primary node to check if Code Manager is enabled. **Supports noop?** false +#### Parameters + +##### `host` + +Data type: `String[1]` + +Hostname of the PE primary node + ### `code_sync_status` A task to confirm code is in sync accross the cluster for clusters with code manager configured diff --git a/plans/add_replica.pp b/plans/add_replica.pp index 99a05b91..54c85523 100644 --- a/plans/add_replica.pp +++ b/plans/add_replica.pp @@ -22,7 +22,10 @@ $replica_target = peadm::get_targets($replica_host, 1) $replica_postgresql_target = peadm::get_targets($replica_postgresql_host, 1) - $code_manager_enabled = run_task('peadm::code_manager_enabled', $primary_target).first.value['code_manager_enabled'] + $code_manager_enabled = run_task( + 'peadm::code_manager_enabled', $primary_target, host => $primary_target.peadm::certname() + ).first.value['code_manager_enabled'] + if $code_manager_enabled == false { fail('Code Manager must be enabled to add a replica. Please refer to the docs for more information on enabling Code Manager.') } diff --git a/tasks/code_manager_enabled.json b/tasks/code_manager_enabled.json index f595bb47..85d24c67 100644 --- a/tasks/code_manager_enabled.json +++ b/tasks/code_manager_enabled.json @@ -1,5 +1,10 @@ { "description": "Run on a PE primary node to check if Code Manager is enabled.", - "parameters": { }, + "parameters": { + "host": { + "type": "String[1]", + "description": "Hostname of the PE primary node" + } + }, "input_method": "stdin" } diff --git a/tasks/code_manager_enabled.rb b/tasks/code_manager_enabled.rb index ba606422..2a8aa5b2 100755 --- a/tasks/code_manager_enabled.rb +++ b/tasks/code_manager_enabled.rb @@ -8,7 +8,9 @@ # GetPEAdmConfig task class class GetPEAdmConfig - def initialize(params); end + def initialize(params) + @host = params['host'] + end def execute! code_manager_enabled = groups.dig('PE Master', 'classes', 'puppet_enterprise::profile::master', 'code_manager_auto_configure') @@ -22,28 +24,22 @@ def execute! # returned by the classifier def groups @groups ||= begin - net = https(4433) + net = https(@host, 4433) res = net.get('/classifier-api/v1/groups') NodeGroup.new(JSON.parse(res.body)) end end - def https(port) - https = Net::HTTP.new('localhost', port) + def https(host, port) + https = Net::HTTP.new(host, port) https.use_ssl = true https.cert = @cert ||= OpenSSL::X509::Certificate.new(File.read(Puppet.settings[:hostcert])) https.key = @key ||= OpenSSL::PKey::RSA.new(File.read(Puppet.settings[:hostprivkey])) - https.verify_mode = OpenSSL::SSL::VERIFY_NONE + https.verify_mode = OpenSSL::SSL::VERIFY_PEER + https.ca_file = Puppet.settings[:localcacert] https end - def pdb_query(query) - pdb = https(8081) - pdb_request = Net::HTTP::Get.new('/pdb/query/v4') - pdb_request.set_form_data({ 'query' => query }) - JSON.parse(pdb.request(pdb_request).body) - end - # Utility class to aid in retrieving useful information from the node group # data class NodeGroup