Skip to content

Commit 0ba1e65

Browse files
committed
Add get_cluster_roles task
This task can introspect an existing cluster (when run on a primary node) and return information about how the cluster is currently configured. This will aid in running plans that need to modify the cluster, by reducing the amount of information the user must supply. The task returns data about the cluster in both primary/replica form, as well as A/B form, since different forms are useful in different scenarios.
1 parent 580c4b0 commit 0ba1e65

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

Diff for: tasks/get_peadm_config.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"description": "Return a hash of currently configured PEAdm cluster node roles",
3+
"parameters": { },
4+
"input_method": "stdin"
5+
}

Diff for: tasks/get_peadm_config.rb

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/opt/puppetlabs/puppet/bin/ruby
2+
# frozen_string_literal: true
3+
4+
require 'json'
5+
require 'uri'
6+
require 'net/http'
7+
require 'puppet'
8+
9+
# GetPEAdmConfig task class
10+
class GetPEAdmConfig
11+
def initialize(params); end
12+
13+
# Returns a GetPEAdmConfig::NodeGroups object created from the /groups object
14+
# returned by the classifier
15+
def groups
16+
return @groups unless @groups.nil?
17+
18+
console_services = https(4433)
19+
response = console_services.get('/classifier-api/v1/groups')
20+
21+
groups = JSON.parse(response.body)
22+
@groups = NodeGroup.new(groups)
23+
end
24+
25+
# Returns a list of compiler certnames, based on a PuppetDB query
26+
def compilers
27+
query = 'inventory[certname] { trusted.extensions.pp_auth_role = "pe_compiler" }'
28+
pdb_query(query).map { |n| n['certname'] }
29+
end
30+
31+
def server(letter)
32+
query = 'inventory[certname] { '\
33+
' trusted.extensions."1.3.6.1.4.1.34380.1.1.9812" = "puppet/server" and ' \
34+
' trusted.extensions."1.3.6.1.4.1.34380.1.1.9813" = "' + letter + '"}'
35+
36+
server = pdb_query(query).map { |n| n['certname'] }
37+
raise "More than one #{letter} server found!" unless server.size <= 1
38+
server.first
39+
end
40+
41+
def postgresql_server(letter)
42+
query = 'inventory[certname] { '\
43+
' trusted.extensions."1.3.6.1.4.1.34380.1.1.9812" = "puppet/puppetdb-database" and ' \
44+
' trusted.extensions."1.3.6.1.4.1.34380.1.1.9813" = "' + letter + '"}'
45+
46+
server = pdb_query(query).map { |n| n['certname'] }
47+
raise "More than one #{letter} postgresql server found!" unless server.size <= 1
48+
server.first
49+
end
50+
51+
def config
52+
server_conf = {
53+
'primary_host' => groups.pinned('PE Master'),
54+
'replica_host' => groups.pinned('PE HA Replica'),
55+
'server_a_host' => server('A'),
56+
'server_b_host' => server('B'),
57+
}
58+
59+
primary_letter = server_conf['primary_host'] == server_conf['server_a_host'] ? 'A' : 'B'
60+
replica_letter = primary_letter == 'A' ? 'B' : 'A'
61+
62+
remaining_conf = {
63+
'primary_postgresql_host' => postgresql_server(primary_letter),
64+
'replica_postgresql_host' => postgresql_server(replica_letter),
65+
'postgresql_a_host' => groups.dig('PE Primary A', 'config_data', 'puppet_enterprise::profile::puppetdb', 'database_host'),
66+
'postgresql_b_host' => groups.dig('PE Primary B', 'config_data', 'puppet_enterprise::profile::puppetdb', 'database_host'),
67+
'compilers' => compilers,
68+
'compiler_pool_address' => groups.dig('PE Master', 'config_data', 'pe_repo', 'compile_master_pool_address'),
69+
'internal_compiler_a_pool_address' => groups.dig('PE Compiler Group A', 'classes', 'puppet_enterprise::profile::master', 'puppetdb_host')[1],
70+
'internal_compiler_b_pool_address' => groups.dig('PE Compiler Group B', 'classes', 'puppet_enterprise::profile::master', 'puppetdb_host')[1],
71+
}
72+
73+
server_conf.merge(remaining_conf)
74+
end
75+
76+
def execute!
77+
puts config.to_json
78+
end
79+
80+
def https(port)
81+
https = Net::HTTP.new('localhost', port)
82+
https.use_ssl = true
83+
https.cert = OpenSSL::X509::Certificate.new(File.read(Puppet.settings[:hostcert]))
84+
https.key = OpenSSL::PKey::RSA.new(File.read(Puppet.settings[:hostprivkey]))
85+
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
86+
https
87+
end
88+
89+
def pdb_query(query)
90+
pdb = https(8081)
91+
pdb_request = Net::HTTP::Get.new('/pdb/query/v4')
92+
pdb_request.set_form_data({ 'query' => query })
93+
JSON.parse(pdb.request(pdb_request).body)
94+
end
95+
96+
# Utility class to aid in retrieving useful information from the node group
97+
# data
98+
class NodeGroup
99+
attr_reader :data
100+
101+
def initialize(data)
102+
@data = data
103+
end
104+
105+
# Aids in digging into node groups by name, rather than UUID
106+
def dig(name, *args)
107+
group = @data.find { |obj| obj['name'] == name }
108+
return group if args.empty?
109+
group.dig(*args)
110+
end
111+
112+
# Return the node pinned to the named group
113+
# If there is more than one node, error
114+
def pinned(name)
115+
rule = dig(name, 'rule')
116+
return nil if rule.nil?
117+
raise "#{name} rule incompatible with pinning" unless rule.first == 'or'
118+
pinned = rule.drop(1)
119+
.select { |r| r[0] == '=' && r[1] == 'name' }
120+
.map { |r| r[2] }
121+
raise "#{name} contains more than one server!" unless pinned.size <= 1
122+
pinned.first
123+
end
124+
end
125+
end
126+
127+
# Run the task unless an environment flag has been set, signaling not to. The
128+
# environment flag is used to disable auto-execution and enable Ruby unit
129+
# testing of this task.
130+
unless ENV['RSPEC_UNIT_TEST_MODE']
131+
Puppet.initialize_settings
132+
task = GetPEAdmConfig.new(JSON.parse(STDIN.read))
133+
task.execute!
134+
end

0 commit comments

Comments
 (0)