Skip to content

Commit e5b5cb1

Browse files
committed
feat: adds failure domain api for AWS and EKS
1 parent e059bb5 commit e5b5cb1

File tree

13 files changed

+355
-0
lines changed

13 files changed

+355
-0
lines changed

api/v1alpha1/aws_node_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ type AWSControlPlaneNodeSpec struct {
2525
}
2626

2727
type AWSWorkerNodeSpec struct {
28+
// The failureDomain the machine deployment will use.
29+
// +kubebuilder:validation:Optional
30+
// +kubebuilder:validation:MinLength=1
31+
// +kubebuilder:validation:MaxLength=128
32+
FailureDomain string `json:"failureDomain,omitempty"`
2833
// The IAM instance profile to use for the cluster Machines.
2934
// +kubebuilder:validation:Optional
3035
// +kubebuilder:default=nodes.cluster-api-provider-aws.sigs.k8s.io

api/v1alpha1/crds/caren.nutanix.com_awsworkernodeconfigs.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ spec:
100100
type: string
101101
type: object
102102
type: object
103+
failureDomain:
104+
description: The failureDomain the machine deployment will use.
105+
maxLength: 128
106+
minLength: 1
107+
type: string
103108
iamInstanceProfile:
104109
default: nodes.cluster-api-provider-aws.sigs.k8s.io
105110
description: The IAM instance profile to use for the cluster Machines.

api/v1alpha1/crds/caren.nutanix.com_eksworkernodeconfigs.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ spec:
100100
type: string
101101
type: object
102102
type: object
103+
failureDomain:
104+
description: The failureDomain the machine deployment will use.
105+
maxLength: 128
106+
minLength: 1
107+
type: string
103108
iamInstanceProfile:
104109
default: nodes.cluster-api-provider-aws.sigs.k8s.io
105110
description: The IAM instance profile to use for the cluster Machines.

common/pkg/testutils/capitest/request/items.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,33 @@ func NewWorkerDockerMachineTemplateRequestItem(
245245
uid,
246246
)
247247
}
248+
249+
func NewWorkerMachineDeploymentRequestItem(
250+
uid types.UID,
251+
) runtimehooksv1.GeneratePatchesRequestItem {
252+
return NewRequestItem(
253+
&clusterv1.MachineDeployment{
254+
TypeMeta: metav1.TypeMeta{
255+
APIVersion: clusterv1.GroupVersion.String(),
256+
Kind: "MachineDeployment",
257+
},
258+
ObjectMeta: metav1.ObjectMeta{
259+
Name: "test-machinedeployment",
260+
Namespace: Namespace,
261+
},
262+
Spec: clusterv1.MachineDeploymentSpec{
263+
Template: clusterv1.MachineTemplateSpec{
264+
Spec: clusterv1.MachineSpec{
265+
ClusterName: ClusterName,
266+
},
267+
},
268+
},
269+
},
270+
&runtimehooksv1.HolderReference{
271+
APIVersion: clusterv1.GroupVersion.String(),
272+
Kind: "MachineDeployment",
273+
FieldPath: "",
274+
},
275+
uid,
276+
)
277+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2023 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package failuredomain
5+
6+
import (
7+
"testing"
8+
9+
. "github.com/onsi/ginkgo/v2"
10+
. "github.com/onsi/gomega"
11+
)
12+
13+
func TestFailureDomainPatch(t *testing.T) {
14+
RegisterFailHandler(Fail)
15+
RunSpecs(t, "AWS failure domain mutator suite")
16+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2023 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package failuredomain
5+
6+
import (
7+
"context"
8+
9+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
12+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
16+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
17+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation"
18+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables"
19+
)
20+
21+
const (
22+
// VariableName is the external patch variable name.
23+
VariableName = "failureDomain"
24+
)
25+
26+
type awsFailureDomainWorkerPatchHandler struct {
27+
variableName string
28+
variableFieldPath []string
29+
}
30+
31+
func NewWorkerPatch() *awsFailureDomainWorkerPatchHandler {
32+
return NewAWSFailureDomainWorkerPatchHandler(
33+
v1alpha1.WorkerConfigVariableName,
34+
v1alpha1.AWSVariableName,
35+
VariableName,
36+
)
37+
}
38+
39+
func NewAWSFailureDomainWorkerPatchHandler(
40+
variableName string,
41+
variableFieldPath ...string,
42+
) *awsFailureDomainWorkerPatchHandler {
43+
return &awsFailureDomainWorkerPatchHandler{
44+
variableName: variableName,
45+
variableFieldPath: variableFieldPath,
46+
}
47+
}
48+
49+
func (h *awsFailureDomainWorkerPatchHandler) Mutate(
50+
ctx context.Context,
51+
obj *unstructured.Unstructured,
52+
vars map[string]apiextensionsv1.JSON,
53+
holderRef runtimehooksv1.HolderReference,
54+
_ client.ObjectKey,
55+
_ mutation.ClusterGetter,
56+
) error {
57+
log := ctrl.LoggerFrom(ctx).WithValues(
58+
"holderRef", holderRef,
59+
)
60+
61+
failureDomainVar, err := variables.Get[string](
62+
vars,
63+
h.variableName,
64+
h.variableFieldPath...,
65+
)
66+
if err != nil {
67+
if variables.IsNotFoundError(err) {
68+
log.V(5).Info("AWS failure domain variable for worker not defined")
69+
return nil
70+
}
71+
return err
72+
}
73+
74+
log = log.WithValues(
75+
"variableName",
76+
h.variableName,
77+
"variableFieldPath",
78+
h.variableFieldPath,
79+
"variableValue",
80+
failureDomainVar,
81+
)
82+
83+
// Check if this is a MachineDeployment
84+
if obj.GetKind() != "MachineDeployment" || obj.GetAPIVersion() != clusterv1.GroupVersion.String() {
85+
log.V(5).Info("not a MachineDeployment, skipping")
86+
return nil
87+
}
88+
89+
log.WithValues(
90+
"patchedObjectKind", obj.GetKind(),
91+
"patchedObjectName", client.ObjectKeyFromObject(obj),
92+
).Info("setting failure domain in worker MachineDeployment spec")
93+
94+
if err := unstructured.SetNestedField(
95+
obj.Object,
96+
failureDomainVar,
97+
"spec", "template", "spec", "failureDomain",
98+
); err != nil {
99+
return err
100+
}
101+
102+
return nil
103+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2023 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package failuredomain
5+
6+
import (
7+
. "github.com/onsi/ginkgo/v2"
8+
"github.com/onsi/gomega"
9+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
10+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
11+
12+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
13+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation"
14+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest"
15+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request"
16+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/test/helpers"
17+
)
18+
19+
var _ = Describe("Generate AMI patches for Worker", func() {
20+
patchGenerator := func() mutation.GeneratePatches {
21+
return mutation.NewMetaGeneratePatchesHandler("", helpers.TestEnv.Client, NewWorkerPatch()).(mutation.GeneratePatches)
22+
}
23+
24+
testDefs := []capitest.PatchTestDef{
25+
{
26+
Name: "failure domain for workers set",
27+
Vars: []runtimehooksv1.Variable{
28+
capitest.VariableWithValue(
29+
v1alpha1.WorkerConfigVariableName,
30+
"us-west-2a",
31+
v1alpha1.AWSVariableName,
32+
VariableName,
33+
),
34+
capitest.VariableWithValue(
35+
runtimehooksv1.BuiltinsName,
36+
apiextensionsv1.JSON{
37+
Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`),
38+
},
39+
),
40+
},
41+
RequestItem: request.NewWorkerMachineDeploymentRequestItem(""),
42+
ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{
43+
Operation: "add",
44+
Path: "/spec/template/spec/failureDomain",
45+
ValueMatcher: gomega.Equal("us-west-2a"),
46+
}},
47+
},
48+
}
49+
50+
// create test node for each case
51+
for _, tt := range testDefs {
52+
It(tt.Name, func() {
53+
capitest.AssertGeneratePatches(
54+
GinkgoT(),
55+
patchGenerator,
56+
&tt,
57+
)
58+
})
59+
}
60+
})
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2023 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package failuredomain
5+
6+
import (
7+
"testing"
8+
9+
"k8s.io/utils/ptr"
10+
11+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
12+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest"
13+
awsworkerconfig "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/workerconfig"
14+
)
15+
16+
func TestVariableValidation(t *testing.T) {
17+
capitest.ValidateDiscoverVariables(
18+
t,
19+
v1alpha1.WorkerConfigVariableName,
20+
ptr.To(v1alpha1.AWSWorkerNodeConfig{}.VariableSchema()),
21+
false,
22+
awsworkerconfig.NewVariable,
23+
capitest.VariableTestDef{
24+
Name: "specified failure domain",
25+
Vals: v1alpha1.AWSWorkerNodeConfigSpec{
26+
AWS: &v1alpha1.AWSWorkerNodeSpec{
27+
FailureDomain: "us-west-2a",
28+
},
29+
},
30+
},
31+
)
32+
}

pkg/handlers/aws/mutation/metapatch_handler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/ami"
1212
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/cni/calico"
1313
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/controlplaneloadbalancer"
14+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/failuredomain"
1415
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/iaminstanceprofile"
1516
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/identityref"
1617
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/instancetype"
@@ -54,6 +55,7 @@ func MetaPatchHandler(mgr manager.Manager) handlers.Named {
5455
func MetaWorkerPatchHandler(mgr manager.Manager) handlers.Named {
5556
patchHandlers := []mutation.MetaMutator{
5657
tags.NewWorkerPatch(),
58+
failuredomain.NewWorkerPatch(),
5759
iaminstanceprofile.NewWorkerPatch(),
5860
instancetype.NewWorkerPatch(),
5961
ami.NewWorkerPatch(),
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2023 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package failuredomain
5+
6+
import (
7+
"testing"
8+
9+
. "github.com/onsi/ginkgo/v2"
10+
. "github.com/onsi/gomega"
11+
)
12+
13+
func TestFailureDomainPatch(t *testing.T) {
14+
RegisterFailHandler(Fail)
15+
RunSpecs(t, "EKS failure domain mutator suite")
16+
}

0 commit comments

Comments
 (0)