Skip to content

Commit 9888996

Browse files
author
petergmurphy
committed
(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.
1 parent 26c3ddf commit 9888996

File tree

5 files changed

+150
-5
lines changed

5 files changed

+150
-5
lines changed

plans/convert.pp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@
232232
run_plan('peadm::modify_certificate', $legacy_compiler_a_targets,
233233
primary_host => $primary_target,
234234
add_extensions => {
235-
peadm::oid('pp_auth_role') => 'pe_compiler',
235+
peadm::oid('pp_auth_role') => 'legacy_compiler',
236236
peadm::oid('peadm_availability_group') => 'A',
237237
peadm::oid('peadm_legacy_compiler') => 'true',
238238
},
@@ -242,7 +242,7 @@
242242
run_plan('peadm::modify_certificate', $legacy_compiler_b_targets,
243243
primary_host => $primary_target,
244244
add_extensions => {
245-
peadm::oid('pp_auth_role') => 'pe_compiler',
245+
peadm::oid('pp_auth_role') => 'legacy_compiler',
246246
peadm::oid('peadm_availability_group') => 'B',
247247
peadm::oid('peadm_legacy_compiler') => 'true',
248248
},
@@ -283,6 +283,16 @@
283283
284284
include peadm::setup::convert_node_manager
285285
}
286+
287+
# Unpin legacy compilers from PE Master group
288+
if $legacy_compiler_targets {
289+
$legacy_compiler_targets.each |$target| {
290+
run_task('peadm::node_group_unpin', $primary_target,
291+
node_certname => $target.peadm::certname(),
292+
group_name => 'PE Master',
293+
)
294+
}
295+
}
286296
}
287297
else {
288298
# lint:ignore:strict_indent

spec/plans/convert_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
end
1010

1111
let(:params) do
12-
{ 'primary_host' => 'primary' }
12+
{ 'primary_host' => 'primary', 'legacy_compiler_host' => 'legacy_compiler' }
1313
end
1414

1515
it 'single primary no dr valid' do
@@ -21,6 +21,7 @@
2121
expect_task('peadm::cert_data').return_for_targets('primary' => trustedjson)
2222
expect_task('peadm::read_file').always_return({ 'content' => '2021.7.9' })
2323
expect_task('peadm::get_group_rules').return_for_targets('primary' => { '_output' => '{"rules": []}' })
24+
expect_task('peadm::node_group_unpin').with_targets('primary').with_params({ 'node_certname' => 'legacy_compiler', 'group_name' => 'PE Master' })
2425

2526
# For some reason, expect_plan() was not working??
2627
allow_plan('peadm::modify_certificate').always_return({})

tasks/get_peadm_config.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def execute!
2222

2323
def config
2424
# Compute values
25-
primary = groups.pinned('PE Master')
25+
primary = groups.pinned('PE Certificate Authority')
2626
replica = groups.pinned('PE HA Replica')
2727
server_a = server('puppet/server', 'A', [primary, replica].compact)
2828
server_b = server('puppet/server', 'B', [primary, replica].compact)
@@ -108,7 +108,7 @@ def compilers
108108
def legacy_compilers
109109
@legacy_compilers ||=
110110
pdb_query('inventory[certname,trusted.extensions] {
111-
trusted.extensions.pp_auth_role = "pe_compiler" and
111+
trusted.extensions.pp_auth_role = "legacy_compiler" and
112112
trusted.extensions."1.3.6.1.4.1.34380.1.1.9814" = "true"
113113
}').map do |c|
114114
{

tasks/node_group_unpin.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"description": "Unpins a node from a specified PE node group",
3+
"parameters": {
4+
"node_certname": {
5+
"type": "String",
6+
"description": "The certname of the node to unpin"
7+
},
8+
"group_name": {
9+
"type": "String",
10+
"description": "The name of the node group to unpin the node from"
11+
}
12+
},
13+
"input_method": "stdin",
14+
"implementations": [
15+
{"name": "node_group_unpin.rb"}
16+
]
17+
}

tasks/node_group_unpin.rb

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/opt/puppetlabs/puppet/bin/ruby
2+
# frozen_string_literal: true
3+
4+
require 'json'
5+
require 'yaml'
6+
require 'net/https'
7+
require 'puppet'
8+
9+
# NodeGroupUnpin task class
10+
class NodeGroupUnpin
11+
def initialize(params)
12+
@params = params
13+
raise "Missing required parameter 'node_certname'" unless @params['node_certname']
14+
raise "Missing required parameter 'group_name'" unless @params['group_name']
15+
@auth = YAML.load_file('/etc/puppetlabs/puppet/classifier.yaml')
16+
rescue Errno::ENOENT
17+
raise 'Could not find classifier.yaml at /etc/puppetlabs/puppet/classifier.yaml'
18+
end
19+
20+
def https_client
21+
client = Net::HTTP.new(Puppet.settings[:certname], 4433)
22+
client.use_ssl = true
23+
client.cert = @cert ||= OpenSSL::X509::Certificate.new(File.read(Puppet.settings[:hostcert]))
24+
client.key = @key ||= OpenSSL::PKey::RSA.new(File.read(Puppet.settings[:hostprivkey]))
25+
client.verify_mode = OpenSSL::SSL::VERIFY_PEER
26+
client.ca_file = Puppet.settings[:localcacert]
27+
client
28+
end
29+
30+
def groups
31+
@groups ||= begin
32+
net = https_client
33+
res = net.get('/classifier-api/v1/groups')
34+
35+
unless res.code == '200'
36+
raise "Failed to fetch groups: HTTP #{res.code} - #{res.body}"
37+
end
38+
39+
NodeGroup.new(JSON.parse(res.body))
40+
rescue JSON::ParserError => e
41+
raise "Invalid JSON response from server: #{e.message}"
42+
rescue StandardError => e
43+
raise "Error fetching groups: #{e.message}"
44+
end
45+
end
46+
47+
def unpin_node(group, node)
48+
raise 'Invalid group object' unless group.is_a?(Hash) && group['id'] && group['name']
49+
50+
net = https_client
51+
begin
52+
data = { "nodes": [node] }.to_json
53+
url = "/classifier-api/v1/groups/#{group['id']}/unpin"
54+
55+
req = Net::HTTP::Post.new(url)
56+
req['Content-Type'] = 'application/json'
57+
req.body = data
58+
59+
res = net.request(req)
60+
61+
case res.code
62+
when '204'
63+
puts "Successfully unpinned node '#{node}' from group '#{group['name']}'"
64+
else
65+
begin
66+
error_body = JSON.parse(res.body.to_s)
67+
raise "Failed to unpin node: #{error_body['kind'] || error_body}"
68+
rescue JSON::ParserError
69+
raise "Invalid response from server (status #{res.code}): #{res.body}"
70+
end
71+
end
72+
rescue StandardError => e
73+
raise "Error during unpin request: #{e.message}"
74+
end
75+
end
76+
77+
# Utility class to aid in retrieving useful information from the node group
78+
# data
79+
class NodeGroup
80+
attr_reader :data
81+
82+
def initialize(data)
83+
@data = data
84+
end
85+
86+
# Aids in digging into node groups by name, rather than UUID
87+
def dig(name, *args)
88+
group = @data.find { |obj| obj['name'] == name }
89+
if group.nil?
90+
nil
91+
elsif args.empty?
92+
group
93+
else
94+
group.dig(*args)
95+
end
96+
end
97+
end
98+
99+
def execute!
100+
group_name = @params['group_name']
101+
node_certname = @params['node_certname']
102+
group = groups.dig(group_name)
103+
if group
104+
unpin_node(group, node_certname)
105+
puts "Unpinned #{node_certname} from #{group_name}"
106+
else
107+
puts "Group #{group_name} not found"
108+
end
109+
end
110+
end
111+
112+
# Run the task unless an environment flag has been set
113+
unless ENV['RSPEC_UNIT_TEST_MODE']
114+
Puppet.initialize_settings
115+
task = NodeGroupUnpin.new(JSON.parse(STDIN.read))
116+
task.execute!
117+
end

0 commit comments

Comments
 (0)