beaker-puppet 4.4.2 → 4.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7e6d038ac57aef64b353df0164ffc60deaa271b12ac273484e9b3af2ef15008
4
- data.tar.gz: 4b79a68287b4b82c9fa322c8020e31c54cac11d5aee4dbd37c470eb0bd655a6c
3
+ metadata.gz: e9d1aa526da4c8769497a59aabdbbe0ac613257a1821007382990de7c33c3894
4
+ data.tar.gz: 8a39103726db46e5321e805fda7925197a2011c96f027dbd4cc9b936abcafc40
5
5
  SHA512:
6
- metadata.gz: 63f4933b686b1d43dc520575b752f4f4267e97a3b8646debc04707a6efd04405d366aa6da5d5fbee2ad1eafc97dcb669e8e0fae3121448c149f253f0491ccbed
7
- data.tar.gz: 339bcc300c9ee16b5157cceb6fa933d95f57062738a5153dec963a64a91d7b39b42d502d86046d00e2e6c48bcf4d7db9c6682ab69abfe7941fa3bc060fcc8f27
6
+ metadata.gz: d71514b42d3f9aca125c68a7458a36c047a5a2a1214b5645acd0faba6274b3f30cc4e98de95526ce291318680a498491d977f8f150812a19a9f5f1c875b9d2db
7
+ data.tar.gz: 61fd33d1feff22ddbce4580e3865dc187d381eb125c8698e6b455f5abbc3ab46fe785152a94c49f2d71a5e7ca822fa6874290f3b31138e87fdbabd708be39093
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.4.3](https://github.com/puppetlabs/beaker-puppet/tree/4.4.3) (2026-08-17)
4
+
5
+ [Full Changelog](https://github.com/puppetlabs/beaker-puppet/compare/4.4.2...4.4.3)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - \(PE-45697\) Content-validate PuppetDB readiness over the ssl status port [\#280](https://github.com/puppetlabs/beaker-puppet/pull/280) ([steveax](https://github.com/steveax))
10
+
3
11
  ## [4.4.2](https://github.com/puppetlabs/beaker-puppet/tree/4.4.2) (2026-08-12)
4
12
 
5
13
  [Full Changelog](https://github.com/puppetlabs/beaker-puppet/compare/4.4.1...4.4.2)
@@ -662,37 +662,49 @@ module Beaker
662
662
  endpoint = 'status/v1/services/puppetdb-status'
663
663
  expected_regex = '\"state\" \{0,\}: \{0,\}\"running\"'
664
664
  end
665
- # The ssl status port is always enabled and is the check this method
666
- # ultimately reports the result of, so use it as the primary
667
- # liveness gate. Checking the nonssl port FIRST (as this method used
668
- # to) meant every host with it disabled -- the default for fresh
669
- # installs as of PE-45384/PE-44906 (SECVULN-1792) -- burned through
670
- # 120 failed retries (~2 minutes, at retry_on's default 1s
671
- # retry_interval) before ever reaching the check that actually
672
- # matters (PE-45697).
673
- result = curl_with_retries('start puppetdb (ssl)',
674
- host, "https://#{host.node_name}:#{ssl_port}", [35, 60])
675
-
676
- # Now that ssl liveness is already confirmed, the nonssl check is
677
- # just a quick, best-effort secondary confirmation: a small retry
678
- # budget is enough, and its absence -- by design, on a host with
679
- # the cleartext listener disabled -- shouldn't fail this method.
680
- nonssl_status_command = "curl -m 1 http://localhost:#{nonssl_port}/#{endpoint} | grep '#{expected_regex}'"
665
+ # Confirm readiness -- not just liveness -- over the ssl status port,
666
+ # which is always enabled. /status/v1/* (and the pre-4.0 /pdb/meta
667
+ # fallback) is allow-unauthenticated and PuppetDB's jetty listener is
668
+ # client-auth=want, so `curl -k` gets a real, content-validated body
669
+ # with no client cert, and it works even when the cleartext listener
670
+ # is disabled by default (PE-45384/PE-44906, SECVULN-1792).
671
+ #
672
+ # PE-45697 could no longer perform this running-state validation once
673
+ # it had to stop relying on the (now disabled-by-default) cleartext
674
+ # port: it fell back to a bare curl_with_retries liveness probe, which
675
+ # only confirms the tls port answers, not that puppetdb reports a
676
+ # running state -- reopening the "port up but not ready" race the
677
+ # nonssl content check used to guard. Restore that check over ssl.
678
+ ssl_status_command = "curl -m 1 -k https://localhost:#{ssl_port}/#{endpoint} | grep '#{expected_regex}'"
681
679
  begin
682
- retry_on(host, nonssl_status_command, { max_retries: 5 })
680
+ result = retry_on(host, ssl_status_command, { max_retries: 60 })
683
681
  rescue RuntimeError => e
684
682
  # Only treat this as the known "exhausted all retries" failure
685
- # retry_on itself raises for THIS command (a plain RuntimeError
686
- # with this exact templated message, see beaker's
683
+ # retry_on itself raises for THIS command (a plain RuntimeError with
684
+ # this exact templated message, see beaker's
687
685
  # Beaker::DSL::Helpers::HostHelpers#retry_on) -- not any other
688
- # RuntimeError, or a same-shaped error for a different command,
689
- # that might surface from deeper in the retry loop (e.g. an
690
- # SSH/connection error from the underlying on() call). Re-raise
691
- # anything else unrecognized rather than silently reclassifying
692
- # it below (PE-45697).
693
- raise unless e.message == "Command `#{nonssl_status_command}` failed."
694
-
695
- logger.warn("sleep_until_puppetdb_started: nonssl status check on port #{nonssl_port} did not succeed (#{e.message}), but ssl status check already confirmed puppetdb is running")
686
+ # RuntimeError, or a same-shaped error for a different command, that
687
+ # might surface from deeper in the retry loop (e.g. an SSH/connection
688
+ # error from the underlying on() call).
689
+ raise unless e.message == "Command `#{ssl_status_command}` failed."
690
+
691
+ # The ssl status endpoint didn't serve unauthenticated content
692
+ # (older or nonstandard config). Degrade to the previous behaviour
693
+ # rather than failing: a bare ssl liveness probe, plus a best-effort
694
+ # nonssl content check whose absence -- by design, on a host with the
695
+ # cleartext listener disabled -- must not fail this method.
696
+ logger.warn("sleep_until_puppetdb_started: ssl status content check did not confirm a running state (#{e.message}); falling back to an ssl liveness probe")
697
+ result = curl_with_retries('start puppetdb (ssl)',
698
+ host, "https://#{host.node_name}:#{ssl_port}", [35, 60])
699
+
700
+ nonssl_status_command = "curl -m 1 http://localhost:#{nonssl_port}/#{endpoint} | grep '#{expected_regex}'"
701
+ begin
702
+ retry_on(host, nonssl_status_command, { max_retries: 5 })
703
+ rescue RuntimeError => nonssl_error
704
+ raise unless nonssl_error.message == "Command `#{nonssl_status_command}` failed."
705
+
706
+ logger.warn("sleep_until_puppetdb_started: nonssl status check on port #{nonssl_port} did not succeed (#{nonssl_error.message}), but ssl liveness was confirmed")
707
+ end
696
708
  end
697
709
 
698
710
  result
@@ -1,3 +1,3 @@
1
1
  module BeakerPuppet
2
- VERSION = '4.4.2'
2
+ VERSION = '4.4.3'
3
3
  end
@@ -1034,96 +1034,119 @@ describe ClassMixedWithDSLHelpers do
1034
1034
  allow(subject).to receive(:version_is_less).and_return(true)
1035
1035
  end
1036
1036
 
1037
- it 'uses the default ports if none given, checking ssl before nonssl' do
1037
+ it 'content-validates over the ssl status port and, on success, never touches the cleartext port' do
1038
1038
  host = hosts[0]
1039
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1040
- expect(subject).to receive(:retry_on).with(anything, /8080/, anything).once.ordered
1041
- subject.sleep_until_puppetdb_started(host)
1042
- end
1043
-
1044
- it 'allows setting the nonssl_port' do
1045
- host = hosts[0]
1046
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1047
- expect(subject).to receive(:retry_on).with(anything, /8084/, anything).once.ordered
1039
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once
1040
+ expect(subject).not_to receive(:curl_with_retries)
1041
+ expect(subject).not_to receive(:retry_on).with(anything, %r{http://localhost:8080/}, anything)
1048
1042
 
1049
- subject.sleep_until_puppetdb_started(host, 8084)
1043
+ subject.sleep_until_puppetdb_started(host)
1050
1044
  end
1051
1045
 
1052
1046
  it 'allows setting the ssl_port' do
1053
1047
  host = hosts[0]
1054
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8085/, anything).once.ordered
1055
- expect(subject).to receive(:retry_on).with(anything, /8080/, anything).once.ordered
1048
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8085/}, { max_retries: 60 }).once
1056
1049
 
1057
1050
  subject.sleep_until_puppetdb_started(host, nil, 8085)
1058
1051
  end
1059
1052
 
1060
- context 'when the cleartext status port never responds (e.g. disabled by default)' do
1061
- it 'swallows the failure once ssl liveness is already confirmed' do
1053
+ context 'when pe_ver is less than 2016.1.0' do
1054
+ it 'content-validates the version endpoint over ssl' do
1062
1055
  host = hosts[0]
1063
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1064
- expect(subject).to receive(:retry_on).with(anything, anything, { max_retries: 5 }).once.ordered do |_host, command, _opts|
1065
- raise "Command `#{command}` failed."
1066
- end
1056
+ host['pe_ver'] = '2015.3.3'
1057
+ expect(subject).to receive(:version_is_less).with(host['pe_ver'], '2016.1.0').and_return(true)
1058
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/pdb/meta/v1/version},
1059
+ { max_retries: 60 }).once
1067
1060
 
