Skip to content

Commit 07c377c

Browse files
thunderboltsidjimmidyson
authored andcommitted
fix(patches): Ensure resulting NutanixMachineTemplate patches are clean
These changes ensure the resulting NutanixMachineTemplate patches also reflect the XOR between failureDomains and cluster/subnets. **How has this been tested?** Tested in conjunction with #1233 in #1226 * Run `make dev.run-on-kind` and see default NutanixMachineTemplates when management cluster is created and observe no placeholder cluster and subnet fields ```yaml - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nutanix-quick-start-cp-nmt namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: ClusterClass name: nutanix-quick-start spec: template: spec: bootType: legacy image: name: "" type: name memorySize: 4Gi systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nutanix-quick-start-md-nmt namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: ClusterClass name: nutanix-quick-start spec: template: spec: bootType: legacy image: name: "" type: name memorySize: 4Gi systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 ``` * Create a cluster without failure domains with a machine deployment with cluster and subnet set ```yaml apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: ... name: nkp-sid-caren-no-fd spec: ... topology: class: nutanix-quick-start controlPlane: metadata: {} replicas: 3 variables: - name: clusterConfig value: ... controlPlane: nutanix: machineDetails: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 4Gi systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 cluster: type: name name: ncn-dev-sandbox subnets: - type: name name: vlan173 ... - name: workerConfig value: nutanix: machineDetails: bootType: uefi cluster: name: ncn-dev-sandbox type: name imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 4Gi subnets: - name: vlan173 type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 version: 1.33.1 workers: machineDeployments: - class: default-worker metadata: annotations: cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "1" cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "1" name: md-0 variables: overrides: - name: workerConfig value: nutanix: machineDetails: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 8Gi cluster: type: name name: ncn-dev-sandbox subnets: - type: name name: vlan173 systemDiskSize: 80Gi vcpuSockets: 8 vcpusPerSocket: 1 - class: default-worker metadata: annotations: cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "1" cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "1" name: md-1 variables: overrides: - name: workerConfig value: nutanix: machineDetails: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 8Gi cluster: type: uuid uuid: 00061f7f-44f7-19dc-3be1-7cc25586ee44 subnets: - type: name name: vlan173 systemDiskSize: 80Gi vcpuSockets: 8 vcpusPerSocket: 1 ``` Observe the generated NutanixMachineTemplate has cluster and subnets set correctly ```yaml apiVersion: v1 items: - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nkp-sid-caren-no-fd-7np7m namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster name: nkp-sid-caren-no-fd spec: template: spec: bootType: uefi cluster: name: ncn-dev-sandbox type: name imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 4Gi subnet: - name: vlan173 type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nkp-sid-caren-no-fd-md-0-qnr58 namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster name: nkp-sid-caren-no-fd spec: template: spec: bootType: uefi cluster: name: ncn-dev-sandbox type: name imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 8Gi subnet: - name: vlan173 type: name systemDiskSize: 80Gi vcpuSockets: 8 vcpusPerSocket: 1 - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nkp-sid-caren-no-fd-md-1-59tlq namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster name: nkp-sid-caren-no-fd spec: template: spec: bootType: uefi cluster: type: uuid uuid: 00061f7f-44f7-19dc-3be1-7cc25586ee44 imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 8Gi subnet: - name: vlan173 type: name systemDiskSize: 80Gi vcpuSockets: 8 vcpusPerSocket: 1 ``` * Create a cluster with control plane and machine deployment on failure domains ```yaml apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: labels: cluster.x-k8s.io/cluster-name: nkp-sid-caren cluster.x-k8s.io/provider: nutanix name: nkp-sid-caren spec: ... topology: class: nutanix-quick-start controlPlane: metadata: {} replicas: 3 variables: - name: clusterConfig value: ... controlPlane: nutanix: failureDomains: - fd-1 - fd-2 - fd-3 machineDetails: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 4Gi systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 ... - name: workerConfig value: nutanix: machineDetails: bootType: uefi cluster: name: ncn-dev-sandbox type: name imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 4Gi subnets: - name: vlan173 type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 version: 1.33.1 workers: machineDeployments: - class: default-worker failureDomain: fd-1 metadata: annotations: cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "1" cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "1" name: md-0 variables: overrides: - name: workerConfig value: nutanix: machineDetails: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 8Gi systemDiskSize: 80Gi vcpuSockets: 8 vcpusPerSocket: 1 ``` Observe the generated NutanixMachineTemplate does not have cluster and subnet set ```yaml - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nkp-sid-caren-kp4nc namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster name: nkp-sid-caren spec: template: spec: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 4Gi systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 - apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate metadata: ... name: nkp-sid-caren-md-0-bfm6v namespace: default ownerReferences: - apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster name: nkp-sid-caren spec: template: spec: bootType: uefi imageLookup: baseOS: rocky-9.6 format: nkp-{{.BaseOS}}-release-{{.K8sVersion}}-* memorySize: 8Gi systemDiskSize: 80Gi vcpuSockets: 8 vcpusPerSocket: 1 ```
1 parent 1f08425 commit 07c377c

