fix(kyaml): correctly handle patches with a partial compound merge key#6192
fix(kyaml): correctly handle patches with a partial compound merge key#6192SetagGnaw wants to merge 2 commits into
Conversation
|
This PR has multiple commits, and the default merge method is: merge. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: SetagGnaw The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @SetagGnaw. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
1ccac38 to
36c1998
Compare
A strategic merge patch that specifies only part of a compound merge key loses data. With the [port, protocol] merge key for Service ports, a patch that omits protocol: - loses an added field when it matches an existing port and adds a field; - drops the partial entries entirely when several ports are patched and some omit protocol while sharing a port number with a sibling that supplies it (issue 4752); and - fails to update the matching element while leaving the sibling intact when the base holds two elements sharing the port (TCP and UDP). Added to mapTestCases in kyaml/yaml/merge2/map_test.go; all fail against the current merge logic.
kustomize resolves an associative list's merge key to the compound x-kubernetes-list-map-keys (e.g. [port, protocol] for Service ports). A strategic merge patch that specifies only part of that key was mishandled: the partial key could not be re-matched and its data was dropped, or it matched every element sharing the specified component and clobbered a sibling that differs only by another component. Match each element on the key it actually specifies. When it populates the full compound key, use it; otherwise fall back to the single strategic-merge-patch merge key the schema declares (x-kubernetes-patch-merge-key, e.g. port), which is the key the SMP path is meant to use. A merged element is re-keyed on the full key it now populates (elementKeyValues) so it replaces its exact counterpart, and the full compound key is passed to appendListNode. A partial-key patch now merges into a single matching element or appends as distinct; an element that specifies neither the full key nor the SMP key is left alone rather than clobbering an unrelated element.
36c1998 to
85c4e2e
Compare
What this fixes
When a strategic merge patch targets an element of an associative list by only
part of a compound merge key, kustomize loses or corrupts data. With the
[port, protocol]merge key for Service ports ([containerPort, protocol]forcontainer ports), a patch that omits
protocol:some omit
protocolwhile sharing a port number with a sibling that suppliesit (patchesStrategicMerge is not working for service of single port but multiple protocols. #4752); and
base holds two elements sharing the port (e.g.
8080/TCPand8080/UDP).Root cause
kustomize resolves an associative list's merge key to the compound
x-kubernetes-list-map-keys(e.g.[port, protocol]). A patch that specifiesonly part of that key was mishandled in
setAssociativeSequenceElements(
kyaml/yaml/walk/associative_sequence.go): the partial key either could not bere-matched, so the element's data was dropped, or it matched every element
sharing the specified component, clobbering a sibling that differs only by
another component.
The fix
Match each element on the key it actually specifies:
declares for the list (
x-kubernetes-patch-merge-key, e.g.port), which isthe key the SMP path is meant to use.
A merged element is then re-keyed on the full key it now populates
(
elementKeyValues) so it replaces its exact counterpart instead of everyelement sharing the partial key, and the full compound key is passed to
appendListNode.Net behavior: a partial-key patch merges into a single matching element (or
appends as a distinct element when none match), and same-port siblings are
preserved rather than clobbered or duplicated.
Testing
Three cases added to
TestMergeinkyaml/yaml/merge2/map_test.go, all failingbefore the fix and passing after:
port patch adds a field but omits protocol (partial compound key)patch with multiple ports, some omitting protocol (#4752)partial-key patch when base has two elements sharing the port (ambiguous)go test ./yaml/merge2/...and the fullkyamlsuite pass. Two-commitbug-fix convention: the first commit adds the failing tests, the second applies
the fix.
Related issues
Fixes #4752
containerPort,protocolcompound (list) merge key(implemented in use merge key list instead of a single merge key #3159, shipped v3.8.7); this PR fixes data-loss and clobbering
bugs in that merge path.