From cf39eaf1b6056edc6e9d8c0265d396bd590d9259 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 6 Aug 2025 12:48:45 +0100 Subject: [PATCH 1/6] fix: Correctly handle variable overrides Currently the metamutator only passes the override values when they are present on a machine deployment or control plane config. This commit fixes that by merging the global variables into the overrides, resulting in the behaviour that we always expected. As overrides are not that commonly used yet, we have not seen this issue but as taints, etc become more commonly used this will become an issue. Tests added to prove the fix as well. --- common/go.mod | 1 + common/go.sum | 2 + .../clustertopology/handlers/mutation/meta.go | 99 ++++++- .../handlers/mutation/meta_test.go | 259 +++++++++++++++++- 4 files changed, 348 insertions(+), 13 deletions(-) diff --git a/common/go.mod b/common/go.mod index a63225853..2cc935643 100644 --- a/common/go.mod +++ b/common/go.mod @@ -8,6 +8,7 @@ go 1.23.0 toolchain go1.24.5 require ( + dario.cat/mergo v1.0.1 github.com/evanphx/json-patch/v5 v5.9.11 github.com/go-logr/logr v1.4.3 github.com/onsi/ginkgo/v2 v2.23.4 diff --git a/common/go.sum b/common/go.sum index 89a0aff51..d8dc81310 100644 --- a/common/go.sum +++ b/common/go.sum @@ -1,5 +1,7 @@ cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo= cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= diff --git a/common/pkg/capi/clustertopology/handlers/mutation/meta.go b/common/pkg/capi/clustertopology/handlers/mutation/meta.go index 13aef75ad..d2a75782d 100644 --- a/common/pkg/capi/clustertopology/handlers/mutation/meta.go +++ b/common/pkg/capi/clustertopology/handlers/mutation/meta.go @@ -5,9 +5,13 @@ package mutation import ( "context" + "encoding/json" "fmt" + "maps" "sync" + "dario.cat/mergo" + "github.com/samber/lo" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -89,6 +93,21 @@ func (mgp metaGeneratePatches) GeneratePatches( ) { clusterKey := handlers.ClusterKeyFromReq(req) clusterGetter := mgp.CreateClusterGetter(clusterKey) + + // Create a map of variables from the request that can be overridden by machine deployment or control plane + // configuration. + // Filter out the "builtin" variable, which is already present in the vars map and should not be overridden by + // the global variables. + globalVars := lo.FilterSliceToMap( + req.Variables, + func(v runtimehooksv1.Variable) (string, apiextensionsv1.JSON, bool) { + if v.Name == "builtin" { + return "", apiextensionsv1.JSON{}, false + } + return v.Name, v.Value, true + }, + ) + topologymutation.WalkTemplates( ctx, unstructured.UnstructuredJSONScheme, @@ -108,16 +127,33 @@ func (mgp metaGeneratePatches) GeneratePatches( log.V(3).Info("Starting mutation pipeline", "handlerCount", len(mgp.mutators)) - for i, h := range mgp.mutators { - handlerName := fmt.Sprintf("%T", h) - log.V(5).Info("Running mutator", "index", i, "handler", handlerName) + // Merge the global variables to the current resource vars. This allows the handlers to access + // the variables defined in the cluster class or cluster configuration and use these correctly when + // overrides are specified on machine deployment or control plane configuration. + mergedVars, err := mergeVariableDefinitions(vars, globalVars) + if err != nil { + log.Error(err, "Failed to merge global variables") + return err + } - if err := h.Mutate(ctx, obj.(*unstructured.Unstructured), vars, holderRef, clusterKey, clusterGetter); err != nil { - log.Error(err, "Mutator failed", "index", i, "handler", handlerName) + for i, h := range mgp.mutators { + mutatorType := fmt.Sprintf("%T", h) + log.V(5). + Info("Running mutator", "index", i, "handler", mutatorType, "vars", vars) + + if err := h.Mutate( + ctx, + obj.(*unstructured.Unstructured), + mergedVars, + holderRef, + clusterKey, + clusterGetter, + ); err != nil { + log.Error(err, "Mutator failed", "index", i, "handler", mutatorType) return err } - log.V(5).Info("Mutator completed successfully", "index", i, "handler", handlerName) + log.V(5).Info("Mutator completed successfully", "index", i, "handler", mutatorType) } log.V(3).Info("Mutation pipeline completed successfully", "handlerCount", len(mgp.mutators)) @@ -125,3 +161,54 @@ func (mgp metaGeneratePatches) GeneratePatches( }, ) } + +func mergeVariableDefinitions( + vars, globalVars map[string]apiextensionsv1.JSON, +) (map[string]apiextensionsv1.JSON, error) { + mergedVars := maps.Clone(vars) + + for k, v := range globalVars { + // If the value of v is nil, skip it. + if v.Raw == nil { + continue + } + + existingValue, exists := mergedVars[k] + + // If the variable does not exist in the mergedVars or the value is nil, add it and continue. + if !exists || existingValue.Raw == nil { + mergedVars[k] = v + continue + } + + // Wrap the value in a temporary key to ensure we can unmarshal to a map. + // This is necessary because the values could be scalars. + tempValJSON := fmt.Sprintf(`{"value": %s}`, string(existingValue.Raw)) + tempGlobalValJSON := fmt.Sprintf(`{"value": %s}`, string(v.Raw)) + + // Unmarshal the existing value and the global value into maps. + var val, globalVal map[string]interface{} + if err := json.Unmarshal([]byte(tempValJSON), &val); err != nil { + return nil, fmt.Errorf("failed to unmarshal existing value for key %q: %w", k, err) + } + + if err := json.Unmarshal([]byte(tempGlobalValJSON), &globalVal); err != nil { + return nil, fmt.Errorf("failed to unmarshal global value for key %q: %w", k, err) + } + + // Now use mergo to perform a deep merge of the values, retaining the values in `val` if present. + if err := mergo.Merge(&val, globalVal); err != nil { + return nil, fmt.Errorf("failed to merge values for key %q: %w", k, err) + } + + // Marshal the merged value back to JSON. + mergedVal, err := json.Marshal(val["value"]) + if err != nil { + return nil, fmt.Errorf("failed to marshal merged value for key %q: %w", k, err) + } + + mergedVars[k] = apiextensionsv1.JSON{Raw: mergedVal} + } + + return mergedVars, nil +} diff --git a/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go b/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go index 66c75b9c2..89ca5a96d 100644 --- a/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go +++ b/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go @@ -34,7 +34,7 @@ var _ MetaMutator = &testHandler{} func (h *testHandler) Mutate( _ context.Context, obj *unstructured.Unstructured, - _ map[string]apiextensionsv1.JSON, + vars map[string]apiextensionsv1.JSON, holderRef runtimehooksv1.HolderReference, _ client.ObjectKey, _ ClusterGetter, @@ -43,6 +43,31 @@ func (h *testHandler) Mutate( return fmt.Errorf("This is a failure") } + varAVal, ok := vars["varA"] + if !ok { + return fmt.Errorf("varA not found in vars") + } + if string(varAVal.Raw) != `{"a":1,"b":2}` { + return fmt.Errorf("varA value mismatch: %s", string(varAVal.Raw)) + } + + varBVal, ok := vars["varB"] + if !ok { + return fmt.Errorf("varB not found in vars") + } + switch obj.GetKind() { + case "KubeadmControlPlaneTemplate": + if string(varBVal.Raw) != `{"c":3,"d":{"e":4,"f":5}}` { + return fmt.Errorf("varB value mismatch: %s", string(varBVal.Raw)) + } + case "KubeadmConfigTemplate": + if string(varBVal.Raw) != `{"c":3,"d":{"e":5,"f":5}}` { + return fmt.Errorf("varB value mismatch: %s", string(varBVal.Raw)) + } + default: + return fmt.Errorf("unexpected object kind: %s", obj.GetKind()) + } + if h.mutateControlPlane { return patches.MutateIfApplicable( obj, nil, &holderRef, selectors.ControlPlane(), logr.Discard(), @@ -61,7 +86,7 @@ func (h *testHandler) Mutate( return patches.MutateIfApplicable( obj, - machineVars(), + vars, &holderRef, selectors.WorkersKubeadmConfigTemplateSelector(), logr.Discard(), @@ -78,10 +103,32 @@ func (h *testHandler) Mutate( ) } -func machineVars() map[string]apiextensionsv1.JSON { - return map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`)}, - } +func globalVars() []runtimehooksv1.Variable { + return []runtimehooksv1.Variable{{ + Name: "varA", + Value: apiextensionsv1.JSON{ + Raw: []byte(`{"a": 1, "b": 2}`), + }, + }, { + Name: "varB", + Value: apiextensionsv1.JSON{ + Raw: []byte(`{"c": 3, "d": {"e": 4, "f": 5}}`), + }, + }} +} + +func overrideVars() []runtimehooksv1.Variable { + return []runtimehooksv1.Variable{{ + Name: "builtin", + Value: apiextensionsv1.JSON{ + Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), + }, + }, { + Name: "varB", + Value: apiextensionsv1.JSON{ + Raw: []byte(`{"d": {"e": 5}}`), + }, + }} } func TestMetaGeneratePatches(t *testing.T) { @@ -221,9 +268,12 @@ func TestMetaGeneratePatches(t *testing.T) { h := NewMetaGeneratePatchesHandler("", nil, tt.mutaters...).(GeneratePatches) resp := &runtimehooksv1.GeneratePatchesResponse{} + kctReq := request.NewKubeadmConfigTemplateRequestItem("kubeadm-config") + kctReq.Variables = overrideVars() h.GeneratePatches(context.Background(), &runtimehooksv1.GeneratePatchesRequest{ + Variables: globalVars(), Items: []runtimehooksv1.GeneratePatchesRequestItem{ - request.NewKubeadmConfigTemplateRequestItem("kubeadm-config"), + kctReq, request.NewKubeadmControlPlaneTemplateRequestItem("kubeadm-control-plane"), }, }, resp) @@ -239,3 +289,198 @@ func jsonPatch(operations ...jsonpatch.Operation) []byte { ) return b } + +func TestMergeVariableDefinitions(t *testing.T) { + t.Parallel() + + type args struct { + vars map[string]apiextensionsv1.JSON + globalVars map[string]apiextensionsv1.JSON + } + tests := []struct { + name string + args args + want map[string]apiextensionsv1.JSON + wantErr bool + errString string + }{ + { + name: "no overlap, globalVars added", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`1`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "b": {Raw: []byte(`2`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`1`)}, + "b": {Raw: []byte(`2`)}, + }, + }, + { + name: "globalVars value is nil, skipped", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`1`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "b": {Raw: nil}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`1`)}, + }, + }, + { + name: "existing value is nil, globalVars value used", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: nil}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`2`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`2`)}, + }, + }, + { + name: "both values are scalars, globalVars ignored", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`1`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`2`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`1`)}, + }, + }, + { + name: "both values are objects, merged", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1,"y":2}`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"y":3,"z":4}`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1,"y":2,"z":4}`)}, + }, + }, + { + name: "both values are objects with nested objects, merged", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1,"y":{"a": 2,"b":{"c": 3}}}`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"y":{"a": 2,"b":{"c": 5, "d": 6}},"z":4}`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1,"y":{"a": 2,"b":{"c": 3, "d": 6}},"z":4}`)}, + }, + }, + { + name: "both values are objects with nested objects with vars having nil object explicitly, merged", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1,"y":{"a": 2,"b": null}}`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"y":{"a": 2,"b":{"c": 5, "d": 6}},"z":4}`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1,"y":{"a": 2,"b":{"c": 5, "d": 6}},"z":4}`)}, + }, + }, + { + name: "globalVars is scalar, vars is object, keep object", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1}`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`2`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1}`)}, + }, + }, + { + name: "vars is scalar, globalVars is object, keep scalar", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`2`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1}`)}, + }, + }, + want: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`2`)}, + }, + }, + { + name: "invalid JSON in vars", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{invalid}`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1}`)}, + }, + }, + wantErr: true, + errString: "failed to unmarshal existing value for key \"a\"", + }, + { + name: "invalid JSON in globalVars", + args: args{ + vars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{"x":1}`)}, + }, + globalVars: map[string]apiextensionsv1.JSON{ + "a": {Raw: []byte(`{invalid}`)}, + }, + }, + wantErr: true, + errString: "failed to unmarshal global value for key \"a\"", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + got, err := mergeVariableDefinitions(tt.args.vars, tt.args.globalVars) + if tt.wantErr { + g.Expect(err).To(gomega.HaveOccurred()) + g.Expect(err.Error()).To(gomega.ContainSubstring(tt.errString)) + return + } + g.Expect(err).ToNot(gomega.HaveOccurred()) + // Compare JSON values + for k, wantVal := range tt.want { + gotVal, ok := got[k] + g.Expect(ok).To(gomega.BeTrue(), "missing key %q", k) + var wantObj, gotObj interface{} + _ = json.Unmarshal(wantVal.Raw, &wantObj) + _ = json.Unmarshal(gotVal.Raw, &gotObj) + g.Expect(gotObj).To(gomega.Equal(wantObj), "key %q", k) + } + // Check for unexpected keys + g.Expect(len(got)).To(gomega.Equal(len(tt.want))) + }) + } +} From 9037d6a80cebd700d3d136752aedf8a46a850f47 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 6 Aug 2025 14:09:15 +0100 Subject: [PATCH 2/6] feat: EKS ClusterClass and Cluster example The bases are included in the hack directory rather than pulling in from external projects as we do for other providers because the EKS CC support has not been released in CAPA yet. Once that has happened, we can switch to the same strategy and use the upstream CC and Cluster as the base for patching to create the CAREN CC/Cluster examples. --- .../eks-cluster-class.yaml | 113 +++++++++++++++++ .../templates/clusterclass_eks.yaml | 6 + examples/capi-quick-start/eks-cluster.yaml | 120 ++++++++++++++++++ hack/examples/bases/eks/cluster/cluster.yaml | 100 +++++++++++++++ .../bases/eks/cluster/kustomization.yaml.tmpl | 36 ++++++ .../bases/eks/clusterclass/clusterclass.yaml | 81 ++++++++++++ .../eks/clusterclass/kustomization.yaml.tmpl | 16 +++ .../eks/kustomization.yaml.tmpl | 59 +++++++++ .../clusterclasses/eks/kustomizeconfig.yaml | 22 ++++ .../clusters/eks/kustomization.yaml.tmpl | 11 ++ hack/examples/patches/eks/ami-lookup.yaml | 12 ++ hack/examples/patches/eks/config-var.yaml | 7 + hack/examples/patches/eks/csi.yaml | 14 ++ .../patches/eks/initialize-variables.yaml | 21 +++ .../eks/start-ssm-kubeadmconfigtemplate.yaml | 7 + hack/examples/sync.sh | 10 ++ make/clusterctl.mk | 4 +- 17 files changed, 637 insertions(+), 2 deletions(-) create mode 100644 charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_eks.yaml create mode 100644 examples/capi-quick-start/eks-cluster.yaml create mode 100644 hack/examples/bases/eks/cluster/cluster.yaml create mode 100644 hack/examples/bases/eks/cluster/kustomization.yaml.tmpl create mode 100644 hack/examples/bases/eks/clusterclass/clusterclass.yaml create mode 100644 hack/examples/bases/eks/clusterclass/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusterclasses/eks/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusterclasses/eks/kustomizeconfig.yaml create mode 100644 hack/examples/overlays/clusters/eks/kustomization.yaml.tmpl create mode 100644 hack/examples/patches/eks/ami-lookup.yaml create mode 100644 hack/examples/patches/eks/config-var.yaml create mode 100644 hack/examples/patches/eks/csi.yaml create mode 100644 hack/examples/patches/eks/initialize-variables.yaml create mode 100644 hack/examples/patches/eks/start-ssm-kubeadmconfigtemplate.yaml diff --git a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml new file mode 100644 index 000000000..174e43748 --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml @@ -0,0 +1,113 @@ +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + labels: + cluster.x-k8s.io/provider: eks + name: eks-quick-start +spec: + controlPlane: + ref: + apiVersion: controlplane.cluster.x-k8s.io/v1beta2 + kind: AWSManagedControlPlaneTemplate + name: eks-quick-start-control-plane + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + kind: AWSManagedClusterTemplate + name: eks-quick-start + patches: + - external: + discoverVariablesExtension: eksclusterconfigvars-dv.cluster-api-runtime-extensions-nutanix + generateExtension: eksclusterv1configpatch-gp.cluster-api-runtime-extensions-nutanix + name: cluster-config + - external: + discoverVariablesExtension: eksworkerconfigvars-dv.cluster-api-runtime-extensions-nutanix + generateExtension: eksworkerv1configpatch-gp.cluster-api-runtime-extensions-nutanix + name: worker-config + - definitions: + - jsonPatches: + - op: add + path: /spec/template/spec/identityRef + value: + kind: AWSClusterControllerIdentity + name: default + selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta2 + kind: AWSManagedControlPlaneTemplate + matchResources: + controlPlane: true + description: AWSClusterStaticIdentity identityRef to use when creating the cluster + name: identityRef + workers: + machineDeployments: + - class: default-worker + template: + bootstrap: + ref: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 + kind: EKSConfigTemplate + name: eks-quick-start-worker-configtemplate + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + kind: AWSMachineTemplate + name: eks-quick-start-worker-machinetemplate + - class: system-worker + template: + bootstrap: + ref: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 + kind: EKSConfigTemplate + name: eks-quick-start-worker-configtemplate + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + kind: AWSMachineTemplate + name: eks-quick-start-worker-machinetemplate +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 +kind: AWSManagedClusterTemplate +metadata: + labels: + cluster.x-k8s.io/provider: eks + name: eks-quick-start +spec: + template: + spec: {} +--- +apiVersion: controlplane.cluster.x-k8s.io/v1beta2 +kind: AWSManagedControlPlaneTemplate +metadata: + labels: + cluster.x-k8s.io/provider: eks + name: eks-quick-start-control-plane +spec: + template: + spec: + bootstrapSelfManagedAddons: false + kubeProxy: + disable: true + vpcCni: + disable: true +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 +kind: AWSMachineTemplate +metadata: + labels: + cluster.x-k8s.io/provider: eks + name: eks-quick-start-worker-machinetemplate +spec: + template: + spec: + instanceType: PLACEHOLDER + sshKeyName: "" +--- +apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 +kind: EKSConfigTemplate +metadata: + labels: + cluster.x-k8s.io/provider: eks + name: eks-quick-start-worker-configtemplate +spec: + template: + spec: {} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_eks.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_eks.yaml new file mode 100644 index 000000000..a8accb04f --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_eks.yaml @@ -0,0 +1,6 @@ +# Copyright 2023 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if and .Values.deployDefaultClusterClasses (.Capabilities.APIVersions.Has "infrastructure.cluster.x-k8s.io/v1beta2/AWSManagedClusterTemplate") }} +{{ .Files.Get "defaultclusterclasses/eks-cluster-class.yaml" }} +{{- end}} diff --git a/examples/capi-quick-start/eks-cluster.yaml b/examples/capi-quick-start/eks-cluster.yaml new file mode 100644 index 000000000..f47d6480a --- /dev/null +++ b/examples/capi-quick-start/eks-cluster.yaml @@ -0,0 +1,120 @@ +apiVersion: v1 +data: + values.yaml: |- + cni: + exclusive: false + hubble: + enabled: true + tls: + auto: + enabled: true # enable automatic TLS certificate generation + method: cronJob # auto generate certificates using cronJob method + certValidityDuration: 60 # certificates validity duration in days (default 2 months) + schedule: "0 0 1 * *" # schedule on the 1st day regeneration of each month + relay: + enabled: true + tls: + server: + enabled: true + mtls: true + image: + useDigest: false + priorityClassName: system-cluster-critical + image: + useDigest: false + operator: + image: + useDigest: false + certgen: + image: + useDigest: false + socketLB: + hostNamespaceOnly: true + envoy: + image: + useDigest: false + kubeProxyReplacement: true + k8sServiceHost: "{{ trimPrefix "https://" .Cluster.spec.controlPlaneEndpoint.host }}" + k8sServicePort: "{{ .Cluster.spec.controlPlaneEndpoint.port }}" + ipam: + mode: eni + enableIPv4Masquerade: false + eni: + enabled: true + awsReleaseExcessIPs: true + routingMode: native + endpointRoutes: + enabled: true +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: eks + name: ${CLUSTER_NAME}-cilium-cni-helm-values-template +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + annotations: + preflight.cluster.caren.nutanix.com/skip: all + labels: + cluster.x-k8s.io/provider: eks + name: ${CLUSTER_NAME} +spec: + topology: + class: eks-quick-start + controlPlane: + metadata: + annotations: + controlplane.cluster.x-k8s.io/skip-kube-proxy: "" + variables: + - name: clusterConfig + value: + addons: + clusterAutoscaler: {} + cni: + provider: Cilium + values: + sourceRef: + kind: ConfigMap + name: ${CLUSTER_NAME}-cilium-cni-helm-values-template + csi: + defaultStorage: + provider: aws-ebs + storageClassConfig: default + providers: + aws-ebs: + storageClassConfigs: + default: {} + snapshotController: {} + nfd: {} + eks: + region: us-west-2 + - name: workerConfig + value: + eks: + instanceType: m5.2xlarge + version: ${KUBERNETES_VERSION} + workers: + machineDeployments: + - class: default-worker + metadata: + annotations: + cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "${WORKER_MACHINE_COUNT}" + cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "${WORKER_MACHINE_COUNT}" + name: md-0 + - class: system-worker + metadata: + labels: + node-restriction.kubernetes.io/capi-controllers: "" + name: system + replicas: 1 + variables: + overrides: + - name: workerConfig + value: + eks: + iamInstanceProfile: control-plane.cluster-api-provider-aws.sigs.k8s.io + taints: + - effect: NoSchedule + key: node-restriction.kubernetes.io/capi-controllers + value: "true" diff --git a/hack/examples/bases/eks/cluster/cluster.yaml b/hack/examples/bases/eks/cluster/cluster.yaml new file mode 100644 index 000000000..9c693a125 --- /dev/null +++ b/hack/examples/bases/eks/cluster/cluster.yaml @@ -0,0 +1,100 @@ +apiVersion: v1 +data: + values.yaml: |- + cni: + exclusive: false + hubble: + enabled: true + tls: + auto: + enabled: true # enable automatic TLS certificate generation + method: cronJob # auto generate certificates using cronJob method + certValidityDuration: 60 # certificates validity duration in days (default 2 months) + schedule: "0 0 1 * *" # schedule on the 1st day regeneration of each month + relay: + enabled: true + tls: + server: + enabled: true + mtls: true + image: + useDigest: false + priorityClassName: system-cluster-critical + image: + useDigest: false + operator: + image: + useDigest: false + certgen: + image: + useDigest: false + socketLB: + hostNamespaceOnly: true + envoy: + image: + useDigest: false + kubeProxyReplacement: true + k8sServiceHost: "{{ trimPrefix "https://" .Cluster.spec.controlPlaneEndpoint.host }}" + k8sServicePort: "{{ .Cluster.spec.controlPlaneEndpoint.port }}" + ipam: + mode: eni + enableIPv4Masquerade: false + eni: + enabled: true + awsReleaseExcessIPs: true + routingMode: native + endpointRoutes: + enabled: true +kind: ConfigMap +metadata: + name: ${CLUSTER_NAME}-cilium-cni-helm-values-template +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: ${CLUSTER_NAME} + annotations: + preflight.cluster.caren.nutanix.com/skip: all +spec: + topology: + class: eks-quick-start + version: ${KUBERNETES_VERSION} + variables: + - name: clusterConfig + value: + addons: + cni: + provider: Cilium + values: + sourceRef: + name: ${CLUSTER_NAME}-cilium-cni-helm-values-template + kind: ConfigMap + - name: workerConfig + value: + eks: + instanceType: m5.2xlarge + controlPlane: + metadata: + annotations: + controlplane.cluster.x-k8s.io/skip-kube-proxy: "" + workers: + machineDeployments: + - class: default-worker + name: md-0 + replicas: ${WORKER_MACHINE_COUNT} + - class: system-worker + name: system + metadata: + labels: + node-restriction.kubernetes.io/capi-controllers: "" + replicas: 1 + variables: + overrides: + - name: workerConfig + value: + taints: + - effect: NoSchedule + key: node-restriction.kubernetes.io/capi-controllers + value: "true" + eks: + iamInstanceProfile: "control-plane.cluster-api-provider-aws.sigs.k8s.io" diff --git a/hack/examples/bases/eks/cluster/kustomization.yaml.tmpl b/hack/examples/bases/eks/cluster/kustomization.yaml.tmpl new file mode 100644 index 000000000..6310f1242 --- /dev/null +++ b/hack/examples/bases/eks/cluster/kustomization.yaml.tmpl @@ -0,0 +1,36 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- cluster.yaml + +sortOptions: + order: fifo + +labels: +- includeSelectors: false + pairs: + cluster.x-k8s.io/provider: eks + +patches: +- target: + kind: Cluster + patch: |- + - op: "add" + path: "/spec/topology/class" + value: "eks-quick-start" +- target: + kind: Cluster + path: ../../../patches/eks/initialize-variables.yaml +- target: + kind: Cluster + path: ../../../patches/cluster-autoscaler.yaml +- target: + kind: Cluster + path: ../../../patches/eks/csi.yaml +- target: + kind: Cluster + path: ../../../patches/eks/config-var.yaml diff --git a/hack/examples/bases/eks/clusterclass/clusterclass.yaml b/hack/examples/bases/eks/clusterclass/clusterclass.yaml new file mode 100644 index 000000000..d636cd340 --- /dev/null +++ b/hack/examples/bases/eks/clusterclass/clusterclass.yaml @@ -0,0 +1,81 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + name: quick-start +spec: + controlPlane: + ref: + apiVersion: controlplane.cluster.x-k8s.io/v1beta2 + kind: AWSManagedControlPlaneTemplate + name: "quick-start-control-plane" + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + kind: AWSManagedClusterTemplate + name: "quick-start" + workers: + machineDeployments: + - class: default-worker + template: + bootstrap: + ref: + name: "quick-start-worker-configtemplate" + apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 + kind: EKSConfigTemplate + infrastructure: + ref: + name: "quick-start-worker-machinetemplate" + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + kind: AWSMachineTemplate + - class: system-worker + template: + bootstrap: + ref: + name: "quick-start-worker-configtemplate" + apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 + kind: EKSConfigTemplate + infrastructure: + ref: + name: "quick-start-worker-machinetemplate" + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + kind: AWSMachineTemplate +--- +kind: AWSManagedClusterTemplate +apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 +metadata: + name: "quick-start" +spec: + template: + spec: {} +--- +kind: AWSManagedControlPlaneTemplate +apiVersion: controlplane.cluster.x-k8s.io/v1beta2 +metadata: + name: "quick-start-control-plane" +spec: + template: + spec: + vpcCni: + disable: true + kubeProxy: + disable: true + bootstrapSelfManagedAddons: false +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 +kind: AWSMachineTemplate +metadata: + name: "quick-start-worker-machinetemplate" +spec: + template: + spec: {} +--- +apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 +kind: EKSConfigTemplate +metadata: + name: "quick-start-worker-configtemplate" +spec: + template: + spec: {} diff --git a/hack/examples/bases/eks/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/eks/clusterclass/kustomization.yaml.tmpl new file mode 100644 index 000000000..b4d33889c --- /dev/null +++ b/hack/examples/bases/eks/clusterclass/kustomization.yaml.tmpl @@ -0,0 +1,16 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- clusterclass.yaml + +sortOptions: + order: fifo + +labels: +- includeSelectors: false + pairs: + cluster.x-k8s.io/provider: eks diff --git a/hack/examples/overlays/clusterclasses/eks/kustomization.yaml.tmpl b/hack/examples/overlays/clusterclasses/eks/kustomization.yaml.tmpl new file mode 100644 index 000000000..ca44c5d9a --- /dev/null +++ b/hack/examples/overlays/clusterclasses/eks/kustomization.yaml.tmpl @@ -0,0 +1,59 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../bases/eks/clusterclass + +sortOptions: + order: fifo + +namePrefix: eks- + +configurations: + - kustomizeconfig.yaml + +patches: + - target: + kind: ClusterClass + patch: |- + - op: "add" + path: "/spec/patches" + value: + - name: "cluster-config" + external: + generateExtension: "eksclusterv1configpatch-gp.cluster-api-runtime-extensions-nutanix" + discoverVariablesExtension: "eksclusterconfigvars-dv.cluster-api-runtime-extensions-nutanix" + - name: "worker-config" + external: + generateExtension: "eksworkerv1configpatch-gp.cluster-api-runtime-extensions-nutanix" + discoverVariablesExtension: "eksworkerconfigvars-dv.cluster-api-runtime-extensions-nutanix" + - name: identityRef + definitions: + - jsonPatches: + - op: add + path: /spec/template/spec/identityRef + value: + kind: AWSClusterControllerIdentity + name: default + selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta2 + kind: AWSManagedControlPlaneTemplate + matchResources: + controlPlane: true + description: AWSClusterStaticIdentity identityRef to use when creating the cluster + - target: + kind: AWSMachineTemplate + patch: |- + - op: "add" + path: "/spec/template/spec/sshKeyName" + value: "" + - target: + kind: AWSMachineTemplate + name: quick-start-worker-machinetemplate + patch: |- + - op: "add" + path: "/spec/template/spec/instanceType" + value: "PLACEHOLDER" diff --git a/hack/examples/overlays/clusterclasses/eks/kustomizeconfig.yaml b/hack/examples/overlays/clusterclasses/eks/kustomizeconfig.yaml new file mode 100644 index 000000000..327d4d811 --- /dev/null +++ b/hack/examples/overlays/clusterclasses/eks/kustomizeconfig.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +nameReference: + - kind: AWSMachineTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/controlPlane/machineInfrastructure/ref/name + - kind: ClusterClass + path: spec/workers/machineDeployments/template/infrastructure/ref/name + - kind: AWSManagedClusterTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/infrastructure/ref/name + - kind: AWSManagedControlPlaneTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/controlPlane/ref/name + - kind: EKSConfigTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/workers/machineDeployments/template/bootstrap/ref/name diff --git a/hack/examples/overlays/clusters/eks/kustomization.yaml.tmpl b/hack/examples/overlays/clusters/eks/kustomization.yaml.tmpl new file mode 100644 index 000000000..63c27d2ad --- /dev/null +++ b/hack/examples/overlays/clusters/eks/kustomization.yaml.tmpl @@ -0,0 +1,11 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../bases/eks/cluster + +sortOptions: + order: fifo diff --git a/hack/examples/patches/eks/ami-lookup.yaml b/hack/examples/patches/eks/ami-lookup.yaml new file mode 100644 index 000000000..d341f5297 --- /dev/null +++ b/hack/examples/patches/eks/ami-lookup.yaml @@ -0,0 +1,12 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables/1/value" + value: + eks: + ami: + lookup: + baseOS: "${AMI_LOOKUP_BASEOS}" + format: "${AMI_LOOKUP_FORMAT}" + org: "${AMI_LOOKUP_ORG}" diff --git a/hack/examples/patches/eks/config-var.yaml b/hack/examples/patches/eks/config-var.yaml new file mode 100644 index 000000000..001e3b33a --- /dev/null +++ b/hack/examples/patches/eks/config-var.yaml @@ -0,0 +1,7 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables/0/value/eks" + value: + region: us-west-2 diff --git a/hack/examples/patches/eks/csi.yaml b/hack/examples/patches/eks/csi.yaml new file mode 100644 index 000000000..ac0346ee5 --- /dev/null +++ b/hack/examples/patches/eks/csi.yaml @@ -0,0 +1,14 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables/0/value/addons/csi" + value: + defaultStorage: + provider: aws-ebs + storageClassConfig: default + providers: + aws-ebs: + storageClassConfigs: + default: {} + snapshotController: {} diff --git a/hack/examples/patches/eks/initialize-variables.yaml b/hack/examples/patches/eks/initialize-variables.yaml new file mode 100644 index 000000000..d9f060546 --- /dev/null +++ b/hack/examples/patches/eks/initialize-variables.yaml @@ -0,0 +1,21 @@ +# Copyright 2024 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables" + value: + - name: "clusterConfig" + value: + addons: + clusterAutoscaler: {} + nfd: {} + cni: + provider: Cilium + values: + sourceRef: + name: ${CLUSTER_NAME}-cilium-cni-helm-values-template + kind: ConfigMap + - name: "workerConfig" + value: + eks: + instanceType: m5.2xlarge diff --git a/hack/examples/patches/eks/start-ssm-kubeadmconfigtemplate.yaml b/hack/examples/patches/eks/start-ssm-kubeadmconfigtemplate.yaml new file mode 100644 index 000000000..4fcb8bcbd --- /dev/null +++ b/hack/examples/patches/eks/start-ssm-kubeadmconfigtemplate.yaml @@ -0,0 +1,7 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + + +- op: "add" + path: "/spec/template/spec/preKubeadmCommands/-" + value: systemctl enable --now amazon-ssm-agent diff --git a/hack/examples/sync.sh b/hack/examples/sync.sh index cff626deb..90a09c55f 100755 --- a/hack/examples/sync.sh +++ b/hack/examples/sync.sh @@ -37,6 +37,16 @@ for provider in "aws" "docker" "nutanix"; do done done +unset provider cni strategy + +kustomize build --load-restrictor LoadRestrictionsNone \ + ./hack/examples/overlays/clusterclasses/eks | + sed 's/ name: eks-eks-/ name: eks-/' >"${EXAMPLE_CLUSTERCLASSES_DIR}"/eks-cluster-class.yaml + +kustomize build --load-restrictor LoadRestrictionsNone \ + ./hack/examples/overlays/clusters/eks \ + >"${EXAMPLE_CLUSTERS_DIR}/eks-cluster.yaml" + # TODO Remove once kustomize supports retaining quotes in what will be numeric values. #shellcheck disable=SC2016 sed -i'' 's/${AMI_LOOKUP_ORG}/"${AMI_LOOKUP_ORG}"/' "${EXAMPLE_CLUSTERS_DIR}"/*.yaml diff --git a/make/clusterctl.mk b/make/clusterctl.mk index de250353f..f85ab3846 100644 --- a/make/clusterctl.mk +++ b/make/clusterctl.mk @@ -25,9 +25,9 @@ clusterctl.init: --infrastructure docker:$(CAPD_VERSION),aws:$(CAPA_VERSION),nutanix:$(CAPX_VERSION) \ --addon helm:$(CAAPH_VERSION) \ --wait-providers - kubectl apply --server-side --force-conflicts \ + kubectl --kubeconfig=$(KIND_KUBECONFIG) apply --server-side --force-conflicts \ -k 'https://github.com/jimmidyson/cluster-api-provider-aws/config/crd?ref=$(CAPA_VERSION)-eksclusterclass' - kubectl set image -n capa-system deployment/capa-controller-manager \ + kubectl --kubeconfig=$(KIND_KUBECONFIG) set image -n capa-system deployment/capa-controller-manager \ manager=ghcr.io/jimmidyson/cluster-api-aws/cluster-api-aws-controller:$(CAPA_VERSION)-eksclusterclass .PHONY: clusterctl.delete From 360962e93c151f8d4e368377f42d4a4d6cd273c2 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 6 Aug 2025 17:35:23 +0100 Subject: [PATCH 3/6] fixup! refactor: Use declared builtin variable name rather than string --- .../clustertopology/handlers/mutation/meta.go | 2 +- .../patches/matchers/match_test.go | 18 +++++++++--------- .../aws/mutation/ami/inject_worker_test.go | 4 ++-- .../iaminstanceprofile/inject_worker_test.go | 2 +- .../instancetype/inject_worker_test.go | 2 +- .../placementgroup/inject_worker_test.go | 2 +- .../securitygroups/inject_worker_test.go | 2 +- .../customimage/inject_control_plane.go | 2 +- .../customimage/inject_control_plane_test.go | 4 ++-- .../mutation/customimage/inject_worker.go | 2 +- .../mutation/customimage/inject_worker_test.go | 4 ++-- .../eks/mutation/ami/inject_worker_test.go | 4 ++-- .../iaminstanceprofile/inject_worker_test.go | 2 +- .../instancetype/inject_worker_test.go | 2 +- .../placementgroup/inject_worker_test.go | 2 +- .../securitygroups/inject_worker_test.go | 2 +- .../inject_test.go | 2 +- .../mutation/containerdmetrics/inject_test.go | 2 +- .../containerdunprivilegedports/inject_test.go | 2 +- .../generic/mutation/httpproxy/inject_test.go | 2 +- .../imageregistries/credentials/inject_test.go | 4 ++-- .../generic/mutation/mirrors/inject_test.go | 10 +++++----- .../noderegistration/inject_worker_test.go | 2 +- .../generic/mutation/ntp/inject_test.go | 6 +++--- .../mutation/taints/inject_worker_test.go | 4 ++-- .../generic/mutation/users/inject_test.go | 4 ++-- .../machinedetails/inject_worker_test.go | 2 +- 27 files changed, 48 insertions(+), 48 deletions(-) diff --git a/common/pkg/capi/clustertopology/handlers/mutation/meta.go b/common/pkg/capi/clustertopology/handlers/mutation/meta.go index d2a75782d..98626a9d8 100644 --- a/common/pkg/capi/clustertopology/handlers/mutation/meta.go +++ b/common/pkg/capi/clustertopology/handlers/mutation/meta.go @@ -101,7 +101,7 @@ func (mgp metaGeneratePatches) GeneratePatches( globalVars := lo.FilterSliceToMap( req.Variables, func(v runtimehooksv1.Variable) (string, apiextensionsv1.JSON, bool) { - if v.Name == "builtin" { + if v.Name == runtimehooksv1.BuiltinsName { return "", apiextensionsv1.JSON{}, false } return v.Name, v.Value, true diff --git a/common/pkg/capi/clustertopology/patches/matchers/match_test.go b/common/pkg/capi/clustertopology/patches/matchers/match_test.go index 18916f67e..0b0d83614 100644 --- a/common/pkg/capi/clustertopology/patches/matchers/match_test.go +++ b/common/pkg/capi/clustertopology/patches/matchers/match_test.go @@ -225,7 +225,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -253,7 +253,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -281,7 +281,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"class-A"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"class-A"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -309,7 +309,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"class-A"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"class-A"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -337,7 +337,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -365,7 +365,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -391,7 +391,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -415,7 +415,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.bootstrap.configRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", @@ -443,7 +443,7 @@ func TestMatchesSelector(t *testing.T) { FieldPath: "spec.template.spec.infrastructureRef", }, templateVariables: map[string]apiextensionsv1.JSON{ - "builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, + runtimehooksv1.BuiltinsName: {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)}, }, selector: clusterv1.PatchSelector{ APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", diff --git a/pkg/handlers/aws/mutation/ami/inject_worker_test.go b/pkg/handlers/aws/mutation/ami/inject_worker_test.go index 01011eb47..015625a01 100644 --- a/pkg/handlers/aws/mutation/ami/inject_worker_test.go +++ b/pkg/handlers/aws/mutation/ami/inject_worker_test.go @@ -32,7 +32,7 @@ var _ = Describe("Generate AMI patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, @@ -63,7 +63,7 @@ var _ = Describe("Generate AMI patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go index 8795d72b2..9f68de792 100644 --- a/pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go +++ b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go @@ -35,7 +35,7 @@ var _ = Describe("Generate IAMInstanceProfile patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/aws/mutation/instancetype/inject_worker_test.go b/pkg/handlers/aws/mutation/instancetype/inject_worker_test.go index aa1a6f0ba..626b90caa 100644 --- a/pkg/handlers/aws/mutation/instancetype/inject_worker_test.go +++ b/pkg/handlers/aws/mutation/instancetype/inject_worker_test.go @@ -35,7 +35,7 @@ var _ = Describe("Generate InstanceType patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/aws/mutation/placementgroup/inject_worker_test.go b/pkg/handlers/aws/mutation/placementgroup/inject_worker_test.go index 969eb233f..0885ce3de 100644 --- a/pkg/handlers/aws/mutation/placementgroup/inject_worker_test.go +++ b/pkg/handlers/aws/mutation/placementgroup/inject_worker_test.go @@ -35,7 +35,7 @@ var _ = Describe("Generate PlacementGroup patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go b/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go index eeb07e180..96e89e5ff 100644 --- a/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go +++ b/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go @@ -39,7 +39,7 @@ var _ = Describe("Generate AWS SecurityGroups patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/docker/mutation/customimage/inject_control_plane.go b/pkg/handlers/docker/mutation/customimage/inject_control_plane.go index 5057f0300..dc596491c 100644 --- a/pkg/handlers/docker/mutation/customimage/inject_control_plane.go +++ b/pkg/handlers/docker/mutation/customimage/inject_control_plane.go @@ -95,7 +95,7 @@ func (h *customImageControlPlanePatchHandler) Mutate( ), log, func(obj *capdv1.DockerMachineTemplate) error { - variablePath := []string{"builtin", "controlPlane", "version"} + variablePath := []string{runtimehooksv1.BuiltinsName, "controlPlane", "version"} if customImageVar == "" { kubernetesVersion, err := variables.Get[string]( diff --git a/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go b/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go index 5c8a4eba1..8c21a415e 100644 --- a/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go +++ b/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go @@ -29,7 +29,7 @@ var _ = Describe("Docker CustomImage patches for ControlPlane", func() { Name: "image unset for control plane", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{Raw: []byte(`{"controlPlane": {"version": "v1.2.3"}}`)}, ), }, @@ -51,7 +51,7 @@ var _ = Describe("Docker CustomImage patches for ControlPlane", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/docker/mutation/customimage/inject_worker.go b/pkg/handlers/docker/mutation/customimage/inject_worker.go index 062e2a52d..da3eeddc6 100644 --- a/pkg/handlers/docker/mutation/customimage/inject_worker.go +++ b/pkg/handlers/docker/mutation/customimage/inject_worker.go @@ -87,7 +87,7 @@ func (h *customImageWorkerPatchHandler) Mutate( ), log, func(obj *capdv1.DockerMachineTemplate) error { - fieldPath := []string{"builtin", "machineDeployment", "version"} + fieldPath := []string{runtimehooksv1.BuiltinsName, "machineDeployment", "version"} if customImageVar == "" { kubernetesVersion, err := variables.Get[string]( diff --git a/pkg/handlers/docker/mutation/customimage/inject_worker_test.go b/pkg/handlers/docker/mutation/customimage/inject_worker_test.go index bdb7fa9d2..834ff96ce 100644 --- a/pkg/handlers/docker/mutation/customimage/inject_worker_test.go +++ b/pkg/handlers/docker/mutation/customimage/inject_worker_test.go @@ -26,7 +26,7 @@ var _ = Describe("Docker CustomImage patches for workers", func() { Name: "image unset for workers", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte( `{"machineDeployment": {"class": "a-worker", "version": "v1.2.3"}}`, @@ -51,7 +51,7 @@ var _ = Describe("Docker CustomImage patches for workers", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/eks/mutation/ami/inject_worker_test.go b/pkg/handlers/eks/mutation/ami/inject_worker_test.go index 4eb88d48b..a44c1a77f 100644 --- a/pkg/handlers/eks/mutation/ami/inject_worker_test.go +++ b/pkg/handlers/eks/mutation/ami/inject_worker_test.go @@ -33,7 +33,7 @@ var _ = Describe("Generate AMI patches for Worker", func() { ami.VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, @@ -64,7 +64,7 @@ var _ = Describe("Generate AMI patches for Worker", func() { ami.VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/eks/mutation/iaminstanceprofile/inject_worker_test.go b/pkg/handlers/eks/mutation/iaminstanceprofile/inject_worker_test.go index cac35327e..452f790bf 100644 --- a/pkg/handlers/eks/mutation/iaminstanceprofile/inject_worker_test.go +++ b/pkg/handlers/eks/mutation/iaminstanceprofile/inject_worker_test.go @@ -36,7 +36,7 @@ var _ = Describe("Generate IAMInstanceProfile patches for Worker", func() { iaminstanceprofile.VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/eks/mutation/instancetype/inject_worker_test.go b/pkg/handlers/eks/mutation/instancetype/inject_worker_test.go index db6fad09b..3412cddf5 100644 --- a/pkg/handlers/eks/mutation/instancetype/inject_worker_test.go +++ b/pkg/handlers/eks/mutation/instancetype/inject_worker_test.go @@ -36,7 +36,7 @@ var _ = Describe("Generate InstanceType patches for Worker", func() { awsinstancetype.VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/eks/mutation/placementgroup/inject_worker_test.go b/pkg/handlers/eks/mutation/placementgroup/inject_worker_test.go index d92e31a55..a137e37bf 100644 --- a/pkg/handlers/eks/mutation/placementgroup/inject_worker_test.go +++ b/pkg/handlers/eks/mutation/placementgroup/inject_worker_test.go @@ -36,7 +36,7 @@ var _ = Describe("Generate PlacementGroup patches for Worker", func() { placementgroup.VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/eks/mutation/securitygroups/inject_worker_test.go b/pkg/handlers/eks/mutation/securitygroups/inject_worker_test.go index ea850f9fd..efefcb389 100644 --- a/pkg/handlers/eks/mutation/securitygroups/inject_worker_test.go +++ b/pkg/handlers/eks/mutation/securitygroups/inject_worker_test.go @@ -40,7 +40,7 @@ var _ = Describe("Generate AWS SecurityGroups patches for Worker", func() { securitygroups.VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/generic/mutation/containerdapplypatchesandrestart/inject_test.go b/pkg/handlers/generic/mutation/containerdapplypatchesandrestart/inject_test.go index 35f366b61..22c4be5e8 100644 --- a/pkg/handlers/generic/mutation/containerdapplypatchesandrestart/inject_test.go +++ b/pkg/handlers/generic/mutation/containerdapplypatchesandrestart/inject_test.go @@ -60,7 +60,7 @@ var _ = Describe("Generate Containerd apply patches and restart patches", func() Name: "restart script and command added to worker node kubeadm config template", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": "*", diff --git a/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go b/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go index 06915ca27..b13bd1fe3 100644 --- a/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go +++ b/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go @@ -47,7 +47,7 @@ var _ = Describe("Generate containerd metrics patches", func() { Name: "containerd metrics config added to worker node kubeadm config template", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": "*", diff --git a/pkg/handlers/generic/mutation/containerdunprivilegedports/inject_test.go b/pkg/handlers/generic/mutation/containerdunprivilegedports/inject_test.go index 42ae646e3..d9cc45db0 100644 --- a/pkg/handlers/generic/mutation/containerdunprivilegedports/inject_test.go +++ b/pkg/handlers/generic/mutation/containerdunprivilegedports/inject_test.go @@ -47,7 +47,7 @@ var _ = Describe("Generate containerd unprivileged ports patches", func() { Name: "containerd unprivileged ports config added to worker node kubeadm config template", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": "*", diff --git a/pkg/handlers/generic/mutation/httpproxy/inject_test.go b/pkg/handlers/generic/mutation/httpproxy/inject_test.go index d36ff0c85..8dd4f7c7b 100644 --- a/pkg/handlers/generic/mutation/httpproxy/inject_test.go +++ b/pkg/handlers/generic/mutation/httpproxy/inject_test.go @@ -62,7 +62,7 @@ var _ = Describe("Generate HTTPProxy Patches", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), diff --git a/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go b/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go index f72a60bee..0f41982b9 100644 --- a/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go +++ b/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go @@ -343,7 +343,7 @@ var _ = Describe("Generate Image registry patches", func() { v1alpha1.ImageRegistriesVariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), @@ -400,7 +400,7 @@ var _ = Describe("Generate Image registry patches", func() { v1alpha1.ImageRegistriesVariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), diff --git a/pkg/handlers/generic/mutation/mirrors/inject_test.go b/pkg/handlers/generic/mutation/mirrors/inject_test.go index c95feb527..4c6284736 100644 --- a/pkg/handlers/generic/mutation/mirrors/inject_test.go +++ b/pkg/handlers/generic/mutation/mirrors/inject_test.go @@ -198,7 +198,7 @@ var _ = Describe("Generate Global mirror patches", func() { v1alpha1.GlobalMirrorVariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), @@ -238,7 +238,7 @@ var _ = Describe("Generate Global mirror patches", func() { v1alpha1.GlobalMirrorVariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), @@ -281,7 +281,7 @@ var _ = Describe("Generate Global mirror patches", func() { v1alpha1.GlobalMirrorVariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), @@ -321,7 +321,7 @@ var _ = Describe("Generate Global mirror patches", func() { v1alpha1.ImageRegistriesVariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), @@ -382,7 +382,7 @@ var _ = Describe("Generate Global mirror patches", func() { []string{"addons", v1alpha1.RegistryAddonVariableName}..., ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), diff --git a/pkg/handlers/generic/mutation/noderegistration/inject_worker_test.go b/pkg/handlers/generic/mutation/noderegistration/inject_worker_test.go index e96525858..a05d7835a 100644 --- a/pkg/handlers/generic/mutation/noderegistration/inject_worker_test.go +++ b/pkg/handlers/generic/mutation/noderegistration/inject_worker_test.go @@ -36,7 +36,7 @@ var _ = Describe("Generate NodeRegistration patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/generic/mutation/ntp/inject_test.go b/pkg/handlers/generic/mutation/ntp/inject_test.go index 068286657..e97dbb8fb 100644 --- a/pkg/handlers/generic/mutation/ntp/inject_test.go +++ b/pkg/handlers/generic/mutation/ntp/inject_test.go @@ -100,7 +100,7 @@ var _ = Describe("Generate NTP patches", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": "worker-class", @@ -131,7 +131,7 @@ var _ = Describe("Generate NTP patches", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": "worker-class", @@ -181,7 +181,7 @@ var _ = Describe("Generate NTP patches", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": "worker-class", diff --git a/pkg/handlers/generic/mutation/taints/inject_worker_test.go b/pkg/handlers/generic/mutation/taints/inject_worker_test.go index 548d3cf4f..ceccdb489 100644 --- a/pkg/handlers/generic/mutation/taints/inject_worker_test.go +++ b/pkg/handlers/generic/mutation/taints/inject_worker_test.go @@ -43,7 +43,7 @@ var _ = Describe("Generate taints patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, @@ -71,7 +71,7 @@ var _ = Describe("Generate taints patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, diff --git a/pkg/handlers/generic/mutation/users/inject_test.go b/pkg/handlers/generic/mutation/users/inject_test.go index cbee5a747..16f0ae406 100644 --- a/pkg/handlers/generic/mutation/users/inject_test.go +++ b/pkg/handlers/generic/mutation/users/inject_test.go @@ -178,7 +178,7 @@ var _ = Describe("Generate Users patches", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), @@ -202,7 +202,7 @@ var _ = Describe("Generate Users patches", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, map[string]any{ "machineDeployment": map[string]any{ "class": names.SimpleNameGenerator.GenerateName("worker-"), diff --git a/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go b/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go index ef9245efb..506b20309 100644 --- a/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go @@ -34,7 +34,7 @@ var _ = Describe("Generate Nutanix Machine Details patches for Worker", func() { VariableName, ), capitest.VariableWithValue( - "builtin", + runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{ Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), }, From 56a3f5b96affb9351d3a88705591ff15ebee54cd Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Tue, 19 Aug 2025 12:50:11 +0100 Subject: [PATCH 4/6] fixup! refactor: Remove system pools from EKS cluster This was breaking certain pod deployments due to incorrect IAM permissions. --- .../defaultclusterclasses/eks-cluster-class.yaml | 12 ------------ examples/capi-quick-start/eks-cluster.yaml | 16 ---------------- hack/examples/bases/eks/cluster/cluster.yaml | 16 ---------------- .../bases/eks/clusterclass/clusterclass.yaml | 12 ------------ 4 files changed, 56 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml index 174e43748..fb9654bf4 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/eks-cluster-class.yaml @@ -52,18 +52,6 @@ spec: apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 kind: AWSMachineTemplate name: eks-quick-start-worker-machinetemplate - - class: system-worker - template: - bootstrap: - ref: - apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 - kind: EKSConfigTemplate - name: eks-quick-start-worker-configtemplate - infrastructure: - ref: - apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 - kind: AWSMachineTemplate - name: eks-quick-start-worker-machinetemplate --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 kind: AWSManagedClusterTemplate diff --git a/examples/capi-quick-start/eks-cluster.yaml b/examples/capi-quick-start/eks-cluster.yaml index f47d6480a..b01372aac 100644 --- a/examples/capi-quick-start/eks-cluster.yaml +++ b/examples/capi-quick-start/eks-cluster.yaml @@ -102,19 +102,3 @@ spec: cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "${WORKER_MACHINE_COUNT}" cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "${WORKER_MACHINE_COUNT}" name: md-0 - - class: system-worker - metadata: - labels: - node-restriction.kubernetes.io/capi-controllers: "" - name: system - replicas: 1 - variables: - overrides: - - name: workerConfig - value: - eks: - iamInstanceProfile: control-plane.cluster-api-provider-aws.sigs.k8s.io - taints: - - effect: NoSchedule - key: node-restriction.kubernetes.io/capi-controllers - value: "true" diff --git a/hack/examples/bases/eks/cluster/cluster.yaml b/hack/examples/bases/eks/cluster/cluster.yaml index 9c693a125..ae7e371f3 100644 --- a/hack/examples/bases/eks/cluster/cluster.yaml +++ b/hack/examples/bases/eks/cluster/cluster.yaml @@ -82,19 +82,3 @@ spec: - class: default-worker name: md-0 replicas: ${WORKER_MACHINE_COUNT} - - class: system-worker - name: system - metadata: - labels: - node-restriction.kubernetes.io/capi-controllers: "" - replicas: 1 - variables: - overrides: - - name: workerConfig - value: - taints: - - effect: NoSchedule - key: node-restriction.kubernetes.io/capi-controllers - value: "true" - eks: - iamInstanceProfile: "control-plane.cluster-api-provider-aws.sigs.k8s.io" diff --git a/hack/examples/bases/eks/clusterclass/clusterclass.yaml b/hack/examples/bases/eks/clusterclass/clusterclass.yaml index d636cd340..7033e0363 100644 --- a/hack/examples/bases/eks/clusterclass/clusterclass.yaml +++ b/hack/examples/bases/eks/clusterclass/clusterclass.yaml @@ -30,18 +30,6 @@ spec: name: "quick-start-worker-machinetemplate" apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 kind: AWSMachineTemplate - - class: system-worker - template: - bootstrap: - ref: - name: "quick-start-worker-configtemplate" - apiVersion: bootstrap.cluster.x-k8s.io/v1beta2 - kind: EKSConfigTemplate - infrastructure: - ref: - name: "quick-start-worker-machinetemplate" - apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 - kind: AWSMachineTemplate --- kind: AWSManagedClusterTemplate apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 From 1260928560e1027ee25c97e99d18ccf84928b528 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Tue, 19 Aug 2025 15:01:06 +0100 Subject: [PATCH 5/6] fixup! build: Add aws-iam-authenticator --- devbox.json | 3 ++- devbox.lock | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/devbox.json b/devbox.json index 32c5c3add..b669f4317 100644 --- a/devbox.json +++ b/devbox.json @@ -37,7 +37,8 @@ "path:./hack/flakes#clusterctl-aws", "path:./hack/flakes#goprintconst", "path:./hack/flakes#helm-with-plugins", - "path:./hack/flakes#release-please" + "path:./hack/flakes#release-please", + "aws-iam-authenticator@latest" ], "shell": { "scripts": { diff --git a/devbox.lock b/devbox.lock index cba1fd3dc..8512f505d 100644 --- a/devbox.lock +++ b/devbox.lock @@ -49,6 +49,54 @@ } } }, + "aws-iam-authenticator@latest": { + "last_modified": "2025-08-02T08:13:18Z", + "resolved": "github:NixOS/nixpkgs/c02d05bcf73fb496c604798c2268ed424a09e73e#aws-iam-authenticator", + "source": "devbox-search", + "version": "0.7.5", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/z9wbarpnj6gkp5kqny48vg2fy9vk757s-aws-iam-authenticator-0.7.5", + "default": true + } + ], + "store_path": "/nix/store/z9wbarpnj6gkp5kqny48vg2fy9vk757s-aws-iam-authenticator-0.7.5" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/0pf34s8z43mqc9hi98kljra376y2rh0s-aws-iam-authenticator-0.7.5", + "default": true + } + ], + "store_path": "/nix/store/0pf34s8z43mqc9hi98kljra376y2rh0s-aws-iam-authenticator-0.7.5" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/07639nsd35gy4d7gbzgywn1kab52jdyr-aws-iam-authenticator-0.7.5", + "default": true + } + ], + "store_path": "/nix/store/07639nsd35gy4d7gbzgywn1kab52jdyr-aws-iam-authenticator-0.7.5" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/cnpdb16wvd0qx2x6smi6v9v1c2c8wlmb-aws-iam-authenticator-0.7.5", + "default": true + } + ], + "store_path": "/nix/store/cnpdb16wvd0qx2x6smi6v9v1c2c8wlmb-aws-iam-authenticator-0.7.5" + } + } + }, "chart-testing@latest": { "last_modified": "2025-07-13T22:45:35Z", "resolved": "github:NixOS/nixpkgs/a421ac6595024edcfbb1ef950a3712b89161c359#chart-testing", From 7a29de54988649f645a90d6e4b904331a513fa56 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Tue, 19 Aug 2025 16:03:40 +0100 Subject: [PATCH 6/6] fixup! test: Add volumeattachment demo --- .../eks-ebs-snapshot-volumeattach/demo.sh | 212 ++++++++++++++++++ .../eks-test.yaml | 109 +++++++++ 2 files changed, 321 insertions(+) create mode 100755 hack/demos/eks-ebs-snapshot-volumeattach/demo.sh create mode 100644 hack/demos/eks-ebs-snapshot-volumeattach/eks-test.yaml diff --git a/hack/demos/eks-ebs-snapshot-volumeattach/demo.sh b/hack/demos/eks-ebs-snapshot-volumeattach/demo.sh new file mode 100755 index 000000000..ed6c082e0 --- /dev/null +++ b/hack/demos/eks-ebs-snapshot-volumeattach/demo.sh @@ -0,0 +1,212 @@ +#!/usr/bin/env bash + +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail +IFS=$'\n\t' + +# This script demonstrates: +# 1. Creating an EKS cluster via ClusterClass +# 2. Creating a PersistentVolumeClaim (PVC) +# 3. Populating it with data via a Pod +# 4. Taking a VolumeSnapshot +# 5. Restoring the snapshot to a new PVC +# 6. Attaching the restored volume to a node via VolumeAttachment +# 7. Validating the data is present on the attached volume + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly SCRIPT_DIR +cd "${SCRIPT_DIR}" + +if [[ -z ${EKS_CLUSTER_NAME:-} ]]; then + EKS_CLUSTER_NAME="$(kubectl get clusters -l caren.nutanix.com/demo-name="EBSSnapshotVolumeAttach" -o custom-columns=NAME:.metadata.name --no-headers)" + if [[ -z ${EKS_CLUSTER_NAME} ]]; then + EKS_CLUSTER_NAME="eks-volumeattach-$(head /dev/urandom | tr -dc a-z0-9 | head -c6)" + fi +fi +export EKS_CLUSTER_NAME +echo "Using EKS cluster name: ${EKS_CLUSTER_NAME}" + +echo +echo "Step 1: Create an EKS cluster via ClusterClass" +envsubst --no-unset -i eks-test.yaml | kubectl apply --server-side -f - +kubectl wait --for=condition=Ready cluster/"${EKS_CLUSTER_NAME}" --timeout=20m + +echo "Cluster is ready, getting kubeconfig" +EKS_KUBECONFIG="$(mktemp -p "${TMPDIR:-/tmp}")" +kubectl get secrets "${EKS_CLUSTER_NAME}-user-kubeconfig" -oyaml | + gojq --yaml-input -r '.data.value | @base64d' >"${EKS_KUBECONFIG}" +export KUBECONFIG="${EKS_KUBECONFIG}" +echo "Using kubeconfig: ${EKS_KUBECONFIG}" + +STORAGE_CLASS="${STORAGE_CLASS:-aws-ebs-default}" +STORAGE_CLASS_IMMEDIATE="${STORAGE_CLASS_IMMEDIATE:-aws-ebs-immediate-binding}" +VOLUME_SNAPSHOT_CLASS="${VOLUME_SNAPSHOT_CLASS:-ebs-snapclass}" +ORIGINAL_PVC="${ORIGINAL_PVC:-pvc-demo-original}" +RESTORED_PVC="${RESTORED_PVC:-pvc-demo-restored}" +SNAPSHOT_NAME="${SNAPSHOT_NAME:-pvc-demo-snapshot}" +DATA_POD="${DATA_POD:-data-writer}" +RESTORE_POD="${RESTORE_POD:-data-reader}" + +NAMESPACE="$(kubectl get namespace -l caren.nutanix.com/demo-name="EBSSnapshotVolumeAttach" -o custom-columns=NAME:.metadata.name --no-headers)" +if [[ -z ${NAMESPACE} ]]; then + NAMESPACE="ebs-demo-$(head /dev/urandom | tr -dc a-z0-9 | head -c6)" + cat < /data/hello.txt; sleep 10 + volumeMounts: + - name: data + mountPath: /data + volumes: + - name: data + persistentVolumeClaim: + claimName: ${ORIGINAL_PVC} +EOF +kubectl -n "${NAMESPACE}" get pod "${DATA_POD}" + +echo "Waiting for PVC to be bound..." +kubectl -n "${NAMESPACE}" wait --for=jsonpath='{.status.phase}'=Bound pvc/"${ORIGINAL_PVC}" --timeout=120s +kubectl -n "${NAMESPACE}" get pvc "${ORIGINAL_PVC}" + +echo "Waiting for data writer pod to complete..." +kubectl -n "${NAMESPACE}" wait --for=jsonpath='{.status.phase}'=Succeeded pod/"${DATA_POD}" --timeout=120s +kubectl -n "${NAMESPACE}" get pod "${DATA_POD}" + +echo +echo "Step 4: Create a VolumeSnapshotClass" +cat <