Merge into ~/.kube/config instead of round-tripping it through a model - #88
Merged
Merged
Conversation
One entry the @kubernetes/client-node loader disliked cost the user every user, every context and their current-context. `readExistingConfig()` called `loadFromString`, which throws on an entry that fails its validation - `contexts[i].context.cluster is missing` being the easy one to hit, since that is what `kubectl config set-context <name> --namespace=<ns>` writes. The throw was caught and logged at `debug`, and the half-loaded KubeConfig it left behind (`loadFromOptions` assigns clusters first, so those survive and nothing else does) was then merged into and written over the file. What is left has no current context, so kubectl falls back to localhost:8080 and every call fails. The same round trip was lossy even when it did not throw: the model carries only the fields it knows about, so `preferences`, per-entry `extensions`, `as`/`as-groups`, `disable-compression` and anything kubectl grows later were dropped on every write, while a `token-file` was read and inlined into the file as a bare `token`. So drop the model. `mergeKubeconfig(existing, clusters)` parses the YAML, edits the three lists in place and dumps it back; everything else in the document is handed back untouched. A same-named entry is updated by merge and stays where it is, so a namespace set on one of Frost's contexts survives the next refresh. A file that will not parse is left alone and logged at `error` - skipping an update beats replacing a file we could not read. Unchanged contents skip the write, and `lineWidth: -1` keeps certificate data and the authenticator path on one line, as `aws eks update-kubeconfig` writes them. Also fixes `getNamePattern`'s `uniqueClusters`, which compared the lengths of two lists built by mapping over the same array and so was always true. It now compares distinct cluster names against distinct cluster ids, which is what having both lists was for: two different clusters sharing a name used to collapse onto one context, silently losing one of them. @kubernetes/client-node was used nowhere else, so it and the @types/ws devDep it needed are gone. Verified with kubectl against the generated files: a config carrying a cluster-less context keeps all of its entries through a merge, two clusters sharing a name get two contexts pointing at two endpoints, the exec plugin runs and the CA parses, and a second run is a no-op.
popen2
force-pushed
the
claude/kubectl-frost-config-gen-55ewjv
branch
from
August 30, 2026 06:19
1125340 to
05befa7
Compare
popen2
enabled auto-merge
August 30, 2026 06:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One entry the @kubernetes/client-node loader disliked cost the user every
user, every context and their current-context.
readExistingConfig()calledloadFromString, which throws on an entrythat fails its validation -
contexts[i].context.cluster is missingbeingthe easy one to hit, since that is what
kubectl config set-context <name> --namespace=<ns>writes. The throw was caught and logged atdebug, andthe half-loaded KubeConfig it left behind (
loadFromOptionsassignsclusters first, so those survive and nothing else does) was then merged
into and written over the file. What is left has no current context, so
kubectl falls back to localhost:8080 and every call fails.
The same round trip was lossy even when it did not throw: the model carries
only the fields it knows about, so
preferences, per-entryextensions,as/as-groups,disable-compressionand anything kubectl grows laterwere dropped on every write, while a
token-filewas read and inlined intothe file as a bare
token.So drop the model.
mergeKubeconfig(existing, clusters)parses the YAML,edits the three lists in place and dumps it back; everything else in the
document is handed back untouched. A same-named entry is updated by merge
and stays where it is, so a namespace set on one of Frost's contexts
survives the next refresh. A file that will not parse is left alone and
logged at
error- skipping an update beats replacing a file we could notread. Unchanged contents skip the write, and
lineWidth: -1keepscertificate data and the authenticator path on one line, as
aws eks update-kubeconfigwrites them.Also fixes
getNamePattern'suniqueClusters, which compared the lengthsof two lists built by mapping over the same array and so was always true.
It now compares distinct cluster names against distinct cluster ids, which
is what having both lists was for: two different clusters sharing a name
used to collapse onto one context, silently losing one of them.
@kubernetes/client-node was used nowhere else, so it and the @types/ws
devDep it needed are gone.
Verified with kubectl against the generated files: a config carrying a
cluster-less context keeps all of its entries through a merge, two clusters
sharing a name get two contexts pointing at two endpoints, the exec plugin
runs and the CA parses, and a second run is a no-op.