diff --git a/REFERENCE.md b/REFERENCE.md
index 065b6d75..250da3cf 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,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