2 changes: 1 addition & 1 deletion .github/workflows/test-add-compiler-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
image: [almalinux-cloud/almalinux-8]
steps:
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Activate Ruby 2.7
uses: ruby/setup-ruby@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-add-replica-matrix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
image: [almalinux-cloud/almalinux-8]
steps:
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Activate Ruby 2.7
uses: ruby/setup-ruby@v1
with:
Expand Down
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org).

## [v3.24.0](https://github.com/puppetlabs/puppetlabs-peadm/tree/v3.24.0) - 2024-09-20

[Full Changelog](https://github.com/puppetlabs/puppetlabs-peadm/compare/v3.23.0...v3.24.0)

### Added

- (PE-39118) Adding code manager check to add_replica [#501](https://github.com/puppetlabs/puppetlabs-peadm/pull/501) ([ragingra](https://github.com/ragingra))

## [v3.23.0](https://github.com/puppetlabs/puppetlabs-peadm/tree/v3.23.0) - 2024-09-12

[Full Changelog](https://github.com/puppetlabs/puppetlabs-peadm/compare/v3.22.0...v3.23.0)
Expand All @@ -26,13 +34,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

### Fixed

- (#469) Assign correct environment to node groups [#479](https://github.com/puppetlabs/puppetlabs-peadm/pull/479) ([bastelfreak](https://github.com/bastelfreak))
- pe_installer_source: Use Stdlib::HTTPSUrl datatype [#466](https://github.com/puppetlabs/puppetlabs-peadm/pull/466) ([bastelfreak](https://github.com/bastelfreak))

### Other

- PE-38815 add_replica plan updated, test matrix added [#480](https://github.com/puppetlabs/puppetlabs-peadm/pull/480) ([AaronShannon](https://github.com/AaronShannon))
- (PE-38818) Removing experimental and private from add_replica [#478](https://github.com/puppetlabs/puppetlabs-peadm/pull/478) ([ragingra](https://github.com/ragingra))
(PE-38814) add_compiler - Making primary_postgresql_host and avail_group_letter optional [#468](https://github.com/puppetlabs/puppetlabs-peadm/pull/468) ([ragingra](https://github.com/ragingra))
- (PE-38814) add_compiler - Making primary_postgresql_host and avail_group_letter optional [#468](https://github.com/puppetlabs/puppetlabs-peadm/pull/468) ([ragingra](https://github.com/ragingra))
- (PE-37235) Verify and update documentation on add_compiler [#429](https://github.com/puppetlabs/puppetlabs-peadm/pull/429) ([cathal41](https://github.com/cathal41))

## [v3.21.0](https://github.com/puppetlabs/puppetlabs-peadm/tree/v3.21.0) - 2024-07-15
Expand Down
7 changes: 7 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1068,6 +1069,12 @@ Data type: `String`

What code manager action to perform. For example: 'deploy production'; 'flush-environment-cache'; 'file-sync commit'

### <a name="code_manager_enabled"></a>`code_manager_enabled`

Run on a PE primary node to check if Code Manager is enabled.

**Supports noop?** false

### <a name="code_sync_status"></a>`code_sync_status`

A task to confirm code is in sync accross the cluster for clusters with code manager configured
Expand Down
2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "puppetlabs-peadm",
"version": "3.23.0",
"version": "3.24.0",
"author": "puppetlabs",
"summary": "Bolt plans used to deploy an at-scale Puppet Enterprise architecture",
"license": "Apache-2.0",
Expand Down
6 changes: 6 additions & 0 deletions plans/add_replica.pp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
$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,
Expand Down
12 changes: 12 additions & 0 deletions spec/plans/add_replica_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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
5 changes: 3 additions & 2 deletions tasks/backup_classification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ def execute!
private

def https_client
client = Net::HTTP.new('localhost', '4433')
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_NONE
client.verify_mode = OpenSSL::SSL::VERIFY_PEER
client.ca_file = Puppet.settings[:localcacert]
client
end

Expand Down
5 changes: 5 additions & 0 deletions tasks/code_manager_enabled.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "Run on a PE primary node to check if Code Manager is enabled.",
"parameters": {},
"input_method": "stdin"
}
67 changes: 67 additions & 0 deletions tasks/code_manager_enabled.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/opt/puppetlabs/puppet/bin/ruby
# frozen_string_literal: true

require 'json'
require 'uri'
require 'net/http'
require 'puppet'

# CodeManagerEnabled task class
class CodeManagerEnabled
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

def groups
@groups ||= begin
net = https
res = net.get('/classifier-api/v1/groups')
NodeGroup.new(JSON.parse(res.body))
end
end

def https
https = Net::HTTP.new(Puppet.settings[:certname], 4433)
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 = CodeManagerEnabled.new
task.execute!
end
5 changes: 3 additions & 2 deletions tasks/code_sync_status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ def execute!
private

def https_client
client = Net::HTTP.new('localhost', '8140')
client = Net::HTTP.new(Puppet.settings[:certname], 8140)
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.verify_mode = OpenSSL::SSL::VERIFY_PEER
client.ca_file = Puppet.settings[:localcacert]
client
end

Expand Down
14 changes: 7 additions & 7 deletions tasks/pe_ldap_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ def main
end

uri = URI("https://#{pe_main}:4433/rbac-api/v1/ds")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.ca_file = cafout.strip
http.cert = OpenSSL::X509::Certificate.new(File.read(certout.strip))
http.key = OpenSSL::PKey::RSA.new(File.read(keyout.strip))
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.ca_file = cafout.strip
https.cert = OpenSSL::X509::Certificate.new(File.read(certout.strip))
https.key = OpenSSL::PKey::RSA.new(File.read(keyout.strip))

req = Net::HTTP::Put.new(uri, 'Content-type' => 'application/json')
req.body = data.to_json

resp = http.request(req)
resp = https.request(req)

puts resp.body
raise "API response code #{resp.code}" unless resp.code == '200'
Expand Down
25 changes: 13 additions & 12 deletions tasks/puppet_infra_upgrade.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require 'open3'
require 'timeout'
require 'etc'
require 'puppet'

# Class to run and execute the `puppet infra upgrade` command as a task.
class PuppetInfraUpgrade
Expand Down Expand Up @@ -39,39 +40,38 @@ def execute!
end
end

def inventory_uri
@inventory_uri ||= URI.parse('https://localhost:8143/orchestrator/v1/inventory')
end

def request_object(nodes:, token_file:)
token = File.read(token_file)
body = {
'nodes' => nodes,
}.to_json

request = Net::HTTP::Post.new(inventory_uri.request_uri)
request = Net::HTTP::Post.new('/orchestrator/v1/inventory')
request['Content-Type'] = 'application/json'
request['X-Authentication'] = token.chomp
request.body = body

request
end

def http_object
http = Net::HTTP.new(inventory_uri.host, inventory_uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
def https_object
https = Net::HTTP.new(Puppet.settings[:certname], 8143)
https.use_ssl = true
https.cert = OpenSSL::X509::Certificate.new(File.read(Puppet.settings[:hostcert]))
https.key = OpenSSL::PKey::RSA.new(File.read(Puppet.settings[:hostprivkey]))
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.ca_file = Puppet.settings[:localcacert]

http
https
end

def wait_until_connected(nodes:, token_file:, timeout: 120)
http = http_object
https = https_object
request = request_object(nodes: nodes, token_file: token_file)
inventory = {}
Timeout.timeout(timeout) do
loop do
response = http.request(request)
response = https.request(request)
unless response.is_a? Net::HTTPSuccess
raise "Unexpected result from orchestrator: #{response.class}\n#{response}"
end
Expand All @@ -92,6 +92,7 @@ def wait_until_connected(nodes:, token_file:, timeout: 120)
# 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
upgrade = PuppetInfraUpgrade.new(JSON.parse(STDIN.read))
upgrade.execute!
end
5 changes: 3 additions & 2 deletions tasks/restore_classification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ def execute!
private

def https_client
client = Net::HTTP.new('localhost', '4433')
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_NONE
client.verify_mode = OpenSSL::SSL::VERIFY_PEER
client.ca_file = Puppet.settings[:localcacert]
client
end

Expand Down