From d36dce439944bbe29e2c7aa708e620889a13d23c Mon Sep 17 00:00:00 2001 From: petergmurphy Date: Wed, 15 Jan 2025 15:12:11 +0000 Subject: [PATCH] (PE-39577) Optimise legacy compiler support This commit: - Adds the `node_group_unpin` task. - `node_group_unpin` task is called in the convert plan to remove legacy compilers from from the PE Master node group. - Legacy compilers `pp_auth_role` changed to `legacy_compiler`. - Changes the PEADM config to use the PE Certificate Authority node group. - Removes peadm_legacy_compiler extension. --- manifests/setup/legacy_compiler_group.pp | 59 ++++++------ manifests/setup/node_manager.pp | 19 ++-- plans/convert.pp | 18 ++-- plans/convert_compiler_to_legacy.pp | 8 +- plans/subplans/component_install.pp | 4 +- plans/subplans/install.pp | 8 +- plans/update_compiler_extensions.pp | 5 - plans/upgrade.pp | 8 +- spec/plans/convert_spec.rb | 4 +- tasks/get_peadm_config.rb | 8 +- tasks/node_group_unpin.json | 17 ++++ tasks/node_group_unpin.rb | 117 +++++++++++++++++++++++ 12 files changed, 199 insertions(+), 76 deletions(-) create mode 100644 tasks/node_group_unpin.json create mode 100755 tasks/node_group_unpin.rb diff --git a/manifests/setup/legacy_compiler_group.pp b/manifests/setup/legacy_compiler_group.pp index e3601200..8c31a9c0 100644 --- a/manifests/setup/legacy_compiler_group.pp +++ b/manifests/setup/legacy_compiler_group.pp @@ -1,43 +1,43 @@ # @api private class peadm::setup::legacy_compiler_group ( String[1] $primary_host, - Optional[String] $internal_compiler_a_pool_address = undef, - Optional[String] $internal_compiler_b_pool_address = undef, + Optional[String] $internal_compiler_a_pool_address = undef, + Optional[String] $internal_compiler_b_pool_address = undef, ) { Node_group { purge_behavior => none, } node_group { 'PE Legacy Compiler': - parent => 'PE Master', - rule => ['and', - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'true'], - ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], - ], - classes => { - 'puppet_enterprise::profile::master' => { - 'puppetdb_host' => [$internal_compiler_a_pool_address, $internal_compiler_b_pool_address].filter |$_| { $_ }, - 'puppetdb_port' => [8081], + ensure => 'present', + parent => 'PE Master', + purge_behavior => 'classes', + rule => ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], + classes => { + 'puppet_enterprise::profile::master' => { + 'puppetdb_host' => [$internal_compiler_a_pool_address, $internal_compiler_b_pool_address].filter |$_| { $_ }, + 'puppetdb_port' => [8081], + 'replication_mode' => 'none', + 'code_manager_auto_configure' => true, }, }, } node_group { 'PE Legacy Compiler Group A': - ensure => 'present', - parent => 'PE Legacy Compiler', - rule => ['and', - ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], + ensure => 'present', + parent => 'PE Legacy Compiler', + purge_behavior => 'classes', + rule => ['and', + ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], ['=', ['trusted', 'extensions', peadm::oid('peadm_availability_group')], 'A'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'true'], ], - classes => { - 'puppet_enterprise::profile::master' => { + classes => { + 'puppet_enterprise::profile::master' => { 'puppetdb_host' => [$internal_compiler_b_pool_address, $internal_compiler_a_pool_address].filter |$_| { $_ }, 'puppetdb_port' => [8081], }, }, - data => { - # Workaround for GH-118 + data => { 'puppet_enterprise::profile::master::puppetdb' => { 'ha_enabled_replicas' => [], }, @@ -45,21 +45,20 @@ } node_group { 'PE Legacy Compiler Group B': - ensure => 'present', - parent => 'PE Legacy Compiler', - rule => ['and', - ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], + ensure => 'present', + parent => 'PE Legacy Compiler', + purge_behavior => 'classes', + rule => ['and', + ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], ['=', ['trusted', 'extensions', peadm::oid('peadm_availability_group')], 'B'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'true'], ], - classes => { - 'puppet_enterprise::profile::master' => { + classes => { + 'puppet_enterprise::profile::master' => { 'puppetdb_host' => [$internal_compiler_a_pool_address, $internal_compiler_b_pool_address].filter |$_| { $_ }, 'puppetdb_port' => [8081], }, }, - data => { - # Workaround for GH-118 + data => { 'puppet_enterprise::profile::master::puppetdb' => { 'ha_enabled_replicas' => [], }, @@ -67,6 +66,6 @@ } node_group { 'PE Compiler': - rule => ['and', ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'false']], + rule => ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], } } diff --git a/manifests/setup/node_manager.pp b/manifests/setup/node_manager.pp index f74cb217..5334a3f1 100644 --- a/manifests/setup/node_manager.pp +++ b/manifests/setup/node_manager.pp @@ -77,12 +77,16 @@ parent => 'PE Infrastructure', data => $compiler_pool_address_data, variables => { 'pe_master' => true }, + rule => ['or', + ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], + ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], + ], } # PE Compiler group comes from default PE and already has the pe compiler role node_group { 'PE Compiler': parent => 'PE Master', - rule => ['and', ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'false']], + rule => ['and', ['=', ['trusted', 'extensions', peadm::oid('pp_auth_role')], 'pe_compiler']], } # This group should pin the primary, and also map to any pe-postgresql nodes @@ -121,7 +125,6 @@ rule => ['and', ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], ['=', ['trusted', 'extensions', peadm::oid('peadm_availability_group')], 'A'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'false'], ], classes => { 'puppet_enterprise::profile::puppetdb' => { @@ -180,7 +183,6 @@ rule => ['and', ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], ['=', ['trusted', 'extensions', peadm::oid('peadm_availability_group')], 'B'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'false'], ], classes => { 'puppet_enterprise::profile::puppetdb' => { @@ -203,10 +205,7 @@ node_group { 'PE Legacy Compiler': parent => 'PE Master', - rule => ['and', - ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'true'], - ], + rule => ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], classes => { 'puppet_enterprise::profile::master' => { 'puppetdb_host' => [$internal_compiler_a_pool_address, $internal_compiler_b_pool_address].filter |$_| { $_ }, @@ -221,9 +220,8 @@ ensure => 'present', parent => 'PE Legacy Compiler', rule => ['and', - ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], + ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], ['=', ['trusted', 'extensions', peadm::oid('peadm_availability_group')], 'A'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'true'], ], classes => { 'puppet_enterprise::profile::master' => { @@ -245,9 +243,8 @@ ensure => 'present', parent => 'PE Legacy Compiler', rule => ['and', - ['=', ['trusted', 'extensions', 'pp_auth_role'], 'pe_compiler'], + ['=', ['trusted', 'extensions', 'pp_auth_role'], 'legacy_compiler'], ['=', ['trusted', 'extensions', peadm::oid('peadm_availability_group')], 'B'], - ['=', ['trusted', 'extensions', peadm::oid('peadm_legacy_compiler')], 'true'], ], classes => { 'puppet_enterprise::profile::master' => { diff --git a/plans/convert.pp b/plans/convert.pp index 1ff1771a..11ee1209 100644 --- a/plans/convert.pp +++ b/plans/convert.pp @@ -214,7 +214,6 @@ add_extensions => { peadm::oid('pp_auth_role') => 'pe_compiler', peadm::oid('peadm_availability_group') => 'A', - peadm::oid('peadm_legacy_compiler') => 'false', }, ) }, @@ -224,7 +223,6 @@ add_extensions => { peadm::oid('pp_auth_role') => 'pe_compiler', peadm::oid('peadm_availability_group') => 'B', - peadm::oid('peadm_legacy_compiler') => 'false', }, ) }, @@ -232,9 +230,8 @@ run_plan('peadm::modify_certificate', $legacy_compiler_a_targets, primary_host => $primary_target, add_extensions => { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => 'A', - peadm::oid('peadm_legacy_compiler') => 'true', }, ) }, @@ -242,9 +239,8 @@ run_plan('peadm::modify_certificate', $legacy_compiler_b_targets, primary_host => $primary_target, add_extensions => { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => 'B', - peadm::oid('peadm_legacy_compiler') => 'true', }, ) }, @@ -283,6 +279,16 @@ include peadm::setup::convert_node_manager } + + # Unpin legacy compilers from PE Master group + if $legacy_compiler_targets { + $legacy_compiler_targets.each |$target| { + run_task('peadm::node_group_unpin', $primary_target, + node_certname => $target.peadm::certname(), + group_name => 'PE Master', + ) + } + } } else { # lint:ignore:strict_indent diff --git a/plans/convert_compiler_to_legacy.pp b/plans/convert_compiler_to_legacy.pp index c75924bd..55a86c3c 100644 --- a/plans/convert_compiler_to_legacy.pp +++ b/plans/convert_compiler_to_legacy.pp @@ -102,7 +102,7 @@ run_plan('peadm::modify_certificate', $compiler_targets, primary_host => $primary_target, add_extensions => { - peadm::oid('peadm_legacy_compiler') => 'false', + peadm::oid('pp_auth_role') => 'legacy_compiler', }, ) }, @@ -110,9 +110,8 @@ run_plan('peadm::modify_certificate', $legacy_compiler_a_targets, primary_host => $primary_target, add_extensions => { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => 'A', - peadm::oid('peadm_legacy_compiler') => 'true', }, ) }, @@ -120,9 +119,8 @@ run_plan('peadm::modify_certificate', $legacy_compiler_b_targets, primary_host => $primary_target, add_extensions => { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => 'B', - peadm::oid('peadm_legacy_compiler') => 'true', }, ) }, diff --git a/plans/subplans/component_install.pp b/plans/subplans/component_install.pp index c117ccb6..5929dd17 100644 --- a/plans/subplans/component_install.pp +++ b/plans/subplans/component_install.pp @@ -21,13 +21,11 @@ $certificate_extensions = { peadm::oid('pp_auth_role') => 'pe_compiler', peadm::oid('peadm_availability_group') => $avail_group_letter, - peadm::oid('peadm_legacy_compiler') => false, } } elsif $role == 'pe_compiler_legacy' { $certificate_extensions = { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => $avail_group_letter, - peadm::oid('peadm_legacy_compiler') => true, } } else { $certificate_extensions = { diff --git a/plans/subplans/install.pp b/plans/subplans/install.pp index 693c056c..ed57ba5b 100644 --- a/plans/subplans/install.pp +++ b/plans/subplans/install.pp @@ -287,7 +287,6 @@ extension_requests => { peadm::oid('pp_auth_role') => 'pe_compiler', peadm::oid('peadm_availability_group') => 'A', - peadm::oid('peadm_legacy_compiler') => 'false', } ) }, @@ -296,25 +295,22 @@ extension_requests => { peadm::oid('pp_auth_role') => 'pe_compiler', peadm::oid('peadm_availability_group') => 'B', - peadm::oid('peadm_legacy_compiler') => 'false', } ) }, background('compiler-a-csr.yaml') || { run_plan('peadm::util::insert_csr_extension_requests', $legacy_a_targets, extension_requests => { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => 'A', - peadm::oid('peadm_legacy_compiler') => 'true', } ) }, background('compiler-b-csr.yaml') || { run_plan('peadm::util::insert_csr_extension_requests', $legacy_b_targets, extension_requests => { - peadm::oid('pp_auth_role') => 'pe_compiler', + peadm::oid('pp_auth_role') => 'legacy_compiler', peadm::oid('peadm_availability_group') => 'B', - peadm::oid('peadm_legacy_compiler') => 'true', } ) }, diff --git a/plans/update_compiler_extensions.pp b/plans/update_compiler_extensions.pp index 784f919e..ff17e89f 100644 --- a/plans/update_compiler_extensions.pp +++ b/plans/update_compiler_extensions.pp @@ -7,11 +7,6 @@ $primary_target = peadm::get_targets($primary_host, 1) $host_targets = peadm::get_targets($compiler_hosts) - run_plan('peadm::modify_certificate', $host_targets, - primary_host => $primary_target, - add_extensions => { peadm::oid('peadm_legacy_compiler') => String($legacy) }, - ) - run_task('peadm::puppet_runonce', $primary_target) run_task('peadm::puppet_runonce', $host_targets) diff --git a/plans/upgrade.pp b/plans/upgrade.pp index 15b240fe..d009077a 100644 --- a/plans/upgrade.pp +++ b/plans/upgrade.pp @@ -172,8 +172,8 @@ $compiler_m1_nonlegacy_targets = $compiler_targets.filter |$target| { ($cert_extensions.dig($target.peadm::certname, peadm::oid('peadm_availability_group')) == $cert_extensions.dig($primary_target[0].peadm::certname, peadm::oid('peadm_availability_group'))) and - ($cert_extensions.dig($target.peadm::certname, peadm::oid('peadm_legacy_compiler')) - == 'false') + ($cert_extensions.dig($target.peadm::certname, peadm::oid('pp_auth_role')) + == 'pe_compiler') } $compiler_m2_targets = $compiler_targets.filter |$target| { @@ -184,8 +184,8 @@ $compiler_m2_nonlegacy_targets = $compiler_targets.filter |$target| { ($cert_extensions.dig($target.peadm::certname, peadm::oid('peadm_availability_group')) == $cert_extensions.dig($replica_target[0].peadm::certname, peadm::oid('peadm_availability_group'))) and - ($cert_extensions.dig($target.peadm::certname, peadm::oid('peadm_legacy_compiler')) - == 'false') + ($cert_extensions.dig($target.peadm::certname, peadm::oid('pp_auth_role')) + == 'pe_compiler') } peadm::plan_step('preparation') || { diff --git a/spec/plans/convert_spec.rb b/spec/plans/convert_spec.rb index 39ec7367..e3c702f0 100644 --- a/spec/plans/convert_spec.rb +++ b/spec/plans/convert_spec.rb @@ -9,7 +9,7 @@ end let(:params) do - { 'primary_host' => 'primary' } + { 'primary_host' => 'primary', 'legacy_compilers' => ['legacy_compiler'] } end it 'single primary no dr valid' do @@ -21,6 +21,8 @@ expect_task('peadm::cert_data').return_for_targets('primary' => trustedjson) expect_task('peadm::read_file').always_return({ 'content' => '2021.7.9' }) expect_task('peadm::get_group_rules').return_for_targets('primary' => { '_output' => '{"rules": []}' }) + expect_task('peadm::node_group_unpin').with_targets('primary').with_params({ 'node_certname' => 'legacy_compiler', 'group_name' => 'PE Master' }) + expect_task('peadm::check_legacy_compilers').with_targets('primary').with_params({ 'legacy_compilers' => 'legacy_compiler' }).return_for_targets('primary' => { '_output' => '' }) # For some reason, expect_plan() was not working?? allow_plan('peadm::modify_certificate').always_return({}) diff --git a/tasks/get_peadm_config.rb b/tasks/get_peadm_config.rb index 9eb3aa02..4bfffd35 100755 --- a/tasks/get_peadm_config.rb +++ b/tasks/get_peadm_config.rb @@ -22,7 +22,7 @@ def execute! def config # Compute values - primary = groups.pinned('PE Master') + primary = groups.pinned('PE Certificate Authority') replica = groups.pinned('PE HA Replica') server_a = server('puppet/server', 'A', [primary, replica].compact) server_b = server('puppet/server', 'B', [primary, replica].compact) @@ -94,8 +94,7 @@ def groups def compilers @compilers ||= pdb_query('inventory[certname,trusted.extensions] { - trusted.extensions.pp_auth_role = "pe_compiler" and - trusted.extensions."1.3.6.1.4.1.34380.1.1.9814" = "false" + trusted.extensions.pp_auth_role = "pe_compiler" }').map do |c| { 'certname' => c['certname'], @@ -108,8 +107,7 @@ def compilers def legacy_compilers @legacy_compilers ||= pdb_query('inventory[certname,trusted.extensions] { - trusted.extensions.pp_auth_role = "pe_compiler" and - trusted.extensions."1.3.6.1.4.1.34380.1.1.9814" = "true" + trusted.extensions.pp_auth_role = "legacy_compiler" }').map do |c| { 'certname' => c['certname'], diff --git a/tasks/node_group_unpin.json b/tasks/node_group_unpin.json new file mode 100644 index 00000000..806a1abf --- /dev/null +++ b/tasks/node_group_unpin.json @@ -0,0 +1,17 @@ +{ + "description": "Unpins a node from a specified PE node group", + "parameters": { + "node_certname": { + "type": "String", + "description": "The certname of the node to unpin" + }, + "group_name": { + "type": "String", + "description": "The name of the node group to unpin the node from" + } + }, + "input_method": "stdin", + "implementations": [ + {"name": "node_group_unpin.rb"} + ] +} \ No newline at end of file diff --git a/tasks/node_group_unpin.rb b/tasks/node_group_unpin.rb new file mode 100755 index 00000000..c1594f62 --- /dev/null +++ b/tasks/node_group_unpin.rb @@ -0,0 +1,117 @@ +#!/opt/puppetlabs/puppet/bin/ruby +# frozen_string_literal: true + +require 'json' +require 'yaml' +require 'net/https' +require 'puppet' + +# NodeGroupUnpin task class +class NodeGroupUnpin + def initialize(params) + @params = params + raise "Missing required parameter 'node_certname'" unless @params['node_certname'] + raise "Missing required parameter 'group_name'" unless @params['group_name'] + @auth = YAML.load_file('/etc/puppetlabs/puppet/classifier.yaml') + rescue Errno::ENOENT + raise 'Could not find classifier.yaml at /etc/puppetlabs/puppet/classifier.yaml' + end + + def https_client + client = Net::HTTP.new(Puppet.settings[:certname], 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_PEER + client.ca_file = Puppet.settings[:localcacert] + client + end + + def groups + @groups ||= begin + net = https_client + res = net.get('/classifier-api/v1/groups') + + unless res.code == '200' + raise "Failed to fetch groups: HTTP #{res.code} - #{res.body}" + end + + NodeGroup.new(JSON.parse(res.body)) + rescue JSON::ParserError => e + raise "Invalid JSON response from server: #{e.message}" + rescue StandardError => e + raise "Error fetching groups: #{e.message}" + end + end + + def unpin_node(group, node) + raise 'Invalid group object' unless group.is_a?(Hash) && group['id'] && group['name'] + + net = https_client + begin + data = { "nodes": [node] }.to_json + url = "/classifier-api/v1/groups/#{group['id']}/unpin" + + req = Net::HTTP::Post.new(url) + req['Content-Type'] = 'application/json' + req.body = data + + res = net.request(req) + + case res.code + when '204' + puts "Successfully unpinned node '#{node}' from group '#{group['name']}'" + else + begin + error_body = JSON.parse(res.body.to_s) + raise "Failed to unpin node: #{error_body['kind'] || error_body}" + rescue JSON::ParserError + raise "Invalid response from server (status #{res.code}): #{res.body}" + end + end + rescue StandardError => e + raise "Error during unpin request: #{e.message}" + end + 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 + + def execute! + group_name = @params['group_name'] + node_certname = @params['node_certname'] + group = groups.dig(group_name) + if group + unpin_node(group, node_certname) + puts "Unpinned #{node_certname} from #{group_name}" + else + puts "Group #{group_name} not found" + end + end +end + +# Run the task unless an environment flag has been set +unless ENV['RSPEC_UNIT_TEST_MODE'] + Puppet.initialize_settings + task = NodeGroupUnpin.new(JSON.parse(STDIN.read)) + task.execute! +end