1068
- expect { subject.sleep_until_puppetdb_started(host) }.not_to raise_error
1061
+ subject.sleep_until_puppetdb_started(host)
1069
1062
  end
1070
1063
  end
1071
1064
 
1072
- context 'when the ssl check itself fails' do
1073
- it 'raises without ever attempting the nonssl check' do
1065
+ context 'when pe_ver is greater than 2015.9.9' do
1066
+ it 'content-validates the status endpoint over ssl' do
1074
1067
  host = hosts[0]
1075
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once
1076
- .and_raise('Command `curl -m 1 https://.../` failed.')
1077
- expect(subject).not_to receive(:retry_on)
1068
+ host['pe_ver'] = '2016.1.0'
1069
+ expect(subject).to receive(:version_is_less).with(host['pe_ver'], '2016.1.0').and_return(false)
1070
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/status/v1/services/puppetdb-status},
1071
+ { max_retries: 60 }).once
1078
1072
 
1079
- expect { subject.sleep_until_puppetdb_started(host) }.to raise_error(/https/)
1073
+ subject.sleep_until_puppetdb_started(host)
1080
1074
  end
1081
1075
  end
1082
1076
 
1083
- context 'when retry_on raises a RuntimeError unrelated to exhausted retries' do
1084
- it 'propagates the error rather than treating it as a disabled port' do
1077
+ context 'when the ssl status endpoint does not serve unauthenticated content' do
1078
+ # Older/nonstandard configs: degrade to the previous behaviour rather
1079
+ # than failing -- a bare ssl liveness probe plus a best-effort nonssl
1080
+ # content check.
1081
+ it 'falls back to an ssl liveness probe and a nonssl content check' do
1085
1082
  host = hosts[0]
