Repository navigation
Conversation
1a6fec3 to
c1cd0b7
Compare
HttpMetadata defaulted to an "{mtime}" checksum of Time.now when the
server sent no usable checksum header (Content-MD5, X-Checksum-*, a
strong ETag with checksum => etag, or Last-Modified). That checksum
changed on every run, so files sourced from such servers, such as
https://github.com/<user>.keys, were rewritten on every run.
When the headers give no checksum, the HTTP file_metadata terminus now
fetches the content and checksums it, using the requested checksum type
when it is a content digest and Puppet[:digest_algorithm] otherwise.
Files are only replaced when their content differs. A HEAD that returns
404 or 500 still returns nil without fetching content.
Fixes OpenVoxProject#581
Assisted-by: Cascade:SWE-1.6 (Devin Desktop)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jo Rhett <geek@jorhett.com>
c1cd0b7 to
2b08f28
Compare
| # that is available from HTTP headers. | ||
| class Puppet::FileServing::HttpMetadata < Puppet::FileServing::Metadata | ||
| # Content digests that can checksum a response body. | ||
| BODY_CHECKSUM_TYPES = [:md5, :sha1, :sha224, :sha256, :sha384, :sha512].freeze |
There was a problem hiding this comment.
Isn't the .freeze redundant because it's a constant?
There was a problem hiding this comment.
No. The constant produces a warning if re-assigned to a different object, but the array object its self is mutable unless explicitly frozen:
https://docs.ruby-lang.org/en/master/language/frozen_objects_md.html#frozen-objects-in-ruby
There was a problem hiding this comment.
FWIW I'd personally be fine either way. I used freeze because it seemed to be used often in more recent changes.
|
FWIW @Sharpie @bastelfreak I wrote the original code with just tab completion. I asked Claude to improve/create new tests. I reviewed and tested everything extensively. This is working on 10k+ nodes right now, which have wide usage of http through file, archive, and even some direct calls in private module Facts. |
|
If I'm reading this correctly, it looks like we would now download the full content and compute the checksum. So, still one downloaded copy when content has not changed on the file server, but two downloaded copies when the file has changed? |
Yes, the second GET comes from the File type's write path which always downloads the content itself. I fought myself on this one and leaned on "smaller patch, limited impact" but we can go the other way if you prefer: the patch would be larger because we have to add conditions to the file resource EtA: perhaps we do the 2nd change to the file resource as a followup PR? 🤔 For some context, we never see these problems on large files. We see them on
So the cost of downloading twice (in every case that I've witnessed) is minimal. |
Short description
This is I believe a more minimal fix for #581 than what is proposed in #582.
Fixes #581
Replaces #582
Root Cause
The
HttpMetadataclass inhttp_metadata.rbwas setting a default mtime checksum usingTime.nowwhen HTTP servers didn't provide checksum headers (Content-MD5, X-Checksum-*, ETag, or Last-Modified). This default now timestamp checksum changed on every run, triggering unnecessary updates.Solution
Time.nowdefault inHttpMetadata#initializefile_metadataterminus now fetches the content and checksums it (HttpMetadata#collect_from_body). It uses the requested checksum type when that is a content digest, andPuppet[:digest_algorithm]otherwise (for example withchecksum => mtime).Impact
Checklist
I have:
Signed-off-byannotation to each of my commitsGenerated-byorAssisted-byannotations to each of my commits created with the help of an AI agentTesting
Tested with agent 8.29.0 against a
fileresource sourced fromhttps://github.com/<user>.keys, which sends only a weak ETag. The stock agent rewrote the file on every run; with this change it was written once and left unchanged on the following runs. A local edit was still restored, and a 404 URL failed the same way as before.Key considerations
I believe this to be a bug/regression and that this fix should be considered for a patch level update. I can find no documentation that says that files should be treated as updated NOW when a timestamp is unavailable, nor that files should always be replaced when timestamp or checksum metadata are unavailable.
I also believe that this would align with user's expectations, such that fixing it in a patch update would be acceptable.
Assisted-by: Cascade:SWE-1.6 (Devin Desktop)
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com