| We could protect against the ruby bug for file sources (either puppet or http*):
diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb |
index df8fa95751..8f48f9865b 100644 |
--- a/lib/puppet/type/file/source.rb |
+++ b/lib/puppet/type/file/source.rb |
@@ -323,7 +323,25 @@ module Puppet |
def chunk_file_from_source |
get_from_source do |response| |
case response.code |
- when /^2/; uncompress(response) { |uncompressor| response.read_body { |chunk| yield uncompressor.uncompress(chunk) } } |
+ when /^2/ |
+ truncated = false |
+ uncompress(response) do |uncompressor| |
+ response.read_body do |data| |
+ # If server closes the connection, Ruby will swallow EOFError |
+ # https://bugs.ruby-lang.org/issues/14972 So verify we received |
+ # all of the data as indicated by Content-Length. However, it |
+ # will be omitted when using chunked transfer encoding. |
+ clen = response['Content-Length'] |
+ if clen && clen.to_i != data.length |
+ truncated = true |
+ end |
+ |
+ yield uncompressor.uncompress(data) |
+ end |
+ end |
+ |
+ # Have to raise after `read_body` returns |
+ raise EOFError if truncated |
else |
# Raise the http error if we didn't get a 'success' of some kind. |
message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
|
But it wouldn't solve the other places where we use Net::HTTP like the rest terminus. So patching ruby is preferable. I was also able to reproduce using toxiproxy. Agent, toxiproxy and puppetserver are on one host. Added file resource to site.pp
On the agent, edited {{/etc/hosts}
On the agent:
In other shell on the agent, enabled TCP proxies for puppet and ruby:
$ toxiproxy-cli create puppet -l localhost:8080 -u localhost:8140 |
$ toxiproxy-cli create ruby -l localhost:8888 -u 151.101.193.178:80
|
And added a limit_data toxic to the downstream connection between agent and proxy:
$ toxiproxy-cli t add ruby -t limit_data -a bytes=1000
|
Agent downloads truncated file due to ignored EOF:
$ rm -f /tmp/ruby.tar.gz && bx puppet agent -t --masterport 8080 |
Info: Using configured environment 'production' |
Info: Retrieving pluginfacts |
Info: Retrieving plugin |
Info: Retrieving locales |
Info: Caching catalog for whatcom |
Info: Applying configuration version '1565393439' |
Notice: /Stage[main]/Foo/File[/tmp/ruby.tar.gz]/ensure: defined content as '{mtime}2019-04-17 15:25:09 UTC' (corrective) |
Notice: Applied catalog in 0.12 seconds |
$ ls -la /tmp/ruby.tar.gz |
-rw-r--r-- 1 josh wheel 404B Aug 9 16:30 /tmp/ruby.tar.gz
|
With the patch I get:
rm -f /tmp/ruby.tar.gz && bx puppet agent -t --masterport 8080 |
Info: Using configured environment 'production' |
Info: Retrieving pluginfacts |
Info: Retrieving plugin |
Info: Retrieving locales |
Info: Caching catalog for whatcom |
Info: Applying configuration version '1565393533' |
Error: Could not set 'file' on ensure: EOFError (file: /etc/puppetlabs/code/environments/production/modules/foo/manifests/init.pp, line: 2) |
Error: Could not set 'file' on ensure: EOFError (file: /etc/puppetlabs/code/environments/production/modules/foo/manifests/init.pp, line: 2) |
Wrapped exception: |
EOFError |
Error: /Stage[main]/Foo/File[/tmp/ruby.tar.gz]/ensure: change from 'absent' to 'file' failed: Could not set 'file' on ensure: EOFError (file: /etc/puppetlabs/code/environments/production/modules/foo/manifests/init.pp, line: 2) (corrective) |
Notice: Applied catalog in 0.15 seconds
|
Note the double EOFError is because Net::HTTP silently attempts to retry failed idempotent requests, and it's not configurable until ruby 2.5. See PUP-3905. |