1086
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1087
- expect(subject).to receive(:retry_on).with(anything, /8080/, anything).once.ordered
1088
- .and_raise('Host unreachable: no route to host')
1083
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once.ordered do |_host, command, _opts|
1084
+ raise "Command `#{command}` failed."
1085
+ end
1086
+ expect(subject).to receive(:curl_with_retries).with(anything, anything, %r{https://[^/]*:8081}, [35, 60]).once.ordered
1087
+ expect(subject).to receive(:retry_on).with(anything, %r{http://localhost:8080/}, { max_retries: 5 }).once.ordered
1089
1088
 
1090
- expect { subject.sleep_until_puppetdb_started(host) }.to raise_error(/Host unreachable/)
1089
+ expect { subject.sleep_until_puppetdb_started(host) }.not_to raise_error
1091
1090
  end
1092
- end
1093
1091
 
1094
- context 'when retry_on raises a RuntimeError formatted like the templated failure but for a different command' do
1095
- it 'propagates the error rather than treating it as a disabled port' do
1092
+ it 'allows setting the nonssl_port in the fallback path' do
1096
1093
  host = hosts[0]
1097
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1098
- expect(subject).to receive(:retry_on).with(anything, /8080/, anything).once.ordered
1099
- .and_raise('Command `some other command` failed.')
1094
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once.ordered do |_host, command, _opts|
1095
+ raise "Command `#{command}` failed."
1096
+ end
1097
+ expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, [35, 60]).once.ordered
1098
+ expect(subject).to receive(:retry_on).with(anything, %r{http://localhost:8084/}, { max_retries: 5 }).once.ordered
1100
1099
 
1101
- expect { subject.sleep_until_puppetdb_started(host) }.to raise_error(/some other command/)
1100
+ subject.sleep_until_puppetdb_started(host, 8084)
1101
+ end
1102
+
1103
+ context 'and the cleartext status port never responds (e.g. disabled by default)' do
1104
+ it 'swallows the nonssl failure once ssl liveness is confirmed' do
1105
+ host = hosts[0]
1106
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once.ordered do |_host, command, _opts|
1107
+ raise "Command `#{command}` failed."
1108
+ end
1109
+ expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, [35, 60]).once.ordered
1110
+ expect(subject).to receive(:retry_on).with(anything, %r{http://localhost:8080/}, { max_retries: 5 }).once.ordered do |_host, command, _opts|
1111
+ raise "Command `#{command}` failed."
1112
+ end
1113
+
1114
+ expect { subject.sleep_until_puppetdb_started(host) }.not_to raise_error
1115
+ end
1116
+
1117
+ it 'propagates an unrelated RuntimeError from the nonssl check' do
1118
+ host = hosts[0]
1119
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once.ordered do |_host, command, _opts|
1120
+ raise "Command `#{command}` failed."
1121
+ end
1122
+ expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, [35, 60]).once.ordered
1123
+ expect(subject).to receive(:retry_on).with(anything, %r{http://localhost:8080/}, { max_retries: 5 }).once.ordered
1124
+ .and_raise('Host unreachable: no route to host')
1125
+
1126
+ expect { subject.sleep_until_puppetdb_started(host) }.to raise_error(/Host unreachable/)
1127
+ end
1102
1128
  end
1103
1129
  end
1104
1130
 
1105
- context 'when pe_ver is less than 2016.1.0' do
1106
- it 'uses the version endpoint' do
1131
+ context 'when the ssl content check raises a RuntimeError unrelated to exhausted retries' do
1132
+ it 'propagates the error rather than falling back' do
1107
1133
  host = hosts[0]
1108
- host['pe_ver'] = '2015.3.3'
1109
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1110
- expect(subject).to receive(:retry_on).with(anything, %r{pdb/meta/v1/version}, anything).once.ordered
1134
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once
1135
+ .and_raise('Host unreachable: no route to host')
1136
+ expect(subject).not_to receive(:curl_with_retries)
1111
1137
 
1112
- expect(subject).to receive(:version_is_less).with(host['pe_ver'], '2016.1.0').and_return(true)
1113
- subject.sleep_until_puppetdb_started(host)
1138
+ expect { subject.sleep_until_puppetdb_started(host) }.to raise_error(/Host unreachable/)
1114
1139
  end
1115
1140
  end
1116
1141
 
1117
- context 'when pe_ver is greater than 2015.9.9' do
1118
- it 'uses the status endpoint' do
1142
+ context 'when the ssl content check raises the templated failure but for a different command' do
1143
+ it 'propagates the error rather than falling back' do
1119
1144
  host = hosts[0]
1120
- host['pe_ver'] = '2016.1.0'
1121
- expect(subject).to receive(:curl_with_retries).with(anything, anything, /8081/, anything).once.ordered
1122
- expect(subject).to receive(:retry_on).with(anything, %r{status/v1/services/puppetdb-status},
1123
- anything).once.ordered
1145
+ expect(subject).to receive(:retry_on).with(anything, %r{-k https://localhost:8081/}, { max_retries: 60 }).once
1146
+ .and_raise('Command `some other command` failed.')
1147
+ expect(subject).not_to receive(:curl_with_retries)
1124
1148
 
1125
- expect(subject).to receive(:version_is_less).with(host['pe_ver'], '2016.1.0').and_return(false)
1126
- subject.sleep_until_puppetdb_started(host)
1149
+ expect { subject.sleep_until_puppetdb_started(host) }.to raise_error(/some other command/)
1127
1150
  end
1128
1151
  end
1129
1152
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beaker-puppet
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.2
4
+ version: 4.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vox Pupuli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-12 00:00:00.000000000 Z
11
+ date: 2026-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fakefs