From 55f193da6028b3fc7133a26d4d2c982c8d59bdac Mon Sep 17 00:00:00 2001 From: Benny Zlotnik Date: Tue, 1 Sep 2026 11:29:53 +0300 Subject: [PATCH 1/2] ci: add go fix check to controller lint job Runs `go fix ./...` in controller and fails the job if it finds anything to rewrite, catching outdated API usage without letting CI silently modify checked-out code. Signed-off-by: Benny Zlotnik --- .github/workflows/lint.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 49df92ed2..f9a0d1e53 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -57,6 +57,13 @@ jobs: go-version-file: .go-version cache-dependency-path: "**/go.sum" + - name: Run go fix + working-directory: controller + run: | + go fix ./... + (cd deploy/operator && go fix ./...) + git diff --exit-code + - name: Run go linter working-directory: controller run: make lint From ade3c28373b17c542c7fd1f075818d34678ee56b Mon Sep 17 00:00:00 2001 From: Benny Zlotnik Date: Tue, 1 Sep 2026 11:29:57 +0300 Subject: [PATCH 2/2] chore(controller): apply go fix modernizations Rewrites flagged by `go fix ./...`: interface{} -> any, for-range-int loops, maps.Copy for map copies, sync.WaitGroup.Go, and ptr.To(x) -> new(x). Verified with go build, go vet, and make test (all pass). Signed-off-by: Benny Zlotnik --- .../api/v1alpha1/client_helpers_test.go | 2 +- controller/api/v1alpha1/exporter_helpers.go | 3 +- .../api/v1alpha1/exporter_helpers_test.go | 7 +-- controller/api/v1alpha1/lease_helpers.go | 16 +++---- controller/api/v1alpha1/lease_helpers_test.go | 4 +- controller/cmd/router/metrics_test.go | 4 +- .../controller/jumpstarter/certificates.go | 15 ++---- .../jumpstarter/endpoints/discovery_test.go | 4 +- .../controller/jumpstarter/endpoints/route.go | 5 +- .../controller/jumpstarter/exporterset.go | 11 ++--- .../jumpstarter/exporterset_test.go | 22 ++++----- .../jumpstarter/jumpstarter_controller.go | 41 ++++++++-------- .../jumpstarter_controller_test.go | 12 +++-- .../controller/jumpstarter/telemetry.go | 11 ++--- .../controller/jumpstarter/telemetry_test.go | 3 +- .../internal/controller/testutils/envtest.go | 2 +- .../deploy/operator/internal/utils/utils.go | 10 ++-- .../deploy/operator/test/e2e/e2e_test.go | 8 ++-- .../deploy/operator/test/utils/utils.go | 4 +- controller/go.mod | 2 +- controller/internal/authorization/basic.go | 3 +- controller/internal/config/types.go | 12 ++--- .../internal/controller/client_controller.go | 2 +- .../controller/exporter_controller.go | 2 +- .../internal/controller/lease_controller.go | 2 +- controller/internal/exporterset/disk/disk.go | 12 ++--- .../internal/exporterset/disk/disk_test.go | 47 +++++++++---------- .../internal/exporterset/exporterconfig.go | 6 +-- .../exporterset/exporterconfig_test.go | 4 +- .../exporterset_controller_test.go | 4 +- .../internal/exporterset/provisioner.go | 4 +- .../provisioners/qemu/enrich_test.go | 40 ++++++++-------- .../exporterset/provisioners/qemu/qemu.go | 32 ++++++------- .../provisioners/qemu/qemu_test.go | 8 ++-- controller/internal/exporterset/reconciler.go | 34 ++++++-------- .../internal/exporterset/reconciler_test.go | 36 +++++++------- controller/internal/log/levels.go | 12 ++--- controller/internal/metrics/lease.go | 2 +- controller/internal/oidc/op.go | 4 +- .../service/controller_service_test.go | 44 ++++++++--------- .../internal/service/dashboard_service.go | 2 +- controller/internal/service/login/service.go | 2 +- controller/test/utils/utils.go | 4 +- 43 files changed, 231 insertions(+), 273 deletions(-) diff --git a/controller/api/v1alpha1/client_helpers_test.go b/controller/api/v1alpha1/client_helpers_test.go index aa3301a25..0455cb9dd 100644 --- a/controller/api/v1alpha1/client_helpers_test.go +++ b/controller/api/v1alpha1/client_helpers_test.go @@ -74,7 +74,7 @@ func TestClient_Usernames(t *testing.T) { t.Run("with custom username", func(t *testing.T) { c := &Client{ ObjectMeta: metav1.ObjectMeta{Name: "my-client", Namespace: "default", UID: types.UID("123")}, - Spec: ClientSpec{Username: stringPtr("custom-user")}, + Spec: ClientSpec{Username: new("custom-user")}, } got := c.Usernames("internal:") if len(got) != 2 || got[1] != "custom-user" { diff --git a/controller/api/v1alpha1/exporter_helpers.go b/controller/api/v1alpha1/exporter_helpers.go index ac1f51150..68c78d440 100644 --- a/controller/api/v1alpha1/exporter_helpers.go +++ b/controller/api/v1alpha1/exporter_helpers.go @@ -6,7 +6,6 @@ import ( cpb "github.com/jumpstarter-dev/jumpstarter/controller/internal/protocol/jumpstarter/client/v1" pb "github.com/jumpstarter-dev/jumpstarter/controller/internal/protocol/jumpstarter/v1" "github.com/jumpstarter-dev/jumpstarter/controller/internal/service/utils" - "google.golang.org/protobuf/proto" "k8s.io/apimachinery/pkg/api/meta" kclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -42,7 +41,7 @@ func (e *Exporter) ToProtobuf() *cpb.Exporter { Online: isOnline, //nolint:staticcheck // populated for older clients still reading this field Status: stringToProtoStatus(e.Status.ExporterStatusValue), StatusMessage: e.Status.StatusMessage, - Enabled: proto.Bool(e.IsEnabled()), + Enabled: new(e.IsEnabled()), } } diff --git a/controller/api/v1alpha1/exporter_helpers_test.go b/controller/api/v1alpha1/exporter_helpers_test.go index 9c7e47a49..8c9dba18e 100644 --- a/controller/api/v1alpha1/exporter_helpers_test.go +++ b/controller/api/v1alpha1/exporter_helpers_test.go @@ -74,7 +74,7 @@ func TestExporter_Usernames(t *testing.T) { t.Run("with custom username", func(t *testing.T) { e := &Exporter{ ObjectMeta: metav1.ObjectMeta{Name: "my-exporter", Namespace: "default", UID: types.UID("123")}, - Spec: ExporterSpec{Username: stringPtr("custom-user")}, + Spec: ExporterSpec{Username: new("custom-user")}, } got := e.Usernames("internal:") if len(got) != 2 || got[1] != "custom-user" { @@ -82,8 +82,3 @@ func TestExporter_Usernames(t *testing.T) { } }) } - -// Helper function to create string pointers -func stringPtr(s string) *string { - return &s -} diff --git a/controller/api/v1alpha1/lease_helpers.go b/controller/api/v1alpha1/lease_helpers.go index 569e109d0..f4c007001 100644 --- a/controller/api/v1alpha1/lease_helpers.go +++ b/controller/api/v1alpha1/lease_helpers.go @@ -3,6 +3,7 @@ package v1alpha1 import ( "context" "fmt" + "maps" "slices" "strings" "time" @@ -19,7 +20,6 @@ import ( "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/utils/ptr" kclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" ) @@ -239,18 +239,14 @@ func LeaseFromProtobuf( var specTags map[string]string if len(req.Tags) > 0 { specTags = make(map[string]string, len(req.Tags)) - for k, v := range req.Tags { - specTags[k] = v - } + maps.Copy(specTags, req.Tags) } // Store user context in spec var specContext map[string]string if len(req.Context) > 0 { specContext = make(map[string]string, len(req.Context)) - for k, v := range req.Context { - specContext[k] = v - } + maps.Copy(specContext, req.Context) } return &Lease{ @@ -297,14 +293,14 @@ func (l *Lease) ToProtobuf() *cpb.Lease { lease := cpb.Lease{ Name: fmt.Sprintf("namespaces/%s/leases/%s", l.Namespace, l.Name), Selector: metav1.FormatLabelSelector(&l.Spec.Selector), - Client: ptr.To(fmt.Sprintf("namespaces/%s/clients/%s", l.Namespace, l.Spec.ClientRef.Name)), + Client: new(fmt.Sprintf("namespaces/%s/clients/%s", l.Namespace, l.Spec.ClientRef.Name)), Conditions: conditions, Tags: l.Spec.Tags, AllowDisabled: l.Spec.AllowDisabled, Context: l.Spec.Context, } if l.Spec.ExporterRef != nil { - lease.ExporterName = ptr.To(l.Spec.ExporterRef.Name) + lease.ExporterName = new(l.Spec.ExporterRef.Name) } if l.Spec.Duration != nil { lease.Duration = durationpb.New(l.Spec.Duration.Duration) @@ -331,7 +327,7 @@ func (l *Lease) ToProtobuf() *cpb.Lease { lease.EffectiveDuration = durationpb.New(effectiveDuration) } if l.Status.ExporterRef != nil { - lease.Exporter = ptr.To(utils.UnparseExporterIdentifier(kclient.ObjectKey{ + lease.Exporter = new(utils.UnparseExporterIdentifier(kclient.ObjectKey{ Namespace: l.Namespace, Name: l.Status.ExporterRef.Name, })) diff --git a/controller/api/v1alpha1/lease_helpers_test.go b/controller/api/v1alpha1/lease_helpers_test.go index 437e97e1f..b814510bd 100644 --- a/controller/api/v1alpha1/lease_helpers_test.go +++ b/controller/api/v1alpha1/lease_helpers_test.go @@ -447,7 +447,7 @@ var _ = Describe("ValidateLeaseTags", func() { It("should reject more than 10 tags", func() { tags := make(map[string]string) - for i := 0; i < 11; i++ { + for i := range 11 { tags[fmt.Sprintf("key%d", i)] = "value" } err := ValidateLeaseTags(tags, 10) @@ -522,7 +522,7 @@ var _ = Describe("ValidateLeaseTags", func() { It("should accept exactly 10 tags", func() { tags := make(map[string]string) - for i := 0; i < 10; i++ { + for i := range 10 { tags[fmt.Sprintf("key%d", i)] = "value" } Expect(ValidateLeaseTags(tags, 10)).To(Succeed()) diff --git a/controller/cmd/router/metrics_test.go b/controller/cmd/router/metrics_test.go index 3cec99fe5..69fefbe5b 100644 --- a/controller/cmd/router/metrics_test.go +++ b/controller/cmd/router/metrics_test.go @@ -48,7 +48,7 @@ func TestMetricsEndpointServesPrometheusText(t *testing.T) { client := &http.Client{Timeout: 2 * time.Second} var resp *http.Response var lastErr error - for i := 0; i < 20; i++ { + for range 20 { resp, lastErr = client.Get("http://" + addr + "/metrics") if lastErr == nil { break @@ -135,7 +135,7 @@ func TestMetricsServerShutdown(t *testing.T) { client := &http.Client{Timeout: 2 * time.Second} var lastErr error - for i := 0; i < 20; i++ { + for range 20 { var resp *http.Response resp, lastErr = client.Get("http://" + addr + "/metrics") if lastErr == nil { diff --git a/controller/deploy/operator/internal/controller/jumpstarter/certificates.go b/controller/deploy/operator/internal/controller/jumpstarter/certificates.go index d86d14889..8106b062c 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/certificates.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/certificates.go @@ -19,7 +19,9 @@ package jumpstarter import ( "context" "fmt" + "maps" "net" + "slices" "time" certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" @@ -294,7 +296,7 @@ func (r *JumpstarterReconciler) reconcileServerCertificate( adjustedRenewBefore := renewBefore if renewBefore >= certDuration { adjustedRenewBefore = certDuration / 2 - logFields := []interface{}{ + logFields := []any{ "component", component, "configured", renewBefore, "certDuration", certDuration, @@ -309,9 +311,7 @@ func (r *JumpstarterReconciler) reconcileServerCertificate( "app.kubernetes.io/managed-by": "jumpstarter-operator", "component": component, } - for k, v := range extraLabels { - labels[k] = v - } + maps.Copy(labels, extraLabels) // Separate IP addresses from DNS names for cert-manager v1 compatibility var dns []string @@ -652,10 +652,5 @@ func isExternalIssuer(js *operatorv1alpha1.Jumpstarter) bool { // contains checks if a string slice contains a specific string. func contains(slice []string, str string) bool { - for _, s := range slice { - if s == str { - return true - } - } - return false + return slices.Contains(slice, str) } diff --git a/controller/deploy/operator/internal/controller/jumpstarter/endpoints/discovery_test.go b/controller/deploy/operator/internal/controller/jumpstarter/endpoints/discovery_test.go index 47ad6c0e4..b46993201 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/endpoints/discovery_test.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/endpoints/discovery_test.go @@ -41,7 +41,7 @@ func createOpenShiftIngressConfig(domain string) *unstructured.Unstructured { Kind: "Ingress", }) ingress.SetName("cluster") - ingress.Object["spec"] = map[string]interface{}{ + ingress.Object["spec"] = map[string]any{ "domain": domain, } return ingress @@ -92,7 +92,7 @@ var _ = Describe("detectOpenShiftBaseDomain", func() { Kind: "Ingress", }) ingress.SetName("cluster") - ingress.Object["spec"] = map[string]interface{}{} + ingress.Object["spec"] = map[string]any{} Expect(k8sClient.Create(ctx, ingress)).To(Succeed()) DeferCleanup(func() { _ = k8sClient.Delete(ctx, ingress) }) diff --git a/controller/deploy/operator/internal/controller/jumpstarter/endpoints/route.go b/controller/deploy/operator/internal/controller/jumpstarter/endpoints/route.go index 314f3cd2c..ec4ebc18d 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/endpoints/route.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/endpoints/route.go @@ -25,7 +25,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -133,7 +132,7 @@ func (r *Reconciler) createRouteForEndpoint(ctx context.Context, owner metav1.Ob To: routev1.RouteTargetReference{ Kind: "Service", Name: serviceName, - Weight: ptr.To(int32(100)), + Weight: new(int32(100)), }, TLS: &routev1.TLSConfig{ Termination: tlsTermination, @@ -215,7 +214,7 @@ func (r *Reconciler) createRouteForLoginEndpoint(ctx context.Context, owner meta To: routev1.RouteTargetReference{ Kind: "Service", Name: serviceName, - Weight: ptr.To(int32(100)), + Weight: new(int32(100)), }, TLS: tlsConfig, WildcardPolicy: routev1.WildcardPolicyNone, diff --git a/controller/deploy/operator/internal/controller/jumpstarter/exporterset.go b/controller/deploy/operator/internal/controller/jumpstarter/exporterset.go index 7485efd3c..79405aa73 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/exporterset.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/exporterset.go @@ -29,7 +29,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -380,8 +379,8 @@ func (r *JumpstarterReconciler) createExporterSetDeployment(jumpstarter *operato }, Spec: appsv1.DeploymentSpec{ Replicas: &replicas, - ProgressDeadlineSeconds: ptr.To(int32(600)), - RevisionHistoryLimit: ptr.To(int32(10)), + ProgressDeadlineSeconds: new(int32(600)), + RevisionHistoryLimit: new(int32(10)), Strategy: appsv1.DeploymentStrategy{ Type: appsv1.RollingUpdateDeploymentStrategyType, RollingUpdate: &appsv1.RollingUpdateDeployment{ @@ -399,7 +398,7 @@ func (r *JumpstarterReconciler) createExporterSetDeployment(jumpstarter *operato Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyAlways, DNSPolicy: corev1.DNSClusterFirst, - TerminationGracePeriodSeconds: ptr.To(int64(30)), + TerminationGracePeriodSeconds: new(int64(30)), Containers: []corev1.Container{ { Name: "manager", @@ -462,7 +461,7 @@ func (r *JumpstarterReconciler) createExporterSetDeployment(jumpstarter *operato TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: corev1.TerminationMessageReadFile, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: boolPtr(false), + AllowPrivilegeEscalation: new(false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{"ALL"}, }, @@ -470,7 +469,7 @@ func (r *JumpstarterReconciler) createExporterSetDeployment(jumpstarter *operato }, }, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: boolPtr(true), + RunAsNonRoot: new(true), SeccompProfile: &corev1.SeccompProfile{ Type: corev1.SeccompProfileTypeRuntimeDefault, }, diff --git a/controller/deploy/operator/internal/controller/jumpstarter/exporterset_test.go b/controller/deploy/operator/internal/controller/jumpstarter/exporterset_test.go index 3a4a92b07..5748bd0b9 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/exporterset_test.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/exporterset_test.go @@ -17,12 +17,13 @@ limitations under the License. package jumpstarter import ( + "slices" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/ptr" operatorv1alpha1 "github.com/jumpstarter-dev/jumpstarter/controller/deploy/operator/api/v1alpha1" ) @@ -279,23 +280,23 @@ var _ = Describe("hasEnabledProvisioners", func() { It("should return true when Enabled is explicitly true", func() { provs := []operatorv1alpha1.ProvisionerConfig{ - {Name: "qemu.jumpstarter.dev", Enabled: ptr.To(true)}, + {Name: "qemu.jumpstarter.dev", Enabled: new(true)}, } Expect(hasEnabledProvisioners(provs)).To(BeTrue()) }) It("should return false when all provisioners are disabled", func() { provs := []operatorv1alpha1.ProvisionerConfig{ - {Name: "qemu.jumpstarter.dev", Enabled: ptr.To(false)}, - {Name: "corellium.jumpstarter.dev", Enabled: ptr.To(false)}, + {Name: "qemu.jumpstarter.dev", Enabled: new(false)}, + {Name: "corellium.jumpstarter.dev", Enabled: new(false)}, } Expect(hasEnabledProvisioners(provs)).To(BeFalse()) }) It("should return true when at least one provisioner is enabled among disabled ones", func() { provs := []operatorv1alpha1.ProvisionerConfig{ - {Name: "qemu.jumpstarter.dev", Enabled: ptr.To(false)}, - {Name: "corellium.jumpstarter.dev", Enabled: ptr.To(true)}, + {Name: "qemu.jumpstarter.dev", Enabled: new(false)}, + {Name: "corellium.jumpstarter.dev", Enabled: new(true)}, } Expect(hasEnabledProvisioners(provs)).To(BeTrue()) }) @@ -506,7 +507,7 @@ var _ = Describe("createExporterSetDeployment", func() { It("should use per-provisioner replicas override", func() { dep := r.createExporterSetDeployment(js, operatorv1alpha1.ProvisionerConfig{ Name: "qemu.jumpstarter.dev", - Replicas: ptr.To(int32(3)), + Replicas: new(int32(3)), }) Expect(*dep.Spec.Replicas).To(Equal(int32(3))) @@ -635,10 +636,5 @@ var _ = Describe("createExporterSetDeployment", func() { }) func containsString(slice []string, s string) bool { - for _, v := range slice { - if v == s { - return true - } - } - return false + return slices.Contains(slice, s) } diff --git a/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go b/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go index 1a15ddf47..573857de0 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go @@ -25,6 +25,7 @@ import ( "encoding/hex" "fmt" "hash" + "maps" "net" "sort" "strings" @@ -40,7 +41,6 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" apiserverv1beta1 "k8s.io/apiserver/pkg/apis/apiserver/v1beta1" "k8s.io/client-go/tools/record" - "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -270,7 +270,7 @@ func (r *JumpstarterReconciler) Reconcile(ctx context.Context, req ctrl.Request) } // emitEventf emits a Kubernetes event on the Jumpstarter object. -func (r *JumpstarterReconciler) emitEventf(js *operatorv1alpha1.Jumpstarter, eventType, reason, msgFmt string, args ...interface{}) { +func (r *JumpstarterReconciler) emitEventf(js *operatorv1alpha1.Jumpstarter, eventType, reason, msgFmt string, args ...any) { if r.Recorder == nil { return } @@ -876,7 +876,7 @@ func (r *JumpstarterReconciler) createControllerDeployment(jumpstarter *operator Name: GetCAConfigMapName(jumpstarter), }, Key: "ca.crt", - Optional: boolPtr(!jumpstarter.Spec.CertManager.Enabled), + Optional: new(!jumpstarter.Spec.CertManager.Enabled), }, }, }, @@ -924,8 +924,8 @@ func (r *JumpstarterReconciler) createControllerDeployment(jumpstarter *operator }, Spec: appsv1.DeploymentSpec{ Replicas: &jumpstarter.Spec.Controller.Replicas, - ProgressDeadlineSeconds: ptr.To(int32(600)), - RevisionHistoryLimit: ptr.To(int32(10)), + ProgressDeadlineSeconds: new(int32(600)), + RevisionHistoryLimit: new(int32(10)), Strategy: appsv1.DeploymentStrategy{ Type: appsv1.RollingUpdateDeploymentStrategyType, RollingUpdate: &appsv1.RollingUpdateDeployment{ @@ -944,7 +944,7 @@ func (r *JumpstarterReconciler) createControllerDeployment(jumpstarter *operator Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyAlways, DNSPolicy: corev1.DNSClusterFirst, - TerminationGracePeriodSeconds: ptr.To(int64(30)), + TerminationGracePeriodSeconds: new(int64(30)), Containers: []corev1.Container{ { Name: "manager", @@ -1011,7 +1011,7 @@ func (r *JumpstarterReconciler) createControllerDeployment(jumpstarter *operator TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: corev1.TerminationMessageReadFile, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: boolPtr(false), + AllowPrivilegeEscalation: new(false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{"ALL"}, }, @@ -1020,7 +1020,7 @@ func (r *JumpstarterReconciler) createControllerDeployment(jumpstarter *operator }, Volumes: volumes, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: boolPtr(true), + RunAsNonRoot: new(true), SeccompProfile: &corev1.SeccompProfile{ Type: corev1.SeccompProfileTypeRuntimeDefault, }, @@ -1032,17 +1032,16 @@ func (r *JumpstarterReconciler) createControllerDeployment(jumpstarter *operator } } +//go:fix inline func boolPtr(b bool) *bool { - return &b + return new(b) } // buildControllerPodAnnotations builds the pod template annotations for the controller deployment. // Includes config/TLS hashes for rolling restart on changes, plus any user-provided pod annotations. func (r *JumpstarterReconciler) buildControllerPodAnnotations(jumpstarter *operatorv1alpha1.Jumpstarter, configMapHash, tlsSecretHash string) map[string]string { annotations := make(map[string]string) - for k, v := range jumpstarter.Spec.Controller.PodAnnotations { - annotations[k] = v - } + maps.Copy(annotations, jumpstarter.Spec.Controller.PodAnnotations) annotations["jumpstarter.dev/configmap-sha256"] = configMapHash if tlsSecretHash != "" { annotations["jumpstarter.dev/tls-secret-sha256"] = tlsSecretHash @@ -1054,9 +1053,7 @@ func (r *JumpstarterReconciler) buildControllerPodAnnotations(jumpstarter *opera // Includes TLS hash for rolling restart on cert renewal, plus any user-provided pod annotations. func (r *JumpstarterReconciler) buildRouterPodAnnotations(jumpstarter *operatorv1alpha1.Jumpstarter, tlsSecretHash string) map[string]string { annotations := make(map[string]string) - for k, v := range jumpstarter.Spec.Routers.PodAnnotations { - annotations[k] = v - } + maps.Copy(annotations, jumpstarter.Spec.Routers.PodAnnotations) if tlsSecretHash != "" { annotations["jumpstarter.dev/tls-secret-sha256"] = tlsSecretHash } @@ -1147,9 +1144,9 @@ func (r *JumpstarterReconciler) createRouterDeployment(jumpstarter *operatorv1al Labels: labels, }, Spec: appsv1.DeploymentSpec{ - Replicas: ptr.To(int32(1)), // Each deployment for the router needs to have exactly 1 replica - ProgressDeadlineSeconds: ptr.To(int32(600)), - RevisionHistoryLimit: ptr.To(int32(10)), + Replicas: new(int32(1)), // Each deployment for the router needs to have exactly 1 replica + ProgressDeadlineSeconds: new(int32(600)), + RevisionHistoryLimit: new(int32(10)), Strategy: appsv1.DeploymentStrategy{ Type: appsv1.RollingUpdateDeploymentStrategyType, RollingUpdate: &appsv1.RollingUpdateDeployment{ @@ -1168,7 +1165,7 @@ func (r *JumpstarterReconciler) createRouterDeployment(jumpstarter *operatorv1al Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyAlways, DNSPolicy: corev1.DNSClusterFirst, - TerminationGracePeriodSeconds: ptr.To(int64(30)), + TerminationGracePeriodSeconds: new(int64(30)), Containers: []corev1.Container{ { Name: "router", @@ -1201,7 +1198,7 @@ func (r *JumpstarterReconciler) createRouterDeployment(jumpstarter *operatorv1al TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: corev1.TerminationMessageReadFile, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: boolPtr(false), + AllowPrivilegeEscalation: new(false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{"ALL"}, }, @@ -1210,7 +1207,7 @@ func (r *JumpstarterReconciler) createRouterDeployment(jumpstarter *operatorv1al }, Volumes: volumes, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: boolPtr(true), + RunAsNonRoot: new(true), SeccompProfile: &corev1.SeccompProfile{ Type: corev1.SeccompProfileTypeRuntimeDefault, }, @@ -1600,7 +1597,7 @@ func (r *JumpstarterReconciler) cleanupExcessRouterServices(ctx context.Context, foundAny := false // Try to delete services for all endpoints and service types for this replica - for endpointIdx := 0; endpointIdx < 10; endpointIdx++ { // reasonable upper bound for endpoints + for endpointIdx := range 10 { // reasonable upper bound for endpoints for _, suffix := range suffixes { var serviceName string if endpointIdx == 0 { diff --git a/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller_test.go b/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller_test.go index 475c4b3bf..593015db4 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller_test.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/jumpstarter_controller_test.go @@ -225,7 +225,7 @@ var _ = Describe("Jumpstarter Controller — JWT CA resolution", func() { ClaimMappings: apiserverv1beta1.ClaimMappings{ Username: apiserverv1beta1.PrefixedClaimOrExpression{ Claim: "preferred_username", - Prefix: strPtr("oidc:"), + Prefix: new("oidc:"), }, }, }, @@ -266,7 +266,7 @@ var _ = Describe("Jumpstarter Controller — JWT CA resolution", func() { ClaimMappings: apiserverv1beta1.ClaimMappings{ Username: apiserverv1beta1.PrefixedClaimOrExpression{ Claim: "preferred_username", - Prefix: strPtr("oidc:"), + Prefix: new("oidc:"), }, }, }, @@ -301,7 +301,7 @@ var _ = Describe("Jumpstarter Controller — JWT CA resolution", func() { ClaimMappings: apiserverv1beta1.ClaimMappings{ Username: apiserverv1beta1.PrefixedClaimOrExpression{ Claim: "preferred_username", - Prefix: strPtr("oidc:"), + Prefix: new("oidc:"), }, }, }, @@ -349,7 +349,7 @@ var _ = Describe("Jumpstarter Controller — JWT CA resolution", func() { ClaimMappings: apiserverv1beta1.ClaimMappings{ Username: apiserverv1beta1.PrefixedClaimOrExpression{ Claim: "preferred_username", - Prefix: strPtr("oidc:"), + Prefix: new("oidc:"), }, }, }, @@ -382,8 +382,10 @@ var _ = Describe("Jumpstarter Controller — JWT CA resolution", func() { }) // strPtr is a helper to create a pointer to a string literal. +// +//go:fix inline func strPtr(s string) *string { - return &s + return new(s) } var _ = Describe("ExporterSet Controller Lifecycle", func() { diff --git a/controller/deploy/operator/internal/controller/jumpstarter/telemetry.go b/controller/deploy/operator/internal/controller/jumpstarter/telemetry.go index c94945b17..c88301346 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/telemetry.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/telemetry.go @@ -29,7 +29,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -363,8 +362,8 @@ func createTelemetryDeployment(jumpstarter *operatorv1alpha1.Jumpstarter, tlsSec }, Spec: appsv1.DeploymentSpec{ Replicas: &replicas, - ProgressDeadlineSeconds: ptr.To(int32(600)), - RevisionHistoryLimit: ptr.To(int32(10)), + ProgressDeadlineSeconds: new(int32(600)), + RevisionHistoryLimit: new(int32(10)), Strategy: appsv1.DeploymentStrategy{ Type: appsv1.RollingUpdateDeploymentStrategyType, RollingUpdate: &appsv1.RollingUpdateDeployment{ @@ -383,7 +382,7 @@ func createTelemetryDeployment(jumpstarter *operatorv1alpha1.Jumpstarter, tlsSec Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyAlways, DNSPolicy: corev1.DNSClusterFirst, - TerminationGracePeriodSeconds: ptr.To(int64(30)), + TerminationGracePeriodSeconds: new(int64(30)), Containers: []corev1.Container{ { Name: "telemetry", @@ -430,7 +429,7 @@ func createTelemetryDeployment(jumpstarter *operatorv1alpha1.Jumpstarter, tlsSec TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: corev1.TerminationMessageReadFile, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: ptr.To(false), + AllowPrivilegeEscalation: new(false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{"ALL"}, }, @@ -439,7 +438,7 @@ func createTelemetryDeployment(jumpstarter *operatorv1alpha1.Jumpstarter, tlsSec }, Volumes: volumes, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: ptr.To(true), + RunAsNonRoot: new(true), SeccompProfile: &corev1.SeccompProfile{ Type: corev1.SeccompProfileTypeRuntimeDefault, }, diff --git a/controller/deploy/operator/internal/controller/jumpstarter/telemetry_test.go b/controller/deploy/operator/internal/controller/jumpstarter/telemetry_test.go index 77b2d2c25..581e4e403 100644 --- a/controller/deploy/operator/internal/controller/jumpstarter/telemetry_test.go +++ b/controller/deploy/operator/internal/controller/jumpstarter/telemetry_test.go @@ -30,7 +30,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/reconcile" operatorv1alpha1 "github.com/jumpstarter-dev/jumpstarter/controller/deploy/operator/api/v1alpha1" @@ -201,7 +200,7 @@ var _ = Describe("Telemetry Lifecycle", func() { spec.Telemetry = &operatorv1alpha1.TelemetryConfig{ Enabled: true, Image: "quay.io/jumpstarter-dev/jumpstarter-telemetry:latest", - Replicas: ptr.To(int32(3)), + Replicas: new(int32(3)), } Expect(k8sClient.Create(ctx, &operatorv1alpha1.Jumpstarter{ ObjectMeta: metav1.ObjectMeta{Name: crName, Namespace: crNamespace}, diff --git a/controller/deploy/operator/internal/controller/testutils/envtest.go b/controller/deploy/operator/internal/controller/testutils/envtest.go index eb5f506d1..3b82b4070 100644 --- a/controller/deploy/operator/internal/controller/testutils/envtest.go +++ b/controller/deploy/operator/internal/controller/testutils/envtest.go @@ -37,7 +37,7 @@ import ( func GetFirstFoundEnvTestBinaryDir(depth int) string { // Build the path based on depth pathComponents := make([]string, 0, depth+2) - for i := 0; i < depth; i++ { + for range depth { pathComponents = append(pathComponents, "..") } pathComponents = append(pathComponents, "bin", "k8s") diff --git a/controller/deploy/operator/internal/utils/utils.go b/controller/deploy/operator/internal/utils/utils.go index 9796da5d5..44aeb810e 100644 --- a/controller/deploy/operator/internal/utils/utils.go +++ b/controller/deploy/operator/internal/utils/utils.go @@ -1,19 +1,17 @@ package utils +import "maps" + // MergeMaps merges two string maps, with values from the second map taking precedence. // This is useful for merging labels, annotations, or any other string key-value pairs. func MergeMaps(base, overrides map[string]string) map[string]string { merged := make(map[string]string) // Add base map first - for k, v := range base { - merged[k] = v - } + maps.Copy(merged, base) // Override with values from second map - for k, v := range overrides { - merged[k] = v - } + maps.Copy(merged, overrides) return merged } diff --git a/controller/deploy/operator/test/e2e/e2e_test.go b/controller/deploy/operator/test/e2e/e2e_test.go index 877c9549e..d21fef9f7 100644 --- a/controller/deploy/operator/test/e2e/e2e_test.go +++ b/controller/deploy/operator/test/e2e/e2e_test.go @@ -494,7 +494,7 @@ provisioning: actualRouter := cm.Data["router"] // Unmarshal and compare as map[string]interface{} for robustness to field ordering - var actualConfigObj, expectedConfigObj map[string]interface{} + var actualConfigObj, expectedConfigObj map[string]any err = yaml.Unmarshal([]byte(actualConfig), &actualConfigObj) g.Expect(err).NotTo(HaveOccurred()) @@ -502,7 +502,7 @@ provisioning: g.Expect(err).NotTo(HaveOccurred()) g.Expect(actualConfigObj).To(Equal(expectedConfigObj), "config map 'config' entry did not match expected") - var actualRouterObj, expectedRouterObj map[string]interface{} + var actualRouterObj, expectedRouterObj map[string]any err = yaml.Unmarshal([]byte(actualRouter), &actualRouterObj) g.Expect(err).NotTo(HaveOccurred()) @@ -920,11 +920,11 @@ provisioning: }, configmap) g.Expect(err).NotTo(HaveOccurred()) - var configObj map[string]interface{} + var configObj map[string]any err = yaml.Unmarshal([]byte(configmap.Data["config"]), &configObj) g.Expect(err).NotTo(HaveOccurred()) - provisioning, ok := configObj["provisioning"].(map[string]interface{}) + provisioning, ok := configObj["provisioning"].(map[string]any) g.Expect(ok).To(BeTrue()) g.Expect(provisioning["enabled"]).To(BeTrue()) }, 1*time.Minute).Should(Succeed()) diff --git a/controller/deploy/operator/test/utils/utils.go b/controller/deploy/operator/test/utils/utils.go index 555344f67..f59e196cd 100644 --- a/controller/deploy/operator/test/utils/utils.go +++ b/controller/deploy/operator/test/utils/utils.go @@ -208,8 +208,8 @@ func LoadImageToKindClusterWithName(name string) error { // according to line breakers, and ignores the empty elements in it. func GetNonEmptyLines(output string) []string { var res []string - elements := strings.Split(output, "\n") - for _, element := range elements { + elements := strings.SplitSeq(output, "\n") + for element := range elements { if element != "" { res = append(res, element) } diff --git a/controller/go.mod b/controller/go.mod index 183c7408b..03fd061e2 100644 --- a/controller/go.mod +++ b/controller/go.mod @@ -27,7 +27,6 @@ require ( k8s.io/apimachinery v0.33.0 k8s.io/apiserver v0.33.0 k8s.io/client-go v0.33.0 - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 sigs.k8s.io/controller-runtime v0.21.0 sigs.k8s.io/yaml v1.4.0 ) @@ -120,6 +119,7 @@ require ( k8s.io/component-base v0.33.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/controller/internal/authorization/basic.go b/controller/internal/authorization/basic.go index 99cbb8b58..2ac0609e2 100644 --- a/controller/internal/authorization/basic.go +++ b/controller/internal/authorization/basic.go @@ -8,7 +8,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/authorization/authorizer" - "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -58,7 +57,7 @@ func (b *BasicAuthorizer) Authorize( Name: attributes.GetName(), }, Spec: jumpstarterdevv1alpha1.ClientSpec{ - Username: ptr.To(attributes.GetUser().GetName()), + Username: new(attributes.GetUser().GetName()), }, } if err := b.client.Create(ctx, &c); err != nil { diff --git a/controller/internal/config/types.go b/controller/internal/config/types.go index 5fe43a5e5..1a4159b54 100644 --- a/controller/internal/config/types.go +++ b/controller/internal/config/types.go @@ -15,9 +15,9 @@ type Config struct { Authentication Authentication `json:"authentication" yaml:"authentication"` Provisioning Provisioning `json:"provisioning" yaml:"provisioning"` Grpc Grpc `json:"grpc" yaml:"grpc"` - LeasePolicy LeasePolicy `json:"leasePolicy,omitempty" yaml:"leasePolicy,omitempty"` - HiddenLabels HiddenLabels `json:"hiddenLabels,omitempty" yaml:"hiddenLabels,omitempty"` - DeprecatedLabels DeprecatedLabels `json:"deprecatedLabels,omitempty" yaml:"deprecatedLabels,omitempty"` + LeasePolicy LeasePolicy `json:"leasePolicy" yaml:"leasePolicy,omitempty"` + HiddenLabels HiddenLabels `json:"hiddenLabels" yaml:"hiddenLabels,omitempty"` + DeprecatedLabels DeprecatedLabels `json:"deprecatedLabels" yaml:"deprecatedLabels,omitempty"` Telemetry *Telemetry `json:"telemetry,omitempty" yaml:"telemetry,omitempty"` } @@ -49,12 +49,12 @@ type Telemetry struct { Certificate string `json:"certificate,omitempty" yaml:"certificate,omitempty"` // Logging configures the log ingestion path to the telemetry service. - Logging TelemetryLogging `json:"logging,omitempty" yaml:"logging,omitempty"` + Logging TelemetryLogging `json:"logging" yaml:"logging,omitempty"` } // TelemetryLogging configures the log push path to the telemetry service. type TelemetryLogging struct { - Filter TelemetryLoggingFilter `json:"filter,omitempty" yaml:"filter,omitempty"` + Filter TelemetryLoggingFilter `json:"filter" yaml:"filter,omitempty"` } // TelemetryLoggingFilter controls which log entries are forwarded to the telemetry service. @@ -100,7 +100,7 @@ type DeprecatedLabels struct { // Supports multiple authentication methods: internal tokens, Kubernetes tokens, and JWT. type Authentication struct { Internal Internal `json:"internal" yaml:"internal"` - K8s K8s `json:"k8s,omitempty" yaml:"k8s,omitempty"` + K8s K8s `json:"k8s" yaml:"k8s,omitempty"` JWT []apiserverv1beta1.JWTAuthenticator `json:"jwt" yaml:"jwt"` } diff --git a/controller/internal/controller/client_controller.go b/controller/internal/controller/client_controller.go index b82d4e579..1016c4340 100644 --- a/controller/internal/controller/client_controller.go +++ b/controller/internal/controller/client_controller.go @@ -131,7 +131,7 @@ func (r *ClientReconciler) reconcileStatusEndpoint( return nil } -func (r *ClientReconciler) emitEventf(client *jumpstarterdevv1alpha1.Client, eventType, reason, msgFmt string, args ...interface{}) { +func (r *ClientReconciler) emitEventf(client *jumpstarterdevv1alpha1.Client, eventType, reason, msgFmt string, args ...any) { if r.Recorder == nil { return } diff --git a/controller/internal/controller/exporter_controller.go b/controller/internal/controller/exporter_controller.go index 50726db4d..8c91c2aa8 100644 --- a/controller/internal/controller/exporter_controller.go +++ b/controller/internal/controller/exporter_controller.go @@ -272,7 +272,7 @@ func (r *ExporterReconciler) reconcileStatusConditionsOnline( }, nil } -func (r *ExporterReconciler) emitEventf(exporter *jumpstarterdevv1alpha1.Exporter, eventType, reason, msgFmt string, args ...interface{}) { +func (r *ExporterReconciler) emitEventf(exporter *jumpstarterdevv1alpha1.Exporter, eventType, reason, msgFmt string, args ...any) { if r.Recorder == nil { return } diff --git a/controller/internal/controller/lease_controller.go b/controller/internal/controller/lease_controller.go index 77acbbf49..a226fd95f 100755 --- a/controller/internal/controller/lease_controller.go +++ b/controller/internal/controller/lease_controller.go @@ -83,7 +83,7 @@ func (r *LeaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl ) } - leaseLogValues := []interface{}{"lease_id", lease.Name, "client", lease.Spec.ClientRef.Name} + leaseLogValues := []any{"lease_id", lease.Name, "client", lease.Spec.ClientRef.Name} if lease.Spec.ExporterRef != nil { leaseLogValues = append(leaseLogValues, "exporter", lease.Spec.ExporterRef.Name) } diff --git a/controller/internal/exporterset/disk/disk.go b/controller/internal/exporterset/disk/disk.go index edc162ef2..c6eea825b 100644 --- a/controller/internal/exporterset/disk/disk.go +++ b/controller/internal/exporterset/disk/disk.go @@ -78,7 +78,7 @@ func Mount() corev1.VolumeMount { // FromParameters reads disk size and optional storage backend from merged // ExporterSet/VirtualTargetClass parameters. -func FromParameters(params map[string]interface{}) (Spec, error) { +func FromParameters(params map[string]any) (Spec, error) { spec := Spec{ AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, } @@ -91,7 +91,7 @@ func FromParameters(params map[string]interface{}) (Spec, error) { spec.VolumeSize = applyOverhead(size, defaultOverheadPercent()) return spec, nil } - storage, ok := params["storage"].(map[string]interface{}) + storage, ok := params["storage"].(map[string]any) if !ok { if params["storage"] != nil { return Spec{}, fmt.Errorf("parameters.storage must be an object, got %T", params["storage"]) @@ -148,7 +148,7 @@ func FromParameters(params map[string]interface{}) (Spec, error) { } // SizeFromParameters reads parameters.storage.size, defaulting to DefaultSize. -func SizeFromParameters(params map[string]interface{}) (resource.Quantity, error) { +func SizeFromParameters(params map[string]any) (resource.Quantity, error) { spec, err := FromParameters(params) if err != nil { return resource.Quantity{}, err @@ -224,7 +224,7 @@ func defaultOverheadPercent() int { return percent } -func parseFSOverhead(v interface{}) (int, error) { +func parseFSOverhead(v any) (int, error) { raw := DefaultFSOverhead if v != nil { s, ok := v.(string) @@ -262,8 +262,8 @@ func applyOverhead(size resource.Quantity, overheadPercent int) resource.Quantit return *resource.NewQuantity(inflated, size.Format) } -func parseAccessModes(v interface{}) ([]corev1.PersistentVolumeAccessMode, error) { - items, ok := v.([]interface{}) +func parseAccessModes(v any) ([]corev1.PersistentVolumeAccessMode, error) { + items, ok := v.([]any) if !ok { return nil, fmt.Errorf("parameters.storage.accessModes must be a list of strings, got %T", v) } diff --git a/controller/internal/exporterset/disk/disk_test.go b/controller/internal/exporterset/disk/disk_test.go index 71651f8c3..c406dcc32 100644 --- a/controller/internal/exporterset/disk/disk_test.go +++ b/controller/internal/exporterset/disk/disk_test.go @@ -17,6 +17,7 @@ limitations under the License. package disk import ( + "maps" "testing" corev1 "k8s.io/api/core/v1" @@ -44,11 +45,11 @@ func TestFromParameters_defaults(t *testing.T) { } func TestFromParameters_storageClassAndSize(t *testing.T) { - spec, err := FromParameters(map[string]interface{}{ - "storage": map[string]interface{}{ + spec, err := FromParameters(map[string]any{ + "storage": map[string]any{ "size": "15Gi", "storageClassName": "gp3", - "accessModes": []interface{}{"ReadWriteOnce", "ReadWriteMany"}, + "accessModes": []any{"ReadWriteOnce", "ReadWriteMany"}, }, }) if err != nil { @@ -69,8 +70,8 @@ func TestFromParameters_storageClassAndSize(t *testing.T) { } func TestFromParameters_emptyStorageClassForcesEmptyDir(t *testing.T) { - spec, err := FromParameters(map[string]interface{}{ - "storage": map[string]interface{}{ + spec, err := FromParameters(map[string]any{ + "storage": map[string]any{ "storageClassName": "", }, }) @@ -83,8 +84,8 @@ func TestFromParameters_emptyStorageClassForcesEmptyDir(t *testing.T) { } func TestFromParameters_rejectsNumericStorage(t *testing.T) { - _, err := FromParameters(map[string]interface{}{ - "storage": map[string]interface{}{"size": 10.0}, + _, err := FromParameters(map[string]any{ + "storage": map[string]any{"size": 10.0}, }) if err == nil { t.Fatal("expected error for numeric storage") @@ -92,8 +93,8 @@ func TestFromParameters_rejectsNumericStorage(t *testing.T) { } func TestFromParameters_fsOverhead(t *testing.T) { - spec, err := FromParameters(map[string]interface{}{ - "storage": map[string]interface{}{ + spec, err := FromParameters(map[string]any{ + "storage": map[string]any{ "size": "10Gi", "fsOverhead": "0%", }, @@ -108,8 +109,8 @@ func TestFromParameters_fsOverhead(t *testing.T) { t.Errorf("VolumeSize = %v, want 10Gi with 0%% overhead", spec.VolumeSize) } - spec, err = FromParameters(map[string]interface{}{ - "storage": map[string]interface{}{ + spec, err = FromParameters(map[string]any{ + "storage": map[string]any{ "size": "10Gi", "fsOverhead": "10%", }, @@ -124,8 +125,8 @@ func TestFromParameters_fsOverhead(t *testing.T) { } func TestFromParameters_rejectsInvalidFSOverhead(t *testing.T) { - _, err := FromParameters(map[string]interface{}{ - "storage": map[string]interface{}{ + _, err := FromParameters(map[string]any{ + "storage": map[string]any{ "fsOverhead": "ten", }, }) @@ -202,13 +203,13 @@ func TestSetEphemeralStorage(t *testing.T) { } func TestFromParameters_mergedEmptyStorageClassForcesEmptyDir(t *testing.T) { - merged := deepMerge(map[string]interface{}{ - "storage": map[string]interface{}{ + merged := deepMerge(map[string]any{ + "storage": map[string]any{ "storageClassName": "gp3", "size": "20Gi", }, - }, map[string]interface{}{ - "storage": map[string]interface{}{ + }, map[string]any{ + "storage": map[string]any{ "storageClassName": "", }, }) @@ -226,14 +227,12 @@ func TestFromParameters_mergedEmptyStorageClassForcesEmptyDir(t *testing.T) { } // deepMerge mirrors exporterset.deepMerge for merge-semantics tests. -func deepMerge(base, override map[string]interface{}) map[string]interface{} { - result := make(map[string]interface{}, len(base)+len(override)) - for k, v := range base { - result[k] = v - } +func deepMerge(base, override map[string]any) map[string]any { + result := make(map[string]any, len(base)+len(override)) + maps.Copy(result, base) for k, v := range override { - if baseMap, ok := result[k].(map[string]interface{}); ok { - if overrideMap, ok := v.(map[string]interface{}); ok { + if baseMap, ok := result[k].(map[string]any); ok { + if overrideMap, ok := v.(map[string]any); ok { result[k] = deepMerge(baseMap, overrideMap) continue } diff --git a/controller/internal/exporterset/exporterconfig.go b/controller/internal/exporterset/exporterconfig.go index 157f42f68..38ca19e65 100644 --- a/controller/internal/exporterset/exporterconfig.go +++ b/controller/internal/exporterset/exporterconfig.go @@ -80,7 +80,7 @@ type exporterConfigTLS struct { type exporterConfigDriver struct { Type string `json:"type,omitempty"` Ref string `json:"ref,omitempty"` - Config interface{} `json:"config,omitempty"` + Config any `json:"config,omitempty"` Children map[string]exporterConfigDriver `json:"children,omitempty"` } @@ -92,7 +92,7 @@ func (r *ExporterSetReconciler) buildExporterConfigSecret( es *virtualtargetv1alpha1.ExporterSet, exporter *jumpstarterdevv1alpha1.Exporter, caBundle string, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, ) (*corev1.Secret, error) { token, err := r.readCredentialToken(ctx, exporter) if err != nil { @@ -169,7 +169,7 @@ func buildExportMap(drivers []virtualtargetv1alpha1.DriverConfig) (map[string]ex continue } - var config interface{} + var config any if d.Config != nil && d.Config.Raw != nil { if err := json.Unmarshal(d.Config.Raw, &config); err != nil { return nil, fmt.Errorf("unmarshal config for driver %q: %w", name, err) diff --git a/controller/internal/exporterset/exporterconfig_test.go b/controller/internal/exporterset/exporterconfig_test.go index a325eb9bd..29df77c21 100644 --- a/controller/internal/exporterset/exporterconfig_test.go +++ b/controller/internal/exporterset/exporterconfig_test.go @@ -25,7 +25,7 @@ import ( ) func TestBuildExportMap(t *testing.T) { - config := map[string]interface{}{ + config := map[string]any{ "arch": "x86_64", "smp": 2, } @@ -61,7 +61,7 @@ func TestBuildExportMap(t *testing.T) { if qemu.Type != "jumpstarter_driver_qemu.driver.Qemu" { t.Errorf("qemu type = %q", qemu.Type) } - configMap, ok := qemu.Config.(map[string]interface{}) + configMap, ok := qemu.Config.(map[string]any) if !ok { t.Fatal("qemu config is not a map") } diff --git a/controller/internal/exporterset/exporterset_controller_test.go b/controller/internal/exporterset/exporterset_controller_test.go index 8939a79a9..209b33977 100644 --- a/controller/internal/exporterset/exporterset_controller_test.go +++ b/controller/internal/exporterset/exporterset_controller_test.go @@ -270,7 +270,7 @@ var _ = Describe("ExporterSet Controller", func() { Labels: map[string]string{"exporterset": "test-scale-down"}, }, Spec: jumpstarterdevv1alpha1.ExporterSpec{ - Enabled: boolPtr(true), + Enabled: new(true), }, } Expect(envTestClient.Create(envTestCtx, exp)).To(Succeed()) @@ -281,7 +281,7 @@ var _ = Describe("ExporterSet Controller", func() { Kind: "ExporterSet", Name: es.Name, UID: es.UID, - Controller: boolPtr(true), + Controller: new(true), }} Expect(envTestClient.Update(envTestCtx, exp)).To(Succeed()) diff --git a/controller/internal/exporterset/provisioner.go b/controller/internal/exporterset/provisioner.go index a03e4df25..7e25119a9 100644 --- a/controller/internal/exporterset/provisioner.go +++ b/controller/internal/exporterset/provisioner.go @@ -46,7 +46,7 @@ type Provisioner interface { ctx context.Context, exporterSet *virtualtargetv1alpha1.ExporterSet, vtc *virtualtargetv1alpha1.VirtualTargetClass, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, images *virtualtargetv1alpha1.ImageOverrides, exporter *jumpstarterdevv1alpha1.Exporter, ) (*corev1.Pod, error) @@ -58,7 +58,7 @@ type Provisioner interface { // The returned slice replaces the original drivers list. EnrichExporterExport( drivers []virtualtargetv1alpha1.DriverConfig, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, ) ([]virtualtargetv1alpha1.DriverConfig, error) // Cleanup is called when an exporter instance is being diff --git a/controller/internal/exporterset/provisioners/qemu/enrich_test.go b/controller/internal/exporterset/provisioners/qemu/enrich_test.go index 8fb759935..5d67eec9a 100644 --- a/controller/internal/exporterset/provisioners/qemu/enrich_test.go +++ b/controller/internal/exporterset/provisioners/qemu/enrich_test.go @@ -29,7 +29,7 @@ func TestEnrichExporterExport_injectsLauncherSocket(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "x86_64", "smp": 2, "mem": "2G", @@ -58,7 +58,7 @@ func TestEnrichExporterExport_injectsDefaultPartitionsX86(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "x86_64", }), }, @@ -70,7 +70,7 @@ func TestEnrichExporterExport_injectsDefaultPartitionsX86(t *testing.T) { } config := unmarshalConfig(t, findDriver(result, "qemu").Config) - partitions, ok := config["default_partitions"].(map[string]interface{}) + partitions, ok := config["default_partitions"].(map[string]any) if !ok { t.Fatalf("default_partitions not a map: %T", config["default_partitions"]) } @@ -87,7 +87,7 @@ func TestEnrichExporterExport_injectsDefaultPartitionsAarch64(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "aarch64", }), }, @@ -99,7 +99,7 @@ func TestEnrichExporterExport_injectsDefaultPartitionsAarch64(t *testing.T) { } config := unmarshalConfig(t, findDriver(result, "qemu").Config) - partitions, ok := config["default_partitions"].(map[string]interface{}) + partitions, ok := config["default_partitions"].(map[string]any) if !ok { t.Fatalf("default_partitions not a map: %T", config["default_partitions"]) } @@ -112,7 +112,7 @@ func TestEnrichExporterExport_injectsDefaultPartitionsAarch64(t *testing.T) { } func TestEnrichExporterExport_respectsUserDefaultPartitions(t *testing.T) { - userPartitions := map[string]interface{}{ + userPartitions := map[string]any{ "OVMF_CODE.fd": "/custom/path/code.fd", "OVMF_VARS.fd": "/custom/path/vars.fd", } @@ -120,7 +120,7 @@ func TestEnrichExporterExport_respectsUserDefaultPartitions(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "x86_64", "default_partitions": userPartitions, }), @@ -133,7 +133,7 @@ func TestEnrichExporterExport_respectsUserDefaultPartitions(t *testing.T) { } config := unmarshalConfig(t, findDriver(result, "qemu").Config) - partitions, ok := config["default_partitions"].(map[string]interface{}) + partitions, ok := config["default_partitions"].(map[string]any) if !ok { t.Fatalf("default_partitions not a map: %T", config["default_partitions"]) } @@ -147,7 +147,7 @@ func TestEnrichExporterExport_injectsHostfwdSSH(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "x86_64", }), }, @@ -159,11 +159,11 @@ func TestEnrichExporterExport_injectsHostfwdSSH(t *testing.T) { } config := unmarshalConfig(t, findDriver(result, "qemu").Config) - hostfwd, ok := config["hostfwd"].(map[string]interface{}) + hostfwd, ok := config["hostfwd"].(map[string]any) if !ok { t.Fatalf("hostfwd not a map: %T", config["hostfwd"]) } - ssh, ok := hostfwd["ssh"].(map[string]interface{}) + ssh, ok := hostfwd["ssh"].(map[string]any) if !ok { t.Fatalf("hostfwd.ssh not a map: %T", hostfwd["ssh"]) } @@ -183,7 +183,7 @@ func TestEnrichExporterExport_autoInjectsTCPDriver(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "x86_64", }), }, @@ -208,14 +208,14 @@ func TestEnrichExporterExport_doesNotDuplicateExistingTCP(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "arch": "x86_64", }), }, { Name: "tcp", Type: tcpDriverType, - Config: mustJSON(map[string]interface{}{"host": "10.0.0.1", "port": 3333}), + Config: mustJSON(map[string]any{"host": "10.0.0.1", "port": 3333}), }, } @@ -240,17 +240,17 @@ func TestEnrichExporterExport_defaultsFromMergedParameters(t *testing.T) { { Name: "qemu", Type: qemuDriverType, - Config: mustJSON(map[string]interface{}{}), + Config: mustJSON(map[string]any{}), }, } - params := map[string]interface{}{ + params := map[string]any{ "arch": "aarch64", - "resources": map[string]interface{}{ + "resources": map[string]any{ "cpu": 4, "memory": "4Gi", }, - "storage": map[string]interface{}{ + "storage": map[string]any{ "size": "40Gi", }, } @@ -304,12 +304,12 @@ func findDriver(drivers []virtualtargetv1alpha1.DriverConfig, name string) *virt return nil } -func unmarshalConfig(t *testing.T, raw *apiextensionsv1.JSON) map[string]interface{} { +func unmarshalConfig(t *testing.T, raw *apiextensionsv1.JSON) map[string]any { t.Helper() if raw == nil || raw.Raw == nil { t.Fatal("config is nil") } - var config map[string]interface{} + var config map[string]any if err := json.Unmarshal(raw.Raw, &config); err != nil { t.Fatalf("unmarshal config: %v", err) } diff --git a/controller/internal/exporterset/provisioners/qemu/qemu.go b/controller/internal/exporterset/provisioners/qemu/qemu.go index c9f203e89..7402aab9c 100644 --- a/controller/internal/exporterset/provisioners/qemu/qemu.go +++ b/controller/internal/exporterset/provisioners/qemu/qemu.go @@ -166,7 +166,7 @@ func (p *Provisioner) RenderPod( ctx context.Context, exporterSet *virtualtargetv1alpha1.ExporterSet, vtc *virtualtargetv1alpha1.VirtualTargetClass, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, images *virtualtargetv1alpha1.ImageOverrides, exporter *jumpstarterdevv1alpha1.Exporter, ) (*corev1.Pod, error) { @@ -252,7 +252,7 @@ func (p *Provisioner) RenderPod( Env: runtimeEnv, SecurityContext: &corev1.SecurityContext{ RunAsUser: &runAsRoot, - RunAsNonRoot: boolPtr(false), + RunAsNonRoot: new(false), }, VolumeMounts: []corev1.VolumeMount{ { @@ -355,7 +355,7 @@ func (p *Provisioner) RenderPod( // - Auto-injects tcp wrapper driver entry func (p *Provisioner) EnrichExporterExport( drivers []virtualtargetv1alpha1.DriverConfig, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, ) ([]virtualtargetv1alpha1.DriverConfig, error) { result := make([]virtualtargetv1alpha1.DriverConfig, 0, len(drivers)+1) hasTCP := false @@ -380,7 +380,7 @@ func (p *Provisioner) EnrichExporterExport( result = append(result, virtualtargetv1alpha1.DriverConfig{ Name: "tcp", Type: tcpDriverType, - Config: mustJSON(map[string]interface{}{ + Config: mustJSON(map[string]any{ "host": "127.0.0.1", "port": 2222, }), @@ -391,8 +391,8 @@ func (p *Provisioner) EnrichExporterExport( } // enrichQemuDriver applies QEMU-specific defaults to a driver config entry. -func enrichQemuDriver(d virtualtargetv1alpha1.DriverConfig, params map[string]interface{}) (virtualtargetv1alpha1.DriverConfig, error) { - config := make(map[string]interface{}) +func enrichQemuDriver(d virtualtargetv1alpha1.DriverConfig, params map[string]any) (virtualtargetv1alpha1.DriverConfig, error) { + config := make(map[string]any) if d.Config != nil && d.Config.Raw != nil { if err := json.Unmarshal(d.Config.Raw, &config); err != nil { return d, fmt.Errorf("unmarshal QEMU driver config: %w", err) @@ -415,12 +415,12 @@ func enrichQemuDriver(d virtualtargetv1alpha1.DriverConfig, params map[string]in } // Inject hostfwd.ssh if not already present. - hostfwd, _ := config["hostfwd"].(map[string]interface{}) + hostfwd, _ := config["hostfwd"].(map[string]any) if hostfwd == nil { - hostfwd = make(map[string]interface{}) + hostfwd = make(map[string]any) } if _, hasSSH := hostfwd["ssh"]; !hasSSH { - hostfwd["ssh"] = map[string]interface{}{ + hostfwd["ssh"] = map[string]any{ "hostaddr": "127.0.0.1", "hostport": 2222, "guestport": 22, @@ -451,15 +451,15 @@ func defaultPartitionsForArch(arch string) map[string]string { // setDefault sets config[key] from params[paramPath] if not already set. // paramPath supports one level of nesting with dot notation. -func setDefault(config map[string]interface{}, key string, params map[string]interface{}, paramPath string) { +func setDefault(config map[string]any, key string, params map[string]any, paramPath string) { if _, exists := config[key]; exists { return } parts := splitDot(paramPath) - var val interface{} = params + var val any = params for _, p := range parts { - m, ok := val.(map[string]interface{}) + m, ok := val.(map[string]any) if !ok { return } @@ -478,7 +478,7 @@ func setDefault(config map[string]interface{}, key string, params map[string]int // normalizeQemuSize converts Kubernetes binary quantity strings (e.g. "10Gi") // to the form expected by the QEMU driver / qemu-img (e.g. "10G"). -func normalizeQemuSize(v interface{}) interface{} { +func normalizeQemuSize(v any) any { s, ok := v.(string) if !ok || len(s) < 2 { return v @@ -507,15 +507,11 @@ func splitDot(s string) []string { return result } -func mustJSON(v interface{}) *apiextensionsv1.JSON { +func mustJSON(v any) *apiextensionsv1.JSON { raw, _ := json.Marshal(v) return &apiextensionsv1.JSON{Raw: raw} } -func boolPtr(v bool) *bool { - return &v -} - // Cleanup handles teardown of QEMU-based exporter instances. // For in-cluster QEMU, this is a no-op since deleting the Pod // (via OwnerReference cascade) handles cleanup. diff --git a/controller/internal/exporterset/provisioners/qemu/qemu_test.go b/controller/internal/exporterset/provisioners/qemu/qemu_test.go index 466443561..6dd1c3fc8 100644 --- a/controller/internal/exporterset/provisioners/qemu/qemu_test.go +++ b/controller/internal/exporterset/provisioners/qemu/qemu_test.go @@ -479,8 +479,8 @@ func TestRenderPod_diskEphemeralWhenStorageClassSet(t *testing.T) { Provisioner: ProvisionerName, }, } - params := map[string]interface{}{ - "storage": map[string]interface{}{ + params := map[string]any{ + "storage": map[string]any{ "size": "20Gi", "storageClassName": "fast-ssd", }, @@ -525,8 +525,8 @@ func TestRenderPod_diskEmptyDirUsesParamSize(t *testing.T) { vtc := &virtualtargetv1alpha1.VirtualTargetClass{ Spec: virtualtargetv1alpha1.VirtualTargetClassSpec{Provisioner: ProvisionerName}, } - params := map[string]interface{}{ - "storage": map[string]interface{}{ + params := map[string]any{ + "storage": map[string]any{ "size": "7Gi", "fsOverhead": "0%", }, diff --git a/controller/internal/exporterset/reconciler.go b/controller/internal/exporterset/reconciler.go index 8491e875b..9ba43ff21 100644 --- a/controller/internal/exporterset/reconciler.go +++ b/controller/internal/exporterset/reconciler.go @@ -330,7 +330,7 @@ func (r *ExporterSetReconciler) scaleUp( ) error { logger := log.FromContext(ctx) - for i := int32(0); i < count; i++ { + for range count { exporter := &jumpstarterdevv1alpha1.Exporter{ ObjectMeta: metav1.ObjectMeta{ GenerateName: es.Name + "-", @@ -339,7 +339,7 @@ func (r *ExporterSetReconciler) scaleUp( Annotations: maps.Clone(es.Spec.Template.Metadata.Annotations), }, Spec: jumpstarterdevv1alpha1.ExporterSpec{ - Enabled: boolPtr(true), + Enabled: new(true), }, } @@ -371,7 +371,7 @@ func (r *ExporterSetReconciler) ensureExporterPods( ctx context.Context, es *virtualtargetv1alpha1.ExporterSet, vtc *virtualtargetv1alpha1.VirtualTargetClass, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, ownedExporters []jumpstarterdevv1alpha1.Exporter, podsByExporter map[string][]corev1.Pod, ) (waiting bool, err error) { @@ -432,7 +432,7 @@ func (r *ExporterSetReconciler) syncConfigSecret( es *virtualtargetv1alpha1.ExporterSet, exp *jumpstarterdevv1alpha1.Exporter, caBundle string, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, ) error { configSecret, err := r.buildExporterConfigSecret(ctx, es, exp, caBundle, mergedParameters) if err != nil { @@ -463,7 +463,7 @@ func (r *ExporterSetReconciler) createExporterPod( ctx context.Context, es *virtualtargetv1alpha1.ExporterSet, vtc *virtualtargetv1alpha1.VirtualTargetClass, - mergedParameters map[string]interface{}, + mergedParameters map[string]any, images *virtualtargetv1alpha1.ImageOverrides, exp *jumpstarterdevv1alpha1.Exporter, ) error { @@ -872,7 +872,7 @@ func (r *ExporterSetReconciler) reconcileScaleDown( continue } - exp.Spec.Enabled = boolPtr(false) + exp.Spec.Enabled = new(false) if err := r.Update(ctx, exp); err != nil { return ctrl.Result{}, fmt.Errorf("unable to disable Exporter %s: %w", exp.Name, err) } @@ -1437,8 +1437,6 @@ func isOwnedByKind(obj client.Object, kind string) bool { return false } -func boolPtr(b bool) *bool { return &b } - func atMaxReplicas(es *virtualtargetv1alpha1.ExporterSet, current int32) bool { return es.Spec.MaxReplicas > 0 && current >= es.Spec.MaxReplicas } @@ -1454,7 +1452,7 @@ func maxScaleUp(es *virtualtargetv1alpha1.ExporterSet, current int32) int32 { return room } -func requeueConflict(logger interface{ Info(string, ...interface{}) }, err error) (ctrl.Result, error) { +func requeueConflict(logger interface{ Info(string, ...any) }, err error) (ctrl.Result, error) { if apierrors.IsConflict(err) { logger.Info("conflict on status update, will retry") } @@ -1465,9 +1463,9 @@ func requeueConflict(logger interface{ Info(string, ...interface{}) }, err error func deepMergeParameters( classParams *apiextensionsv1.JSON, setParams *apiextensionsv1.JSON, -) (map[string]interface{}, error) { - base := make(map[string]interface{}) - override := make(map[string]interface{}) +) (map[string]any, error) { + base := make(map[string]any) + override := make(map[string]any) if classParams != nil && classParams.Raw != nil { if err := json.Unmarshal(classParams.Raw, &base); err != nil { @@ -1484,14 +1482,12 @@ func deepMergeParameters( return deepMerge(base, override), nil } -func deepMerge(base, override map[string]interface{}) map[string]interface{} { - result := make(map[string]interface{}, len(base)+len(override)) - for k, v := range base { - result[k] = v - } +func deepMerge(base, override map[string]any) map[string]any { + result := make(map[string]any, len(base)+len(override)) + maps.Copy(result, base) for k, v := range override { - if baseMap, ok := result[k].(map[string]interface{}); ok { - if overrideMap, ok := v.(map[string]interface{}); ok { + if baseMap, ok := result[k].(map[string]any); ok { + if overrideMap, ok := v.(map[string]any); ok { result[k] = deepMerge(baseMap, overrideMap) continue } diff --git a/controller/internal/exporterset/reconciler_test.go b/controller/internal/exporterset/reconciler_test.go index 5b4eb4734..6902e06b6 100644 --- a/controller/internal/exporterset/reconciler_test.go +++ b/controller/internal/exporterset/reconciler_test.go @@ -107,11 +107,11 @@ func makeExporter(name string, online bool, leased bool, enabled bool) *jumpstar Kind: kindExporterSet, Name: "demo-set", UID: testExporterSetUID, - Controller: boolPtr(true), + Controller: new(true), }}, }, Spec: jumpstarterdevv1alpha1.ExporterSpec{ - Enabled: boolPtr(enabled), + Enabled: new(enabled), }, } @@ -208,7 +208,7 @@ func makePod(name string, phase corev1.PodPhase) *corev1.Pod { Kind: kindExporter, Name: name, UID: types.UID(name + "-uid"), - Controller: boolPtr(true), + Controller: new(true), }}, }, Status: corev1.PodStatus{Phase: phase}, @@ -996,27 +996,27 @@ func TestComputePoolState(t *testing.T) { // --- Deep merge tests --- func TestDeepMerge_mapsRecursive(t *testing.T) { - base := map[string]interface{}{ - "resources": map[string]interface{}{ + base := map[string]any{ + "resources": map[string]any{ "cpu": "4", "memory": "4Gi", }, - "storage": map[string]interface{}{ + "storage": map[string]any{ "size": "16Gi", }, - "firmware": map[string]interface{}{ + "firmware": map[string]any{ "url": "registry.example.com/fw:v1", }, } - override := map[string]interface{}{ - "resources": map[string]interface{}{ + override := map[string]any{ + "resources": map[string]any{ "memory": "8Gi", }, } result := deepMerge(base, override) - resources := result["resources"].(map[string]interface{}) + resources := result["resources"].(map[string]any) if resources["cpu"] != "4" { t.Errorf("cpu = %v, want 4", resources["cpu"]) } @@ -1024,20 +1024,20 @@ func TestDeepMerge_mapsRecursive(t *testing.T) { t.Errorf("memory = %v, want 8Gi", resources["memory"]) } - storage := result["storage"].(map[string]interface{}) + storage := result["storage"].(map[string]any) if storage["size"] != "16Gi" { t.Errorf("storage.size = %v, want 16Gi", storage["size"]) } - firmware := result["firmware"].(map[string]interface{}) + firmware := result["firmware"].(map[string]any) if firmware["url"] != "registry.example.com/fw:v1" { t.Errorf("firmware.url = %v, want original", firmware["url"]) } } func TestDeepMerge_scalarReplace(t *testing.T) { - base := map[string]interface{}{"machineType": "virt"} - override := map[string]interface{}{"machineType": "q35"} + base := map[string]any{"machineType": "virt"} + override := map[string]any{"machineType": "q35"} result := deepMerge(base, override) if result["machineType"] != "q35" { @@ -1046,11 +1046,11 @@ func TestDeepMerge_scalarReplace(t *testing.T) { } func TestDeepMerge_listReplace(t *testing.T) { - base := map[string]interface{}{"ports": []interface{}{22, 80}} - override := map[string]interface{}{"ports": []interface{}{443}} + base := map[string]any{"ports": []any{22, 80}} + override := map[string]any{"ports": []any{443}} result := deepMerge(base, override) - ports := result["ports"].([]interface{}) + ports := result["ports"].([]any) if len(ports) != 1 || ports[0] != 443 { t.Errorf("ports = %v, want [443]", ports) } @@ -1915,7 +1915,7 @@ func TestEnsureExporterPods_skipsDisabledExporters(t *testing.T) { exp2 := makeExporter("exp-2", false, false, true) exp2.Status.Credential = &corev1.LocalObjectReference{Name: "exp-2-exporter"} exp2.Status.Endpoint = testEndpoint - exp2.Spec.Enabled = boolPtr(false) + exp2.Spec.Enabled = new(false) credSecret := makeCredentialSecret("exp-2") r, _ := newReconciler(t, es, makeVTC(), makeCACM(), exp2, credSecret) diff --git a/controller/internal/log/levels.go b/controller/internal/log/levels.go index 151748a97..23f6b6d30 100644 --- a/controller/internal/log/levels.go +++ b/controller/internal/log/levels.go @@ -48,31 +48,31 @@ func WithLevel(logger logr.Logger, level int) logr.Logger { } // Error logs an error message (always shown) -func Error(logger logr.Logger, err error, msg string, keysAndValues ...interface{}) { +func Error(logger logr.Logger, err error, msg string, keysAndValues ...any) { logger.Error(err, msg, keysAndValues...) } // Warning logs a warning message -func Warning(logger logr.Logger, msg string, keysAndValues ...interface{}) { +func Warning(logger logr.Logger, msg string, keysAndValues ...any) { logger.V(LevelWarning).Info(msg, keysAndValues...) } // Info logs an info message -func Info(logger logr.Logger, msg string, keysAndValues ...interface{}) { +func Info(logger logr.Logger, msg string, keysAndValues ...any) { logger.V(LevelInfo).Info(msg, keysAndValues...) } // Debug logs a debug message -func Debug(logger logr.Logger, msg string, keysAndValues ...interface{}) { +func Debug(logger logr.Logger, msg string, keysAndValues ...any) { logger.V(LevelDebug).Info(msg, keysAndValues...) } // Trace logs a trace message -func Trace(logger logr.Logger, msg string, keysAndValues ...interface{}) { +func Trace(logger logr.Logger, msg string, keysAndValues ...any) { logger.V(LevelTrace).Info(msg, keysAndValues...) } // Verbose logs a very verbose trace message -func Verbose(logger logr.Logger, msg string, keysAndValues ...interface{}) { +func Verbose(logger logr.Logger, msg string, keysAndValues ...any) { logger.V(LevelVerbose).Info(msg, keysAndValues...) } diff --git a/controller/internal/metrics/lease.go b/controller/internal/metrics/lease.go index 91b1f03bd..61f042ba0 100644 --- a/controller/internal/metrics/lease.go +++ b/controller/internal/metrics/lease.go @@ -192,7 +192,7 @@ func truncateRunes(s string, maxRunes int) string { return s } i := 0 - for n := 0; n < maxRunes; n++ { + for range maxRunes { _, size := utf8.DecodeRuneInString(s[i:]) i += size } diff --git a/controller/internal/oidc/op.go b/controller/internal/oidc/op.go index d24b9c52a..076f152e4 100644 --- a/controller/internal/oidc/op.go +++ b/controller/internal/oidc/op.go @@ -91,7 +91,7 @@ func (k *Signer) SetTokenLifetime(d time.Duration) { } func (k *Signer) Validate(token string) error { - _, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { + _, err := jwt.Parse(token, func(t *jwt.Token) (any, error) { return &k.privatekey.PublicKey, nil }, jwt.WithValidMethods([]string{ @@ -106,7 +106,7 @@ func (k *Signer) Validate(token string) error { // ParseSubject validates the token and returns the subject claim. func (k *Signer) ParseSubject(token string) (string, error) { claims := &jwt.RegisteredClaims{} - _, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) { + _, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (any, error) { return &k.privatekey.PublicKey, nil }, jwt.WithValidMethods([]string{ diff --git a/controller/internal/service/controller_service_test.go b/controller/internal/service/controller_service_test.go index 2848d3cbd..6d9a58e28 100644 --- a/controller/internal/service/controller_service_test.go +++ b/controller/internal/service/controller_service_test.go @@ -673,7 +673,7 @@ func TestListenQueueStaleReaderConsumesDialToken(t *testing.T) { func TestListenQueueStaleReaderAlwaysDetectsSupersession(t *testing.T) { iterations := 100 - for i := 0; i < iterations; i++ { + for i := range iterations { svc := &ControllerService{} leaseName := "test-lease-concurrent" @@ -747,7 +747,7 @@ func TestDialRejectsSupersededQueue(t *testing.T) { func TestDialWithPreSwapReferenceNeverSendsToStaleQueue(t *testing.T) { iterations := 500 - for i := 0; i < iterations; i++ { + for i := range iterations { svc := &ControllerService{} leaseName := "test-lease-pre-swap-ref" @@ -893,7 +893,7 @@ func TestDialSendToListenerSerializesWithSwap(t *testing.T) { // This tests the scenario where the swap completes before the send. iterations := 500 - for i := 0; i < iterations; i++ { + for i := range iterations { svc := &ControllerService{} leaseName := "test-lease-serialized" @@ -949,7 +949,7 @@ func TestDialSendToListenerConcurrentWithSwapNeverLandsOnSuperseded(t *testing.T sentToG2 := 0 rejected := 0 - for i := 0; i < iterations; i++ { + for i := range iterations { svc := &ControllerService{} leaseName := "test-lease-concurrent-serial" @@ -1255,10 +1255,8 @@ func TestListenQueueConcurrentDialDuringReconnection(t *testing.T) { var g2 *listenQueue g2ListenerDone := make(chan struct{}) - for i := 0; i < dialAttempts; i++ { - dialWg.Add(1) - go func() { - defer dialWg.Done() + for i := range dialAttempts { + dialWg.Go(func() { ctx := context.Background() err := svc.sendToListener(ctx, leaseName, &pb.ListenResponse{ RouterEndpoint: "ep", RouterToken: testRouterToken, @@ -1272,7 +1270,7 @@ func TestListenQueueConcurrentDialDuringReconnection(t *testing.T) { sentMu.Lock() sentCount++ sentMu.Unlock() - }() + }) if i == 25 { g2 = &listenQueue{ @@ -1375,7 +1373,7 @@ func TestListenQueueListenLoopDeliversTokensAndExitsOnDone(t *testing.T) { wrapper.ch <- &pb.ListenResponse{RouterEndpoint: "ep1", RouterToken: "tok1"} wrapper.ch <- &pb.ListenResponse{RouterEndpoint: "ep2", RouterToken: "tok2"} - for i := 0; i < 2; i++ { + for range 2 { select { case msg := <-delivered: if msg.RouterEndpoint == "" || msg.RouterToken == "" { @@ -1417,7 +1415,7 @@ func TestSendToListenerReturnsResourceExhaustedWithCancelledContextAndBufferFull } svc.swapListenQueue(leaseName, q) - for i := 0; i < 8; i++ { + for range 8 { q.ch <- &pb.ListenResponse{RouterEndpoint: "fill", RouterToken: "fill"} } @@ -1450,7 +1448,7 @@ func TestSendToListenerReturnsImmediatelyDuringBackpressure(t *testing.T) { } svc.swapListenQueue(leaseName, q) - for i := 0; i < 8; i++ { + for range 8 { q.ch <- &pb.ListenResponse{RouterEndpoint: "fill", RouterToken: "fill"} } @@ -1544,13 +1542,11 @@ func TestLeaseLockRefCountConcurrentAcquireRelease(t *testing.T) { var wg sync.WaitGroup goroutines := 100 - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range goroutines { + wg.Go(func() { svc.acquireLeaseLock(leaseName) svc.releaseLeaseLock(leaseName) - }() + }) } wg.Wait() @@ -1570,10 +1566,8 @@ func TestLeaseLockRefCountConcurrentOverlappingListeners(t *testing.T) { allAcquired := sync.WaitGroup{} allAcquired.Add(goroutines) - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range goroutines { + wg.Go(func() { mu := svc.acquireLeaseLock(leaseName) defer svc.releaseLeaseLock(leaseName) @@ -1583,7 +1577,7 @@ func TestLeaseLockRefCountConcurrentOverlappingListeners(t *testing.T) { mu.Lock() counter++ mu.Unlock() - }() + }) } wg.Wait() @@ -1669,7 +1663,7 @@ func TestSendToListenerReturnsResourceExhaustedWhenBufferFull(t *testing.T) { } svc.swapListenQueue(leaseName, q) - for i := 0; i < 8; i++ { + for range 8 { q.ch <- &pb.ListenResponse{RouterEndpoint: "fill", RouterToken: "fill"} } @@ -1699,7 +1693,7 @@ func TestSendToListenerDoesNotBlockMutexWhenBufferFull(t *testing.T) { } svc.swapListenQueue(leaseName, q) - for i := 0; i < 8; i++ { + for range 8 { q.ch <- &pb.ListenResponse{RouterEndpoint: "fill", RouterToken: "fill"} } @@ -1748,7 +1742,7 @@ func TestSwapNotBlockedWhenBufferFull(t *testing.T) { } svc.swapListenQueue(leaseName, g1) - for i := 0; i < 8; i++ { + for range 8 { g1.ch <- &pb.ListenResponse{RouterEndpoint: "fill", RouterToken: "fill"} } diff --git a/controller/internal/service/dashboard_service.go b/controller/internal/service/dashboard_service.go index 0fbf93ae8..223b44034 100644 --- a/controller/internal/service/dashboard_service.go +++ b/controller/internal/service/dashboard_service.go @@ -62,7 +62,7 @@ func (s *DashboardService) Start(ctx context.Context) error { return } - c.HTML(http.StatusOK, "index.html", map[string]interface{}{ + c.HTML(http.StatusOK, "index.html", map[string]any{ "Exporters": exporters.Items, "Clients": clients.Items, "Leases": leases.Items, diff --git a/controller/internal/service/login/service.go b/controller/internal/service/login/service.go index dbddd2e7d..b1c247885 100644 --- a/controller/internal/service/login/service.go +++ b/controller/internal/service/login/service.go @@ -178,7 +178,7 @@ func (s *Service) SetupWithManager(mgr ctrl.Manager) error { // handleLandingPage serves the landing page with login instructions func (s *Service) handleLandingPage(c *gin.Context) { - c.HTML(http.StatusOK, "index.html", map[string]interface{}{ + c.HTML(http.StatusOK, "index.html", map[string]any{ "GRPCEndpoint": s.config.GRPCEndpoint, "RouterEndpoint": s.config.RouterEndpoint, "LoginEndpoint": s.config.LoginEndpoint, diff --git a/controller/test/utils/utils.go b/controller/test/utils/utils.go index fe909c7c2..c2cefca52 100644 --- a/controller/test/utils/utils.go +++ b/controller/test/utils/utils.go @@ -121,8 +121,8 @@ func LoadImageToKindClusterWithName(name string) error { // according to line breakers, and ignores the empty elements in it. func GetNonEmptyLines(output string) []string { var res []string - elements := strings.Split(output, "\n") - for _, element := range elements { + elements := strings.SplitSeq(output, "\n") + for element := range elements { if element != "" { res = append(res, element) }