Skip to content

Commit 490c3e2

Browse files
committed
feat: Validate the configured failure domain(s) exist and valid
1 parent 9c71eb0 commit 490c3e2

File tree

7 files changed

+672
-3
lines changed

7 files changed

+672
-3
lines changed

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"sigs.k8s.io/controller-runtime/pkg/webhook"
2929
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
3030

31+
capxv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
3132
caaphv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
3233
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers"
3334
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/server"
@@ -56,6 +57,7 @@ func main() {
5657
utilruntime.Must(crsv1.AddToScheme(clientScheme))
5758
utilruntime.Must(clusterv1.AddToScheme(clientScheme))
5859
utilruntime.Must(caaphv1.AddToScheme(clientScheme))
60+
utilruntime.Must(capxv1.AddToScheme(clientScheme))
5961

6062
webhookOptions := webhook.Options{
6163
Port: 9444,

pkg/webhook/preflight/nutanix/checker.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
var Checker = &nutanixChecker{
2121
configurationCheckFactory: newConfigurationCheck,
2222
credentialsCheckFactory: newCredentialsCheck,
23+
failureDomainCheckFactory: newFailureDomainChecks,
2324
vmImageChecksFactory: newVMImageChecks,
2425
vmImageKubernetesVersionChecksFactory: newVMImageKubernetesVersionChecks,
2526
storageContainerChecksFactory: newStorageContainerChecks,
@@ -36,6 +37,10 @@ type nutanixChecker struct {
3637
cd *checkDependencies,
3738
) preflight.Check
3839

40+
failureDomainCheckFactory func(
41+
cd *checkDependencies,
42+
) []preflight.Check
43+
3944
vmImageChecksFactory func(
4045
cd *checkDependencies,
4146
) []preflight.Check
@@ -78,6 +83,10 @@ func (n *nutanixChecker) Init(
7883
n.credentialsCheckFactory(ctx, newClient, cd),
7984
}
8085

86+
// The failure domains check need to run before the image, storage container checks that depends on whether
87+
// failure domains are configured correctly.
88+
checks = append(checks, n.failureDomainCheckFactory(cd)...)
89+
8190
checks = append(checks, n.vmImageChecksFactory(cd)...)
8291
checks = append(checks, n.vmImageKubernetesVersionChecksFactory(cd)...)
8392
checks = append(checks, n.storageContainerChecksFactory(cd)...)

pkg/webhook/preflight/nutanix/checker_test.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func TestNutanixChecker_Init(t *testing.T) {
4242
vmImageCheckCount int
4343
vmImageKubernetesVersionCheckCount int
4444
storageContainerCheckCount int
45+
failureDomainCheckCount int
4546
}{
4647
{
4748
name: "basic initialization with no configs",
@@ -53,6 +54,7 @@ func TestNutanixChecker_Init(t *testing.T) {
5354
vmImageCheckCount: 0,
5455
vmImageKubernetesVersionCheckCount: 0,
5556
storageContainerCheckCount: 0,
57+
failureDomainCheckCount: 0,
5658
},
5759
{
5860
name: "initialization with control plane config",
@@ -62,12 +64,13 @@ func TestNutanixChecker_Init(t *testing.T) {
6264
},
6365
},
6466
workerNodeConfigs: nil,
65-
expectedCheckCount: 5, //nolint:lll // config check, credentials check, 1 VM image check, 1 storage container check, 1 VM image Kubernetes version check
67+
expectedCheckCount: 6, //nolint:lll // config check, credentials check, 1 VM image check, 1 storage container check, 1 VM image Kubernetes version check
6668
expectedFirstCheckName: "NutanixConfiguration",
6769
expectedSecondCheckName: "NutanixCredentials",
6870
vmImageCheckCount: 1,
6971
vmImageKubernetesVersionCheckCount: 1,
7072
storageContainerCheckCount: 1,
73+
failureDomainCheckCount: 1,
7174
},
7275
{
7376
name: "initialization with worker node configs",
@@ -80,12 +83,13 @@ func TestNutanixChecker_Init(t *testing.T) {
8083
Nutanix: &carenv1.NutanixWorkerNodeSpec{},
8184
},
8285
},
83-
expectedCheckCount: 8, //nolint:lll // config check, credentials check, 2 VM image checks, 2 storage container checks, 2 VM image Kubernetes version checks
86+
expectedCheckCount: 10, //nolint:lll // config check, credentials check, 2 VM image checks, 2 storage container checks, 2 VM image Kubernetes version checks
8487
expectedFirstCheckName: "NutanixConfiguration",
8588
expectedSecondCheckName: "NutanixCredentials",
8689
vmImageCheckCount: 2,
8790
vmImageKubernetesVersionCheckCount: 2,
8891
storageContainerCheckCount: 2,
92+
failureDomainCheckCount: 2,
8993
},
9094
{
9195
name: "initialization with both control plane and worker node configs",
@@ -99,12 +103,13 @@ func TestNutanixChecker_Init(t *testing.T) {
99103
Nutanix: &carenv1.NutanixWorkerNodeSpec{},
100104
},
101105
},
102-
expectedCheckCount: 8, //nolint:lll // config check, credentials check, 2 VM image checks (1 CP + 1 worker), 2 storage container checks (1 CP + 1 worker), 2 VM image Kubernetes version checks
106+
expectedCheckCount: 10, //nolint:lll // config check, credentials check, 2 VM image checks (1 CP + 1 worker), 2 storage container checks (1 CP + 1 worker), 2 VM image Kubernetes version checks
103107
expectedFirstCheckName: "NutanixConfiguration",
104108
expectedSecondCheckName: "NutanixCredentials",
105109
vmImageCheckCount: 2,
106110
vmImageKubernetesVersionCheckCount: 2,
107111
storageContainerCheckCount: 2,
112+
failureDomainCheckCount: 2,
108113
},
109114
}
110115

@@ -119,6 +124,7 @@ func TestNutanixChecker_Init(t *testing.T) {
119124
vmImageCheckCount := 0
120125
storageContainerCheckCount := 0
121126
vmImageKubernetesVersionCheckCount := 0
127+
failureDomainCheckCount := 0
122128

123129
checker.configurationCheckFactory = func(cd *checkDependencies) preflight.Check {
124130
configCheckCalled = true
@@ -188,6 +194,22 @@ func TestNutanixChecker_Init(t *testing.T) {
188194
return checks
189195
}
190196

197+
checker.failureDomainCheckFactory = func(cd *checkDependencies) []preflight.Check {
198+
checks := []preflight.Check{}
199+
for i := 0; i < tt.failureDomainCheckCount; i++ {
200+
failureDomainCheckCount++
201+
checks = append(checks,
202+
&mockCheck{
203+
name: fmt.Sprintf("NutanixFailureDomain-%d", i),
204+
result: preflight.CheckResult{
205+
Allowed: true,
206+
},
207+
},
208+
)
209+
}
210+
return checks
211+
}
212+
191213
// Call Init
192214
ctx := context.Background()
193215
checks := checker.Init(ctx, nil, &clusterv1.Cluster{
@@ -210,6 +232,12 @@ func TestNutanixChecker_Init(t *testing.T) {
210232
storageContainerCheckCount,
211233
"Wrong number of storage container checks",
212234
)
235+
assert.Equal(
236+
t,
237+
tt.failureDomainCheckCount,
238+
failureDomainCheckCount,
239+
"Wrong number of failure domain checks",
240+
)
213241

214242
// Verify the first two checks when we have results
215243
if len(checks) >= 2 {

pkg/webhook/preflight/nutanix/clients.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99

1010
clustermgmtv4 "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/models/clustermgmt/v4/config"
11+
netv4 "github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4/models/networking/v4/config"
1112
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
1213

1314
prismgoclient "github.com/nutanix-cloud-native/prism-go-client"
@@ -48,6 +49,16 @@ type client interface {
4849
select_ *string,
4950
args ...map[string]interface{},
5051
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
52+
GetSubnetById(id *string) (*netv4.GetSubnetApiResponse, error)
53+
ListSubnets(
54+
page_ *int,
55+
limit_ *int,
56+
filter_ *string,
57+
orderby_ *string,
58+
expand_ *string,
59+
select_ *string,
60+
args ...map[string]interface{},
61+
) (*netv4.ListSubnetsApiResponse, error)
5162
}
5263

5364
// clientWrapper implements the client interface and wraps both v3 and v4 clients.
@@ -163,3 +174,35 @@ func (c *clientWrapper) ListStorageContainers(
163174
}
164175
return resp, nil
165176
}
177+
178+
func (c *clientWrapper) GetSubnetById(id *string) (*netv4.GetSubnetApiResponse, error) {
179+
resp, err := c.v4client.SubnetsApiInstance.GetSubnetById(id)
180+
if err != nil {
181+
return nil, err
182+
}
183+
return resp, nil
184+
}
185+
186+
func (c *clientWrapper) ListSubnets(
187+
page_ *int,
188+
limit_ *int,
189+
filter_ *string,
190+
orderby_ *string,
191+
expand_ *string,
192+
select_ *string,
193+
args ...map[string]interface{},
194+
) (*netv4.ListSubnetsApiResponse, error) {
195+
resp, err := c.v4client.SubnetsApiInstance.ListSubnets(
196+
page_,
197+
limit_,
198+
filter_,
199+
orderby_,
200+
expand_,
201+
select_,
202+
args...,
203+
)
204+
if err != nil {
205+
return nil, err
206+
}
207+
return resp, nil
208+
}

pkg/webhook/preflight/nutanix/clients_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88

99
clustermgmtv4 "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/models/clustermgmt/v4/config"
10+
netv4 "github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4/models/networking/v4/config"
1011
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
1112

1213
prismv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
@@ -57,6 +58,18 @@ type mocknclient struct {
5758
select_ *string,
5859
args ...map[string]interface{},
5960
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
61+
62+
GetSubnetByIdFunc func(id *string) (*netv4.GetSubnetApiResponse, error)
63+
64+
ListSubnetsFunc func(
65+
page_ *int,
66+
limit_ *int,
67+
filter_ *string,
68+
orderby_ *string,
69+
expand_ *string,
70+
select_ *string,
71+
args ...map[string]interface{},
72+
) (*netv4.ListSubnetsApiResponse, error)
6073
}
6174

6275
func (m *mocknclient) GetCurrentLoggedInUser(ctx context.Context) (*prismv3.UserIntentResponse, error) {
@@ -94,3 +107,19 @@ func (m *mocknclient) ListStorageContainers(
94107
) (*clustermgmtv4.ListStorageContainersApiResponse, error) {
95108
return m.listStorageContainersFunc(page, limit, filter, orderby, select_, args...)
96109
}
110+
111+
func (m *mocknclient) GetSubnetById(id *string) (*netv4.GetSubnetApiResponse, error) {
112+
return m.GetSubnetByIdFunc(id)
113+
}
114+
115+
func (m *mocknclient) ListSubnets(
116+
page_ *int,
117+
limit_ *int,
118+
filter_ *string,
119+
orderby_ *string,
120+
expand_ *string,
121+
select_ *string,
122+
args ...map[string]interface{},
123+
) (*netv4.ListSubnetsApiResponse, error) {
124+
return m.ListSubnetsFunc(page_, limit_, filter_, orderby_, expand_, select_, args...)
125+
}

0 commit comments

Comments
 (0)