From cc4de7c79b089b4306104c4aaa2c36d6016f1d59 Mon Sep 17 00:00:00 2001 From: atbagan Date: Sun, 30 Aug 2026 21:13:24 -0500 Subject: [PATCH] feat(controller): map konnectivity resources onto the StewardControlPlane addons The new ControlPlaneResourcesSpec.Konnectivity (butler-api v0.24.0) is a Steward addon rather than a top-level control plane component, so it is written into the StewardControlPlane addons block as addons.konnectivity.server.resources. capi-steward copies the addons block onto the TenantControlPlane, which renders the requests onto the konnectivity-server container. Emitted only when set; the merge in ResolveControlPlaneResources carries the per-tenant override. --- go.mod | 2 +- go.sum | 2 + internal/capi/builder.go | 14 +++++ internal/capi/builder_konnectivity_test.go | 66 ++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 internal/capi/builder_konnectivity_test.go diff --git a/go.mod b/go.mod index b930726..a464303 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/butlerdotdev/butler-controller go 1.24.6 require ( - github.com/butlerdotdev/butler-api v0.23.0 + github.com/butlerdotdev/butler-api v0.24.0 github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/gomega v1.36.1 github.com/prometheus/client_golang v1.22.0 diff --git a/go.sum b/go.sum index 2fc0d46..991af69 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/butlerdotdev/butler-api v0.23.0 h1:t6NSgZLg5e7t/xE18yfw1sOrAp3vCfQncYsgbLVCzGQ= github.com/butlerdotdev/butler-api v0.23.0/go.mod h1:q/RjPFM/r2ELq4DqR78OiAxerKBvH5D4nTGsVLKbjqY= +github.com/butlerdotdev/butler-api v0.24.0 h1:37ogSev37Wt4sNcbT1N0QqQ+w0im49+8ONvNMy52hdQ= +github.com/butlerdotdev/butler-api v0.24.0/go.mod h1:q/RjPFM/r2ELq4DqR78OiAxerKBvH5D4nTGsVLKbjqY= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/internal/capi/builder.go b/internal/capi/builder.go index 7420e08..6dd7ac7 100644 --- a/internal/capi/builder.go +++ b/internal/capi/builder.go @@ -545,6 +545,17 @@ func (b *Builder) buildStewardControlPlane(name string) *unstructured.Unstructur if resources.Scheduler != nil { spec["scheduler"] = b.componentResourceMap(resources.Scheduler) } + if resources.Konnectivity != nil { + // Konnectivity is a Steward addon, not a top-level control plane + // component, so its resources go into the addons block. capi-steward + // copies addons onto the TenantControlPlane, which renders them onto + // the konnectivity-server container (addons.konnectivity.server.resources). + addons["konnectivity"] = map[string]interface{}{ + "server": map[string]interface{}{ + "resources": b.componentResourceMap(resources.Konnectivity), + }, + } + } } // Add certSANs if specified @@ -1196,6 +1207,9 @@ func ResolveControlPlaneResources(tc *butlerv1alpha1.TenantCluster, butlerConfig if tcResources.Scheduler != nil { merged.Scheduler = tcResources.Scheduler } + if tcResources.Konnectivity != nil { + merged.Konnectivity = tcResources.Konnectivity + } return merged } diff --git a/internal/capi/builder_konnectivity_test.go b/internal/capi/builder_konnectivity_test.go new file mode 100644 index 0000000..3bea94d --- /dev/null +++ b/internal/capi/builder_konnectivity_test.go @@ -0,0 +1,66 @@ +/* +Copyright 2026 The Butler Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package capi + +import ( + "encoding/json" + "strings" + "testing" + + butlerv1alpha1 "github.com/butlerdotdev/butler-api/api/v1alpha1" + "k8s.io/apimachinery/pkg/api/resource" +) + +// TestBuildStewardControlPlane_Konnectivity verifies konnectivity resources +// (a Steward addon, not a top-level control plane component) are written into +// the StewardControlPlane addons block only when set, so capi-steward can carry +// them to the TenantControlPlane's konnectivity-server. +func TestBuildStewardControlPlane_Konnectivity(t *testing.T) { + pc := newTestProviderConfig("harvester") + qty := func(s string) *resource.Quantity { q := resource.MustParse(s); return &q } + + addonsFor := func(t *testing.T, k *butlerv1alpha1.ComponentResources) map[string]interface{} { + t.Helper() + tc := newTestTenantCluster("cp-konn", "default") + tc.Spec.ControlPlane.Resources = &butlerv1alpha1.ControlPlaneResourcesSpec{Konnectivity: k} + rs, err := NewBuilder(tc, pc, "cp-konn-12345678").Build() + if err != nil { + t.Fatalf("build: %v", err) + } + spec := rs.ControlPlane.Object["spec"].(map[string]interface{}) + return spec["addons"].(map[string]interface{}) + } + + t.Run("omitted keeps konnectivity addon empty", func(t *testing.T) { + konn, _ := addonsFor(t, nil)["konnectivity"].(map[string]interface{}) + if len(konn) != 0 { + t.Fatalf("konnectivity addon should be empty when unset, got %v", konn) + } + }) + + t.Run("explicit maps to addons.konnectivity.server.resources", func(t *testing.T) { + addons := addonsFor(t, &butlerv1alpha1.ComponentResources{ + Requests: &butlerv1alpha1.ResourceQuantities{CPU: qty("10m"), Memory: qty("32Mi")}, + }) + b, _ := json.Marshal(addons["konnectivity"]) + s := string(b) + if !strings.Contains(s, `"server"`) || !strings.Contains(s, `"resources"`) || + !strings.Contains(s, "32Mi") || !strings.Contains(s, "10m") { + t.Fatalf("konnectivity resources not mapped into addons: %s", s) + } + }) +}