fix: base62 identifiers produce invalid Kubernetes object names - #437
Merged
Conversation
Base62 (baseconv Digits62) encodes the value 36 as "A", and metadata.name must be a lowercase RFC 1123 subdomain, so BGPVRFInstanceName and BGPAdvertisementName produce names the API server rejects for any identifier carrying an uppercase character. Encode both name segments as the lowercase hex value the base62 identifier represents. Kernel interface names are untouched: base62 exists there for the 15-character limit. internal/gc's kernel-VRF-to-CRD join now encodes the VPC it parsed out of an interface name before matching, and tolerates both the pre-rename and current forms while CRDs written by an older node age out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
privateip
approved these changes
Aug 21, 2026
privateip
added a commit
that referenced
this pull request
Aug 21, 2026
Rebasing this branch onto main picked up #437's base62-to-hex CRD-name encoding, which required updating TestBGPAdvertisementName/ TestTenantIdentifier's expected values in the same conflict resolution. That reintroduced the literal "00G" a third time across this file, tripping golangci-lint's goconst check. Add testAttachmentBase62 alongside the existing testVPC/testVPCBase62/testAttachment fixture constants and use it at both sites. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
What breaks today
Galactic cannot attach a workload to a VPC whose identifier was generated rather than hand-picked.
BGPVRFInstanceandBGPAdvertisementnames interpolate the base62 VPC/attachment identifiers straight intometadata.name, and base62 (baseconvDigits62) encodes the value 36 asA. Kubernetes object names must be lowercase RFC 1123 subdomains, so the API server rejects the CRD and the CNI ADD fails.Nothing has hit this because every identifier in the tree is small and hand-written (
10,20,21). Randomly generated 48-bit VPC identifiers are a different story — roughly 99% of them contain at least one uppercase character (f2a752e6b439renders as1dLaEmCAp), and a controller indatum-cloud/cloudis about to start generating them. This breaks on the first one.The fix
Both name helpers encode each identifier as the lowercase hex value it represents:
Why hex rather than sanitizing base62. Hex is what these identifiers already are everywhere above the kernel —
intf.HexToBase62takes hex in, and base62 exists solely to fitG%09s%03s%sinside the kernel's 15-character interface-name limit, whichmetadata.namedoes not have. It is lowercase by construction, contains no-to confuse the VPC-segment parsing ininternal/gc, and a name can be read straight back against the identifier the API published. Lowercasing base62 instead would collapseA(36) ontoa(10) — two different VPCs, one name.Kernel interface names are unchanged. This PR only touches
metadata.name.An identifier that is not valid base62 at all (nothing in production produces one) is hashed under an
xprefix rather than emitted as an invalid name.Garbage collection
internal/gcdecides whether a kernel VRF is orphaned by matching the base62 VPC in its interface name against the VPC segment of that node'sBGPAdvertisementnames — a cross-domain join that would silently start deleting live VRFs if only one side changed. Both sides now agree, and during an upgrade a VPC is matched under either form, so a CRD written by a not-yet-upgraded node keeps its VRF alive.What operators need to do
Nothing blocking, and nothing in
config/ordeploy/names these objects.Existing
BGPAdvertisement/BGPVRFInstanceobjects keep their old names — they are not renamed in place (a name change is a delete-and-recreate). Live pods keep working: their advertisements stay valid, andgalactic-router's GC collects the old objects once the pods that created them are gone. A rolling node drain, or deleting the stale objects by hand, makes that immediate. The same precedent exists inlegacyVRFNameRegex, which is how this repo handled its previous VRF rename.Tests
New unit tests assert both helpers produce names passing
validation.IsDNS1123Subdomainfor identifiers that contain uppercase (including a real random 48-bit VPC rendering), that the two helpers agree on the VPC segment for a node name containing-, thatAandastay distinct, and that the kernel-VRF-to-CRD join ininternal/gcholds across the upgrade window.go build ./...andgo test ./internal/...were run in a Linux container. Everything in scope passes; the only failures are the pre-existing environmental ones (tests needing/sys/fs/bpf, thevrfmodule,iptablesor netns creation), which fail identically on an unmodified checkout.golangci-lint runis clean for the touched packages.task test:e2e(Kind) was not run.Related
Unblocks generated VPC identifiers, which #17 and #197 both lead to — today every identifier in the tree is hand-picked and small, which is the only reason this has not fired. The first consumer is the VPC controller in datum-cloud/cloud#6.
Not affected by this PR: #332, #329 and #328 concern kernel and allocation state, and kernel interface names are unchanged here.
🤖 Generated with Claude Code