openvox 8.29.0 → 8.31.0
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 +4 -4
- data/CHANGELOG.md +38 -0
- data/Gemfile +1 -1
- data/Rakefile +1 -1
- data/lib/puppet/agent.rb +79 -7
- data/lib/puppet/face/epp.rb +1 -1
- data/lib/puppet/face/parser.rb +1 -1
- data/lib/puppet/indirector/facts/facter.rb +13 -12
- data/lib/puppet/pal/json_catalog_encoder.rb +1 -1
- data/lib/puppet/pops/evaluator/deferred_resolver.rb +4 -1
- data/lib/puppet/reference/metaparameter.rb +1 -1
- data/lib/puppet/util/json.rb +15 -3
- data/lib/puppet/version.rb +1 -1
- data/tasks/vox.rake +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ece318da56b45d387a1226f12d25f99701b1aec5c8bd24c14bfe56db28b9e664
|
|
4
|
+
data.tar.gz: a4b801c632d5c9299c7d292184f184aa153372f5c9e6a8b695a43a56d7affa76
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 317ad75eebd895d0f718250404861d3090a32569a73b4ca8afe3f09f1ce3440399d99bf0b36eb4199e364f9ffeb592a82cac37ffae59ec0c21d943eb467fcfab
|
|
7
|
+
data.tar.gz: 4b968c2474e46628e7e06d9937de4d4e7cb3738436c3353491fd9ba2b2ef2ea6624215a9c6e0bfc0a9e8599f0f486f86cd6729878107b113952adef2e16a2123
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [8.31.0](https://github.com/openvoxproject/openvox/tree/8.31.0) (2026-10-12)
|
|
6
|
+
|
|
7
|
+
[Full Changelog](https://github.com/openvoxproject/openvox/compare/8.30.0...8.31.0)
|
|
8
|
+
|
|
9
|
+
**Implemented enhancements:**
|
|
10
|
+
|
|
11
|
+
- \[Backport 8.x\] Port Puppet::Util::Json to the json 3 API [\#721](https://github.com/OpenVoxProject/openvox/pull/721) ([miharp](https://github.com/miharp))
|
|
12
|
+
|
|
13
|
+
**Merged pull requests:**
|
|
14
|
+
|
|
15
|
+
- Promote puppet-runtime 2026.10.12.2 into 8.x [\#723](https://github.com/OpenVoxProject/openvox/pull/723) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
16
|
+
|
|
17
|
+
## [8.30.0](https://github.com/openvoxproject/openvox/tree/8.30.0) (2026-10-07)
|
|
18
|
+
|
|
19
|
+
[Full Changelog](https://github.com/openvoxproject/openvox/compare/8.29.0...8.30.0)
|
|
20
|
+
|
|
21
|
+
**Fixed bugs:**
|
|
22
|
+
|
|
23
|
+
- \[Bug\]: use of "server\_list" \(instead of server\) throws an error [\#658](https://github.com/OpenVoxProject/openvox/issues/658)
|
|
24
|
+
- \[Bug\]: Ruby crashes on child side of fork pre-exec macOS 26 \(Tahoe\) [\#538](https://github.com/OpenVoxProject/openvox/issues/538)
|
|
25
|
+
- \[Backport 8.x\] Pin json below 3 to unblock CI [\#676](https://github.com/OpenVoxProject/openvox/pull/676) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
26
|
+
- \[backport 8.x\] fix: `Deferred` resolution of Puppet-language functions \(e.g. mocks in tests\) failing due to lack of `:global_scope` [\#671](https://github.com/OpenVoxProject/openvox/pull/671) ([griggi-ws](https://github.com/griggi-ws))
|
|
27
|
+
- \[Backport 8.x\] print "Loading facts" just once [\#663](https://github.com/OpenVoxProject/openvox/pull/663) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
28
|
+
|
|
29
|
+
**Closed issues:**
|
|
30
|
+
|
|
31
|
+
- json 3.0.0 breaks Puppet::Util::Json and the test suite [\#654](https://github.com/OpenVoxProject/openvox/issues/654)
|
|
32
|
+
|
|
33
|
+
**Merged pull requests:**
|
|
34
|
+
|
|
35
|
+
- \[Backport 8.x\] Skip the tests that need jruby-openssl in FIPS mode [\#714](https://github.com/OpenVoxProject/openvox/pull/714) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
36
|
+
- Promote openfact 5.7.2 into 8.x [\#711](https://github.com/OpenVoxProject/openvox/pull/711) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
37
|
+
- Promote puppet-runtime 2026.09.29.1 into 8.x [\#704](https://github.com/OpenVoxProject/openvox/pull/704) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
38
|
+
- \[Backport 8.x\] Kill the forked agent run if it outlives runtimeout [\#698](https://github.com/OpenVoxProject/openvox/pull/698) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
39
|
+
- \[Backport 8.x\] Wait for certificates in the forked child, not in the daemon [\#697](https://github.com/OpenVoxProject/openvox/pull/697) ([nmburgan](https://github.com/nmburgan))
|
|
40
|
+
- openfact: Update 5.7.0 -\> 5.7.1 [\#678](https://github.com/OpenVoxProject/openvox/pull/678) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
41
|
+
- \[Backport 8.x\] Proper markdown for alias reference documentation. [\#650](https://github.com/OpenVoxProject/openvox/pull/650) ([OpenVoxProjectBot](https://github.com/OpenVoxProjectBot))
|
|
42
|
+
|
|
5
43
|
## [8.29.0](https://github.com/openvoxproject/openvox/tree/8.29.0) (2026-09-04)
|
|
6
44
|
|
|
7
45
|
[Full Changelog](https://github.com/openvoxproject/openvox/compare/8.28.1...8.29.0)
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
|
@@ -159,7 +159,7 @@ begin
|
|
|
159
159
|
HEADER
|
|
160
160
|
config.user = "openvoxproject"
|
|
161
161
|
config.project = "openvox"
|
|
162
|
-
config.exclude_labels = %w[dependencies duplicate question invalid wontfix wont-fix modulesync skip-changelog]
|
|
162
|
+
config.exclude_labels = %w[dependencies duplicate question invalid wontfix wont-fix modulesync skip-changelog skip-8.x-changelog]
|
|
163
163
|
config.since_tag = "8.18.1"
|
|
164
164
|
config.future_release = Puppet::PUPPETVERSION
|
|
165
165
|
config.exclude_tags_regex = /\A[7,9]\./
|
data/lib/puppet/agent.rb
CHANGED
|
@@ -22,6 +22,12 @@ class Puppet::Agent
|
|
|
22
22
|
class RunTimeoutError < Exception # rubocop:disable Lint/InheritException
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
# Exit status the forked child uses to tell the daemon that the SSL state
|
|
26
|
+
# machine gave up waiting for a certificate, so the daemon can exit as it
|
|
27
|
+
# did when the wait happened in the parent. Must not collide with the
|
|
28
|
+
# detailed exit codes returned by a run (0, 1, 2, 4, 6) or with 254 (NoMemoryError).
|
|
29
|
+
CERTIFICATE_FAILURE_EXIT_STATUS = 253
|
|
30
|
+
|
|
25
31
|
attr_reader :client_class, :client, :should_fork
|
|
26
32
|
|
|
27
33
|
def initialize(client_class, should_fork = true)
|
|
@@ -60,12 +66,28 @@ class Puppet::Agent
|
|
|
60
66
|
end
|
|
61
67
|
end
|
|
62
68
|
|
|
63
|
-
# waiting for certs may sleep for awhile depending on onetime, waitforcert and maxwaitforcert!
|
|
64
|
-
# this needs to happen before forking so that if we fail to obtain certs and try to exit, then
|
|
65
|
-
# we exit the main process and not the forked child.
|
|
66
|
-
ssl_context = wait_for_certificates(client_options)
|
|
67
|
-
|
|
68
69
|
result = run_in_fork(should_fork) do
|
|
70
|
+
# waiting for certs may sleep for awhile depending on onetime, waitforcert and maxwaitforcert!
|
|
71
|
+
#
|
|
72
|
+
# This happens in the forked child, not in the long-lived daemon. Refreshing
|
|
73
|
+
# the CRL or renewing the certificate resolves the server's name, and on
|
|
74
|
+
# Ruby 3.3+ that runs in short-lived native threads. If the daemon forks
|
|
75
|
+
# while one of those threads is exiting, the child inherits glibc's
|
|
76
|
+
# resolv.conf lock in the locked state and every name lookup in the run
|
|
77
|
+
# hangs (#485). Keeping the lookups out of the parent avoids that.
|
|
78
|
+
#
|
|
79
|
+
# The state machine calls exit when it gives up waiting for a certificate
|
|
80
|
+
# (waitforcert 0 or maxwaitforcert exceeded). Report that back so the
|
|
81
|
+
# daemon exits, as it did when the wait happened in the parent.
|
|
82
|
+
begin
|
|
83
|
+
ssl_context = wait_for_certificates(client_options)
|
|
84
|
+
rescue SystemExit
|
|
85
|
+
next CERTIFICATE_FAILURE_EXIT_STATUS
|
|
86
|
+
rescue StandardError => detail
|
|
87
|
+
Puppet.log_exception(detail, _("Could not obtain certificates: %{detail}") % { detail: detail })
|
|
88
|
+
next nil
|
|
89
|
+
end
|
|
90
|
+
|
|
69
91
|
with_client(client_options[:transaction_uuid], client_options[:job_id]) do |client|
|
|
70
92
|
client_args = client_options.merge(:pluginsync => Puppet::Configurer.should_pluginsync?)
|
|
71
93
|
begin
|
|
@@ -115,6 +137,9 @@ class Puppet::Agent
|
|
|
115
137
|
end
|
|
116
138
|
end
|
|
117
139
|
end
|
|
140
|
+
# The child could not obtain a certificate and the state machine asked to exit.
|
|
141
|
+
exit(1) if result == CERTIFICATE_FAILURE_EXIT_STATUS
|
|
142
|
+
|
|
118
143
|
true
|
|
119
144
|
end
|
|
120
145
|
Puppet.notice _("Shutdown/restart in progress (%{status}); skipping run") % { status: Puppet::Application.run_status.inspect } unless block_run
|
|
@@ -146,8 +171,55 @@ class Puppet::Agent
|
|
|
146
171
|
atForkHandler.parent
|
|
147
172
|
end
|
|
148
173
|
|
|
149
|
-
|
|
150
|
-
|
|
174
|
+
_, status = wait_for_child(child_pid)
|
|
175
|
+
status.exitstatus
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Wait for the forked child to exit. The child enforces `runtimeout` on its
|
|
179
|
+
# own run, but it may fail to exit afterwards (a stranded thread, a hung
|
|
180
|
+
# subprocess, etc.). Without a deadline here, the parent blocks forever and
|
|
181
|
+
# the agent stops checking in. Once the run timeout plus a grace period has
|
|
182
|
+
# elapsed, the child is killed so the daemon can carry on.
|
|
183
|
+
def wait_for_child(child_pid)
|
|
184
|
+
deadline = child_deadline
|
|
185
|
+
return Process.waitpid2(child_pid) unless deadline
|
|
186
|
+
|
|
187
|
+
loop do
|
|
188
|
+
result = Process.waitpid2(child_pid, Process::WNOHANG)
|
|
189
|
+
return result if result
|
|
190
|
+
|
|
191
|
+
if monotonic_now >= deadline
|
|
192
|
+
Puppet.err _("Agent run (pid %{pid}) did not exit within %{timeout} seconds of the run timeout, killing it") %
|
|
193
|
+
{ pid: child_pid, timeout: child_grace_period }
|
|
194
|
+
begin
|
|
195
|
+
Process.kill(:KILL, child_pid)
|
|
196
|
+
rescue Errno::ESRCH
|
|
197
|
+
# The child exited between the last check and the kill.
|
|
198
|
+
end
|
|
199
|
+
return Process.waitpid2(child_pid)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
sleep 1
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# After the run timeout fires inside the child, it may still need to send
|
|
207
|
+
# its report, which is bounded by the HTTP connect and read timeouts.
|
|
208
|
+
def child_grace_period
|
|
209
|
+
Puppet[:http_connect_timeout] + Puppet[:http_read_timeout]
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Returns the absolute monotonic deadline for the child, or nil when
|
|
213
|
+
# `runtimeout` is disabled.
|
|
214
|
+
def child_deadline
|
|
215
|
+
runtimeout = Puppet[:runtimeout]
|
|
216
|
+
return nil if runtimeout.nil? || runtimeout <= 0
|
|
217
|
+
|
|
218
|
+
monotonic_now + runtimeout + child_grace_period
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def monotonic_now
|
|
222
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
151
223
|
end
|
|
152
224
|
|
|
153
225
|
private
|
data/lib/puppet/face/epp.rb
CHANGED
|
@@ -384,7 +384,7 @@ Puppet::Face.define(:epp, '0.0.1') do
|
|
|
384
384
|
pn = Puppet::Pops::Model::PNTransformer.transform(parse_result)
|
|
385
385
|
case fmt
|
|
386
386
|
when 'json'
|
|
387
|
-
options[:pretty] ? JSON.
|
|
387
|
+
options[:pretty] ? JSON.pretty_generate(pn.to_data) : JSON.dump(pn.to_data)
|
|
388
388
|
else
|
|
389
389
|
pn.format(options[:pretty] ? Puppet::Pops::PN::Indent.new(' ') : nil, output)
|
|
390
390
|
end
|
data/lib/puppet/face/parser.rb
CHANGED
|
@@ -194,7 +194,7 @@ Puppet::Face.define(:parser, '0.0.1') do
|
|
|
194
194
|
pn = Puppet::Pops::Model::PNTransformer.transform(parse_result)
|
|
195
195
|
case fmt
|
|
196
196
|
when 'json'
|
|
197
|
-
options[:pretty] ? JSON.
|
|
197
|
+
options[:pretty] ? JSON.pretty_generate(pn.to_data) : JSON.dump(pn.to_data)
|
|
198
198
|
else
|
|
199
199
|
pn.format(options[:pretty] ? Puppet::Pops::PN::Indent.new(' ') : nil, output)
|
|
200
200
|
end
|
|
@@ -62,21 +62,22 @@ class Puppet::Node::Facts::Facter < Puppet::Indirector::Code
|
|
|
62
62
|
end
|
|
63
63
|
end.flatten + Puppet[:factpath].split(File::PATH_SEPARATOR)
|
|
64
64
|
|
|
65
|
-
dirs
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
dirs.select! { |dir| FileTest.directory?(dir) }
|
|
66
|
+
|
|
67
|
+
# Even though we no longer directly load facts in the terminus,
|
|
68
|
+
# print out each .rb in the facts directory as module
|
|
69
|
+
# developers may find that information useful for debugging purposes
|
|
70
|
+
unless dirs.empty?
|
|
71
|
+
Puppet.info _("Loading facts")
|
|
72
|
+
if Puppet::Util::Log.sendlevel?(:debug)
|
|
73
|
+
dirs.each do |dir|
|
|
74
|
+
Dir.glob("#{dir}/*.rb").each do |file|
|
|
75
|
+
Puppet.debug { "Loading facts from #{file}" }
|
|
76
|
+
end
|
|
75
77
|
end
|
|
76
78
|
end
|
|
77
|
-
|
|
78
|
-
true
|
|
79
79
|
end
|
|
80
|
+
|
|
80
81
|
dirs << request.options[:custom_dir] if request.options[:custom_dir]
|
|
81
82
|
Puppet.runtime[:facter].search(*dirs)
|
|
82
83
|
end
|
|
@@ -58,7 +58,7 @@ class JsonCatalogEncoder
|
|
|
58
58
|
r = possibly_filtered_catalog.resource(type, title)
|
|
59
59
|
return nil if r.nil?
|
|
60
60
|
|
|
61
|
-
r.to_data_hash
|
|
61
|
+
Puppet::Util::Json.dump(r.to_data_hash, :pretty => pretty)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Applies a filter for virtual resources and returns filtered catalog
|
|
@@ -48,7 +48,10 @@ class DeferredResolver
|
|
|
48
48
|
# # Server facts are always about the local node's version etc.
|
|
49
49
|
# @scope.set_server_facts(node.server_facts)
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
# Must be wrapped in with_context_overrides to ensure global_scope is valid for Puppet-language functions
|
|
52
|
+
compiler.with_context_overrides do
|
|
53
|
+
resolver.resolve_futures(catalog)
|
|
54
|
+
end
|
|
52
55
|
nil
|
|
53
56
|
end
|
|
54
57
|
|
data/lib/puppet/util/json.rb
CHANGED
|
@@ -18,6 +18,14 @@ module Puppet::Util
|
|
|
18
18
|
|
|
19
19
|
require 'json'
|
|
20
20
|
|
|
21
|
+
# Generator options equivalent to the `JSON::PRETTY_STATE_PROTOTYPE`
|
|
22
|
+
# that json 2.x provided and json 3 removed.
|
|
23
|
+
PRETTY_OPTIONS = { :indent => ' ', :space => ' ', :object_nl => "\n", :array_nl => "\n" }.freeze
|
|
24
|
+
|
|
25
|
+
# Generator options that json 3 rejects as unknown. `quirks_mode` has been
|
|
26
|
+
# a no-op since json 2.0, when quirks mode became the only mode.
|
|
27
|
+
OBSOLETE_DUMP_OPTIONS = [:quirks_mode].freeze
|
|
28
|
+
|
|
21
29
|
# Load the content from a file as JSON if
|
|
22
30
|
# contents are in valid format. This method does not
|
|
23
31
|
# raise error but returns `nil` when invalid file is
|
|
@@ -41,16 +49,20 @@ module Puppet::Util
|
|
|
41
49
|
def self.load(string, options = {})
|
|
42
50
|
string = string.read if string.respond_to?(:read)
|
|
43
51
|
|
|
52
|
+
options = options.dup
|
|
44
53
|
options[:symbolize_names] = true if options.delete(:symbolize_keys)
|
|
45
|
-
|
|
54
|
+
# json 3 only accepts parser options as keyword arguments
|
|
55
|
+
::JSON.parse(string, **options)
|
|
46
56
|
rescue JSON::ParserError => e
|
|
47
57
|
raise Puppet::Util::Json::ParseError.build(e, string)
|
|
48
58
|
end
|
|
49
59
|
|
|
50
60
|
def self.dump(object, options = {})
|
|
51
61
|
# Options is a state when we're being called recursively
|
|
52
|
-
|
|
53
|
-
options.
|
|
62
|
+
unless options.is_a?(JSON::State)
|
|
63
|
+
options = options.dup
|
|
64
|
+
OBSOLETE_DUMP_OPTIONS.each { |key| options.delete(key) }
|
|
65
|
+
options.merge!(PRETTY_OPTIONS) if options.delete(:pretty)
|
|
54
66
|
end
|
|
55
67
|
object.to_json(options)
|
|
56
68
|
end
|
data/lib/puppet/version.rb
CHANGED
data/tasks/vox.rake
CHANGED
|
@@ -9,8 +9,8 @@ namespace :vox do
|
|
|
9
9
|
puts "Setting version to #{version}"
|
|
10
10
|
|
|
11
11
|
data = File.read('lib/puppet/version.rb')
|
|
12
|
-
new_data = data.sub(/PUPPETVERSION = '\d+\.\d+\.\d+(
|
|
13
|
-
|
|
12
|
+
new_data = data.sub(/PUPPETVERSION = '\d+\.\d+\.\d+(-(alpha|beta|rc)\d+)?'/, "PUPPETVERSION = '#{version}'")
|
|
13
|
+
fail 'Failed to update version in lib/puppet/version.rb' if data == new_data
|
|
14
14
|
|
|
15
15
|
File.write('lib/puppet/version.rb', new_data)
|
|
16
16
|
end
|