Skip to content

Commit f59ff6e

Browse files
authored
Merge pull request #89 from bastelfreak/facts
Document fact bootstrapping for new puppetserver
2 parents c4804c8 + 37ed9a9 commit f59ff6e

File tree

1 file changed

+128
-1
lines changed

1 file changed

+128
-1
lines changed

README.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
1. [Contributors](#contributors)
2828
1. [See Also](#see-also)
2929
1. [Upload facts to PuppetDB](#upload-facts-to-puppetdb)
30+
1. [Modern fact submission](#modern-fact-submission)
3031

3132

3233
## Overview
@@ -336,8 +337,134 @@ version 3 to Masters running version 5. It uses the [`/puppet/v3/facts/` API](ht
336337
which is available in version 3 and >= 5 of Puppet. This API was removed in Puppet 4 but
337338
added again in 5.
338339

339-
### Further documentation
340+
### Modern fact submission
341+
342+
Nowadays it's possible to use `puppet facts upload --server $new_server` to
343+
submit facts to a new server. This however requires that the new puppetserver
344+
and the old one share one certificate authority. You can easily run this once
345+
via bolt to get all facts to a new puppetserver.
346+
347+
### complex fact submission
348+
349+
To every problem an overengineered solution exists! Let's assume this:
350+
You have an existing Puppet environment. You setup a new Puppetserver,
351+
with a newer Puppet version and a new CA. You have a third box with
352+
catalog_diff, that has certificates to access the old and new Puppetserver. Now
353+
for catalog_diff to work, we need to get the facts from the old environment to
354+
the new one. There are three little scripts that you can use to:
355+
356+
* download facts from old PuppetDB
357+
* Convert the format
358+
* Submit them to the new Puppetserver
359+
360+
It's best to run them on the catalog_diff box, since it already has certificates
361+
that allow it to access all required APIs:
362+
363+
364+
```bash
365+
#!/bin/bash
366+
367+
368+
#differ_certs/
369+
#├── catalog-diff_dev
370+
#│ ├── ca
371+
#│ │ └── ca.pem
372+
#│ ├── cert
373+
#│ │ └── catalog-diff.pem
374+
#│ └── private
375+
#│ └── catalog-diff.pem
376+
#├── catalog-diff_prod
377+
#│ ├── ca
378+
#│ │ └── ca.pem
379+
#│ ├── cert
380+
#│ │ └── catalog-diff.pem
381+
#│ └── private
382+
#│ └── catalog-diff.pem
383+
384+
385+
certs_dir="${HOME}/differ_certs"
386+
certs_dev="${certs_dir}/catalog-diff_dev"
387+
certs_prod="${certs_dir}/catalog-diff_prod"
388+
cert='catalog-diff.pem'
389+
puppetdb_dev=puppet-dev.local
390+
puppetdb_prod=puppet-prod.local
391+
clientcert_dev="${certs_dev}/cert/${cert}"
392+
clientcert_prod="${certs_prod}/cert/${cert}"
393+
clientkey_dev="${certs_dev}/private/${cert}"
394+
clientkey_prod="${certs_prod}/private/${cert}"
395+
cacert_dev="${certs_dev}/ca/ca.pem"
396+
cacert_prod="${certs_prod}/ca/ca.pem"
397+
398+
function prod_facts() {
399+
curl --request GET \
400+
--url "https://${puppetdb_prod}:8081/pdb/query/v4/factsets" \
401+
--cert "${clientcert_prod}" \
402+
--cacert "${cacert_prod}" \
403+
--key "${clientkey_prod}" \
404+
--silent \
405+
| jq -cr '.[] | .certname, .' | awk 'NR%2{f="factsets/"$0".json";next} {print >f;close(f)}'
406+
}
407+
408+
function dev_facts() {
409+
curl --request GET \
410+
--url "https://${puppetdb_dev}:8081/pdb/query/v4/factsets" \
411+
--cert "${clientcert_dev}" \
412+
--cacert "${cacert_dev}" \
413+
--key "${clientkey_dev}" \
414+
--silent \
415+
| jq -cr '.[] | .certname, .' | awk 'NR%2{f="factsets/"$0".json";next} {print >f;close(f)}'
416+
}
417+
418+
function facts() {
419+
dev_facts
420+
prod_facts
421+
}
422+
facts
423+
```
340424

425+
```ruby
426+
#!/opt/puppetlabs/puppet/bin/ruby
427+
428+
require 'json'
429+
require 'date'
430+
431+
Dir[Dir.home + "/factsets/*.json"].each do |file|
432+
filename = File.basename(file)
433+
puts "processing #{filename}"
434+
facts = JSON.parse(File.read(file))
435+
real_facts = { }
436+
real_facts['values'] = facts['facts']['data'].map{|facthash| {facthash['name'] => facthash['value']}}.reduce({}, :merge)
437+
real_facts['name'] = facts['certname']
438+
real_facts['timestamp'] = facts['timestamp']
439+
# expiration is usually timestamp + runintervall. We use 30min here
440+
real_facts['expiration'] = DateTime.parse(facts['timestamp']) + Rational(30 * 60, 86400)
441+
File.open(Dir.home + "/facts/#{filename}","w") do |f| f.write("#{JSON.pretty_generate(real_facts)}\n") end
442+
end
443+
```
444+
445+
```bash
446+
#!/bin/bash
447+
448+
hostcert="$(puppet config print hostcert)"
449+
hostprivkey="$(puppet config print hostprivkey)"
450+
localcacert="$(puppet config print localcacert)"
451+
server="$(puppet config print server)"
452+
for file in facts/*json; do
453+
filename="$(basename $file)"
454+
certname="$(basename $filename '.json')"
455+
environment="$(jq --raw-output .environment factsets/${filename})"
456+
curl --include \
457+
--request PUT \
458+
--cert "${hostcert}" \
459+
--key "${hostprivkey}" \
460+
--cacert "${localcacert}" \
461+
--data @"${file}" \
462+
--url "https://${server}:8140/puppet/v3/facts/${certname}?environment=${environment}" \
463+
--header 'Content-Type: application/json'
464+
done
465+
```
466+
467+
### Further documentation
341468

342469
* Raphaël Pinson wrote a [blog series on dev.to](https://dev.to/camptocamp-ops/diffing-puppet-environments-1fno) about using puppet-catalog-diff and GitLab integration
343470
* Raphaël Pinson also made two talks about it:

0 commit comments

Comments
 (0)