From f830c656aa7ce903547fff84b2063fa6063ff001 Mon Sep 17 00:00:00 2001 From: Neil Anderson Date: Wed, 18 Sep 2024 13:52:05 +0100 Subject: [PATCH] (PE-39118) Adding code manager check to add_replica (#501) * (PE-39118) Adding code manager check to add_replica * Fixing lint, and changing null return to false * Adding VERIFY_PEER --- REFERENCE.md | 15 +++++++ plans/add_replica.pp | 8 ++++ spec/plans/add_replica_spec.rb | 12 ++++++ tasks/code_manager_enabled.json | 10 +++++ tasks/code_manager_enabled.rb | 73 +++++++++++++++++++++++++++++++++ 5 files changed, 118 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 bf4d04f9..1a7f7fb4 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -58,6 +58,7 @@ * [`cert_valid_status`](#cert_valid_status): Check primary for valid state of a certificate * [`classify_compilers`](#classify_compilers): Classify compilers as legacy or non-legacy * [`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 @@ -1092,6 +1093,20 @@ 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 + +#### 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 98ec78b9..54c85523 100644 --- a/plans/add_replica.pp +++ b/plans/add_replica.pp @@ -22,6 +22,14 @@ $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, 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.') + } + 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..85d24c67 --- /dev/null +++ b/tasks/code_manager_enabled.json @@ -0,0 +1,10 @@ +{ + "description": "Run on a PE primary node to check if Code Manager is enabled.", + "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 new file mode 100755 index 00000000..2a8aa5b2 --- /dev/null +++ b/tasks/code_manager_enabled.rb @@ -0,0 +1,73 @@ +#!/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) + @host = params['host'] + end + + def execute! + code_manager_enabled = groups.dig('PE Master', 'classes', 'puppet_enterprise::profile::master', 'code_manager_auto_configure') + + 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 + # returned by the classifier + def groups + @groups ||= begin + net = https(@host, 4433) + res = net.get('/classifier-api/v1/groups') + NodeGroup.new(JSON.parse(res.body)) + end + end + + 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_PEER + https.ca_file = Puppet.settings[:localcacert] + https + 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