Provider production-hardening: deployable, correct, tested - #1
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-true Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds LoadConfig() reading CLUSTER_NAME from the environment (required), threads the cluster name into instance.Provider, tags every created server with karpenter.sh/cluster=<name>, and filters List() by both the managed-by and cluster labels so two clusters in one Hetzner project cannot see each other's servers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eate tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ches Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… harness Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…set + label-skip Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ync; image-failure test
Without this, CloudProvider.Create rejected every instance type because the custom cpu-type/server-family requirement labels were undefined, breaking all provisioning. Surfaced by cloudprovider Create tests.
…e Create Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r config Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
golangci-lint v1.64.8 (built with go1.24) refused to lint a module targeting go1.26.3. Upgrade to golangci-lint v2 via action@v8 with a v2-format config (gosimple merged into staticcheck), and let go mod tidy settle the go directive to the dependency floor (1.26.2) instead of the spurious 1.26.3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- register HCloudNodeClass into the client-go global scheme in init() so the operator manager (built from scheme.Scheme) can watch it at runtime; this also replaces the deprecated controller-runtime scheme.Builder (SA1019) - applyAvailability: construct a fresh InstanceType instead of copying *it, fixing govet copylocks (InstanceType embeds sync.Once) - drop unused abs() test helper (unused); simplify promoted-field selector (QF1008) - gofmt Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 tasks
3 tasks
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.
Summary
Makes
karpenter-provider-hetzneractually deployable and production-correct (Spec #1 of 4). Design + plan:docs/superpowers/specs/2026-06-13-provider-production-hardening-design.md.Highlights:
make. CRD is generated, committed, and guarded by a CI drift check (make generate-verify).pkg/controllers/nodeclass): validates network, firewalls, and SSH keys exist and resolves the image family per architecture; setsImagesReady/NetworkReady/ResourcesReadyaggregated intoReady(which Karpenter gates provisioning on); populates arch-keyedStatus.ResolvedImages; periodic resync.instance.Create: waits on create actions before returning; maps Hetznerresource_unavailable/resource_limit_exceededto KarpenterInsufficientCapacityErrorso the scheduler falls back to another type/zone.(serverType, location)unavailable for a TTL, applied live perListwithout staleness-trapping the 6h type catalog.enablePublicIPv4/enablePublicIPv6NodeClass flags (default true) so private-network clusters can drop the billed primary IPv4.CLUSTER_NAME(charset-validated), tagged on every server, and filtered inList/GC so two clusters in one Hetzner project never collide.CLUSTER_NAME(fail-fast if unset), metrics/health ports, and liveness/readiness probes.Critical bug fixed
The provider stamped custom requirement labels (
karpenter.hetzner.cloud/cpu-type,/server-family) on instance types but never registered them in Karpenter'sWellKnownLabels— soCreaterejected every instance type for any normal NodeClaim, making provisioning impossible. Surfaced by the new CloudProvider tests; fixed viapkg/apis/v1alpha1/wellknown.go.Test Plan
go build ./...go test -race -count=1 ./...(all 7 packages green)make generate-verify(committed CRD matches types)helm lint+ fail-fast on missingclusterNamegolangci-lint run ./...— runs in CIlintjob (not installed locally)monoHetzner/Talos cluster with cost guardrails — Spec Repo polish: README, contributor docs, issue/PR templates, security tooling #2 (separate)Scope / follow-ups (own specs)
mono+ cost guardrails + Talos node-join contractmitosFirecracker sandboxes🤖 Generated with Claude Code