File tree

10 files changed

+65
-53
lines changed

10 files changed

+65
-53
lines changed

api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1/nutanixmachine_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,12 @@ type NutanixMachineSpec struct {
132132
// The cluster identifier (uuid or name) can be obtained from the Prism Central console
133133
// or using the prism_central API.
134134
// +kubebuilder:validation:Optional
135-
Cluster NutanixResourceIdentifier `json:"cluster"`
135+
Cluster NutanixResourceIdentifier `json:"cluster,omitzero"`
136136
// subnet is to identify the cluster's network subnet to use for the Machine's VM
137137
// The cluster identifier (uuid or name) can be obtained from the Prism Central console
138138
// or using the prism_central API.
139139
// +kubebuilder:validation:Optional
140-
Subnets []NutanixResourceIdentifier `json:"subnet"`
140+
Subnets []NutanixResourceIdentifier `json:"subnet,omitempty"`
141141
// List of categories that need to be added to the machines. Categories must already exist in Prism Central
142142
// +kubebuilder:validation:Optional
143143
AdditionalCategories []NutanixCategoryIdentifier `json:"additionalCategories,omitempty"`

charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,10 @@ spec:
304304
template:
305305
spec:
306306
bootType: legacy
307-
cluster:
308-
name: ""
309-
type: name
310307
image:
311308
name: ""
312309
type: name
313310
memorySize: 4Gi
314-
subnet:
315-
- name: ""
316-
type: name
317311
systemDiskSize: 40Gi
318312
vcpuSockets: 2
319313
vcpusPerSocket: 1
@@ -328,16 +322,10 @@ spec:
328322
template:
329323
spec:
330324
bootType: legacy
331-
cluster:
332-
name: ""
333-
type: name
334325
image:
335326
name: ""
336327
type: name
337328
memorySize: 4Gi
338-
subnet:
339-
- name: ""
340-
type: name
341329
systemDiskSize: 40Gi
342330
vcpuSockets: 2
343331
vcpusPerSocket: 1

common/pkg/capi/clustertopology/handlers/mutation/meta.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
1515
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
1616
"sigs.k8s.io/cluster-api/exp/runtime/topologymutation"
17+
ctrl "sigs.k8s.io/controller-runtime"
1718
"sigs.k8s.io/controller-runtime/pkg/client"
1819

1920
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers"
@@ -99,12 +100,27 @@ func (mgp metaGeneratePatches) GeneratePatches(
99100
vars map[string]apiextensionsv1.JSON,
100101
holderRef runtimehooksv1.HolderReference,
101102
) error {
102-
for _, h := range mgp.mutators {
103+
log := ctrl.LoggerFrom(ctx).WithValues(
104+
"holderRef", holderRef,
105+
"objectKind", obj.GetObjectKind().GroupVersionKind().String(),
106+
"handlerName", mgp.name,
107+
)
108+
109+
log.V(3).Info("Starting mutation pipeline", "handlerCount", len(mgp.mutators))
110+
111+
for i, h := range mgp.mutators {
112+
handlerName := fmt.Sprintf("%T", h)
113+
log.V(5).Info("Running mutator", "index", i, "handler", handlerName)
114+
103115
if err := h.Mutate(ctx, obj.(*unstructured.Unstructured), vars, holderRef, clusterKey, clusterGetter); err != nil {
116+
log.Error(err, "Mutator failed", "index", i, "handler", handlerName)
104117
return err
105118
}
119+
120+
log.V(5).Info("Mutator completed successfully", "index", i, "handler", handlerName)
106121
}
107122

123+
log.V(3).Info("Mutation pipeline completed successfully", "handlerCount", len(mgp.mutators))
108124
return nil
109125
},
110126
)

hack/examples/overlays/clusterclasses/nutanix/kustomization.yaml.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ patches:
4949
kind: KubeadmControlPlaneTemplate
5050
path: ../../../patches/cis-admissionconfiguration.yaml
5151
# END CIS patches
52+
53+
- target:
54+
kind: NutanixMachineTemplate
55+
path: ../../../patches/nutanix/remove-cluster-and-subnet-from-machinetemplates.yaml
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- op: remove
2+
path: /spec/template/spec/cluster
3+
- op: remove
4+
path: /spec/template/spec/subnet

hack/third-party/capx/go.mod

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
module github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/external/capx
55

6-
go 1.23.0
6+
go 1.24.0
77

8-
toolchain go1.24.2
8+
toolchain go1.24.3
99

10-
require github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.0-beta.2
10+
require github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.0-beta.4
1111

1212
require (
1313
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
@@ -28,7 +28,6 @@ require (
2828
github.com/nutanix-cloud-native/prism-go-client v0.5.0 // indirect
2929
github.com/pkg/errors v0.9.1 // indirect
3030
github.com/x448/float16 v0.8.4 // indirect
31-
go.uber.org/automaxprocs v1.6.0 // indirect
3231
golang.org/x/net v0.38.0 // indirect
3332
golang.org/x/text v0.23.0 // indirect
3433
google.golang.org/protobuf v1.36.5 // indirect

hack/third-party/capx/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/
7676
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
7777
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
7878
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
79-
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.0-beta.2 h1:RsqSaYm5Vg6887taqJ8mRtqa1zckiwtqZVf3/xJRcro=
80-
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.0-beta.2/go.mod h1:8F3sXZInz+dShppYLmMzQwUAzFsZTyaxaB3bf5rIk/A=
79+
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.0-beta.4 h1:SNfZlG/AJ/RUpEij0Lu1XbrIoOxk+tZvzQktFdPkGYc=
80+
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.0-beta.4/go.mod h1:6AJwae8W/nGmITlnuTnvMxCxxztctEAUJulxC9z/jgU=
8181
github.com/nutanix-cloud-native/prism-go-client v0.5.0 h1:aSNuKDOK7+q676MQyetYXcySY41IjSvN2UmrDIU3+6s=
8282
github.com/nutanix-cloud-native/prism-go-client v0.5.0/go.mod h1:QhLX+sEep0cStzHVYU6mPgIlnA8U3DySskagrbDprRk=
8383
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=

pkg/handlers/nutanix/mutation/controlplanefailuredomains/inject.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (h *nutanixControlPlaneFailureDomains) Mutate(
7171
)
7272
if err != nil {
7373
if variables.IsNotFoundError(err) {
74-
log.V(5).Info("ControlPlane nutanix failureDomains variable not defined", "error", err.Error())
74+
log.V(5).Info("ControlPlane nutanix failureDomains variable not defined in cluster config")
7575
return nil
7676
}
7777
log.V(5).Error(err, "failed to get controlPlane nutanix failureDomains variable")

pkg/handlers/nutanix/mutation/machinedetails/inject.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,6 @@ func (h *nutanixMachineDetailsPatchHandler) Mutate(
9999
spec.BootType = nutanixMachineDetailsVar.BootType
100100
if nutanixMachineDetailsVar.Cluster != nil {
101101
spec.Cluster = *nutanixMachineDetailsVar.Cluster
102-
} else {
103-
// Have to set the required Type field.
104-
spec.Cluster = capxv1.NutanixResourceIdentifier{
105-
Type: capxv1.NutanixIdentifierName,
106-
}
107102
}
108103

109104
switch {
@@ -122,7 +117,10 @@ func (h *nutanixMachineDetailsPatchHandler) Mutate(
122117
spec.MemorySize = nutanixMachineDetailsVar.MemorySize
123118
spec.SystemDiskSize = nutanixMachineDetailsVar.SystemDiskSize
124119

125-
spec.Subnets = slices.Clone(nutanixMachineDetailsVar.Subnets)
120+
if len(nutanixMachineDetailsVar.Subnets) > 0 {
121+
spec.Subnets = slices.Clone(nutanixMachineDetailsVar.Subnets)
122+
}
123+
126124
spec.AdditionalCategories = slices.Clone(nutanixMachineDetailsVar.AdditionalCategories)
127125
spec.GPUs = slices.Clone(nutanixMachineDetailsVar.GPUs)
128126
spec.Project = nutanixMachineDetailsVar.Project.DeepCopy()

pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane_test.go

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -86,24 +86,19 @@ var (
8686
},
8787
}
8888
matchersForAllImageTemplating = []capitest.JSONPatchMatcher{
89-
// boot type
9089
{
9190
Operation: "add",
9291
Path: "/spec/template/spec/bootType",
9392
ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixBootTypeLegacy),
9493
},
95-
// cluster
9694
{
97-
Operation: "add",
98-
Path: "/spec/template/spec/cluster/name",
99-
ValueMatcher: gomega.BeEquivalentTo("fake-pe-cluster"),
95+
Operation: "add",
96+
Path: "/spec/template/spec/cluster",
97+
ValueMatcher: gomega.SatisfyAll(
98+
gomega.HaveKeyWithValue("type", gomega.BeEquivalentTo(capxv1.NutanixIdentifierName)),
99+
gomega.HaveKeyWithValue("name", gomega.BeEquivalentTo("fake-pe-cluster")),
100+
),
100101
},
101-
{
102-
Operation: "replace",
103-
Path: "/spec/template/spec/cluster/type",
104-
ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixIdentifierName),
105-
},
106-
107102
{
108103
Operation: "replace",
109104
Path: "/spec/template/spec/vcpuSockets",
@@ -125,9 +120,14 @@ var (
125120
ValueMatcher: gomega.BeEquivalentTo("40Gi"),
126121
},
127122
{
128-
Operation: "replace",
129-
Path: "/spec/template/spec/subnet",
130-
ValueMatcher: gomega.HaveLen(1),
123+
Operation: "add",
124+
Path: "/spec/template/spec/subnet",
125+
ValueMatcher: gomega.ContainElement(
126+
gomega.SatisfyAll(
127+
gomega.HaveKeyWithValue("type", gomega.BeEquivalentTo(capxv1.NutanixIdentifierName)),
128+
gomega.HaveKeyWithValue("name", gomega.BeEquivalentTo("fake-subnet")),
129+
),
130+
),
131131
},
132132
{
133133
Operation: "add",
@@ -159,14 +159,12 @@ var (
159159
ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixBootTypeLegacy),
160160
},
161161
{
162-
Operation: "add",
163-
Path: "/spec/template/spec/cluster/name",
164-
ValueMatcher: gomega.BeEquivalentTo("fake-pe-cluster"),
165-
},
166-
{
167-
Operation: "replace",
168-
Path: "/spec/template/spec/cluster/type",
169-
ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixIdentifierName),
162+
Operation: "add",
163+
Path: "/spec/template/spec/cluster",
164+
ValueMatcher: gomega.SatisfyAll(
165+
gomega.HaveKeyWithValue("type", gomega.BeEquivalentTo(capxv1.NutanixIdentifierName)),
166+
gomega.HaveKeyWithValue("name", gomega.BeEquivalentTo("fake-pe-cluster")),
167+
),
170168
},
171169
{
172170
Operation: "replace",
@@ -189,9 +187,14 @@ var (
189187
ValueMatcher: gomega.BeEquivalentTo("40Gi"),
190188
},
191189
{
192-
Operation: "replace",
193-
Path: "/spec/template/spec/subnet",
194-
ValueMatcher: gomega.HaveLen(1),
190+
Operation: "add",
191+
Path: "/spec/template/spec/subnet",
192+
ValueMatcher: gomega.ContainElement(
193+
gomega.SatisfyAll(
194+
gomega.HaveKeyWithValue("type", gomega.BeEquivalentTo(capxv1.NutanixIdentifierName)),
195+
gomega.HaveKeyWithValue("name", gomega.BeEquivalentTo("fake-subnet")),
196+
),
197+
),
195198
},
196199
{
197200
Operation: "add",

0 commit comments

Comments
 (0)