Skip to content

Commit 3ef53dc

Browse files
feat(preflight): Storage container checks for Nutanix (#1136)
Add pre-flight checks to ensure the storage container mentioned in CSI Provider storage class config parameters is present in all relevant AOS clusters i.e. control plane and workers. --------- Co-authored-by: Daniel Lipovetsky <daniel.lipovetsky@nutanix.com> Co-authored-by: Daniel Lipovetsky <daniel.lipovetsky@gmail.com>
1 parent c706b3d commit 3ef53dc

File tree

6 files changed

+1581
-30
lines changed

6 files changed

+1581
-30
lines changed

pkg/webhook/preflight/nutanix/checker.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ import (
1818
)
1919

2020
var Checker = &nutanixChecker{
21-
configurationCheckFactory: newConfigurationCheck,
22-
credentialsCheckFactory: newCredentialsCheck,
23-
vmImageChecksFactory: newVMImageChecks,
21+
configurationCheckFactory: newConfigurationCheck,
22+
credentialsCheckFactory: newCredentialsCheck,
23+
vmImageChecksFactory: newVMImageChecks,
24+
storageContainerChecksFactory: newStorageContainerChecks,
2425
}
2526

2627
type nutanixChecker struct {
@@ -37,6 +38,10 @@ type nutanixChecker struct {
3738
vmImageChecksFactory func(
3839
cd *checkDependencies,
3940
) []preflight.Check
41+
42+
storageContainerChecksFactory func(
43+
cd *checkDependencies,
44+
) []preflight.Check
4045
}
4146

4247
type checkDependencies struct {
@@ -69,6 +74,7 @@ func (n *nutanixChecker) Init(
6974
}
7075

7176
checks = append(checks, n.vmImageChecksFactory(cd)...)
77+
checks = append(checks, n.storageContainerChecksFactory(cd)...)
7278

7379
// Add more checks here as needed.
7480

pkg/webhook/preflight/nutanix/checker_test.go

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,24 @@ func (m *mockCheck) Run(ctx context.Context) preflight.CheckResult {
3333

3434
func TestNutanixChecker_Init(t *testing.T) {
3535
tests := []struct {
36-
name string
37-
nutanixConfig *carenv1.NutanixClusterConfigSpec
38-
workerNodeConfigs map[string]*carenv1.NutanixWorkerNodeConfigSpec
39-
expectedCheckCount int
40-
expectedFirstCheckName string
41-
expectedSecondCheckName string
42-
vmImageCheckCount int
36+
name string
37+
nutanixConfig *carenv1.NutanixClusterConfigSpec
38+
workerNodeConfigs map[string]*carenv1.NutanixWorkerNodeConfigSpec
39+
expectedCheckCount int
40+
expectedFirstCheckName string
41+
expectedSecondCheckName string
42+
vmImageCheckCount int
43+
storageContainerCheckCount int
4344
}{
4445
{
45-
name: "basic initialization with no configs",
46-
nutanixConfig: nil,
47-
workerNodeConfigs: nil,
48-
expectedCheckCount: 2, // config check and credentials check
49-
expectedFirstCheckName: "NutanixConfiguration",
50-
expectedSecondCheckName: "NutanixCredentials",
51-
vmImageCheckCount: 0,
46+
name: "basic initialization with no configs",
47+
nutanixConfig: nil,
48+
workerNodeConfigs: nil,
49+
expectedCheckCount: 2, // config check and credentials check
50+
expectedFirstCheckName: "NutanixConfiguration",
51+
expectedSecondCheckName: "NutanixCredentials",
52+
vmImageCheckCount: 0,
53+
storageContainerCheckCount: 0,
5254
},
5355
{
5456
name: "initialization with control plane config",
@@ -57,11 +59,12 @@ func TestNutanixChecker_Init(t *testing.T) {
5759
Nutanix: &carenv1.NutanixNodeSpec{},
5860
},
5961
},
60-
workerNodeConfigs: nil,
61-
expectedCheckCount: 3, // config check, credentials check, 1 VM image check
62-
expectedFirstCheckName: "NutanixConfiguration",
63-
expectedSecondCheckName: "NutanixCredentials",
64-
vmImageCheckCount: 1,
62+
workerNodeConfigs: nil,
63+
expectedCheckCount: 4, // config check, credentials check, 1 VM image check, 1 storage container check
64+
expectedFirstCheckName: "NutanixConfiguration",
65+
expectedSecondCheckName: "NutanixCredentials",
66+
vmImageCheckCount: 1,
67+
storageContainerCheckCount: 1,
6568
},
6669
{
6770
name: "initialization with worker node configs",
@@ -74,10 +77,11 @@ func TestNutanixChecker_Init(t *testing.T) {
7477
Nutanix: &carenv1.NutanixNodeSpec{},
7578
},
7679
},
77-
expectedCheckCount: 4, // config check, credentials check, 2 VM image checks
78-
expectedFirstCheckName: "NutanixConfiguration",
79-
expectedSecondCheckName: "NutanixCredentials",
80-
vmImageCheckCount: 2,
80+
expectedCheckCount: 6, // config check, credentials check, 2 VM image checks, 2 storage container checks
81+
expectedFirstCheckName: "NutanixConfiguration",
82+
expectedSecondCheckName: "NutanixCredentials",
83+
vmImageCheckCount: 2,
84+
storageContainerCheckCount: 2,
8185
},
8286
{
8387
name: "initialization with both control plane and worker node configs",
@@ -91,10 +95,12 @@ func TestNutanixChecker_Init(t *testing.T) {
9195
Nutanix: &carenv1.NutanixNodeSpec{},
9296
},
9397
},
94-
expectedCheckCount: 4, // config check, credentials check, 2 VM image checks (1 CP + 1 worker)
95-
expectedFirstCheckName: "NutanixConfiguration",
96-
expectedSecondCheckName: "NutanixCredentials",
97-
vmImageCheckCount: 2,
98+
// config check, credentials check, 2 VM image checks (1 CP + 1 worker), 2 storage container checks (1 CP + 1 worker)
99+
expectedCheckCount: 6,
100+
expectedFirstCheckName: "NutanixConfiguration",
101+
expectedSecondCheckName: "NutanixCredentials",
102+
vmImageCheckCount: 2,
103+
storageContainerCheckCount: 2,
98104
},
99105
}
100106

@@ -107,6 +113,7 @@ func TestNutanixChecker_Init(t *testing.T) {
107113
configCheckCalled := false
108114
credsCheckCalled := false
109115
vmImageCheckCount := 0
116+
storageContainerCheckCount := 0
110117

111118
checker.configurationCheckFactory = func(cd *checkDependencies) preflight.Check {
112119
configCheckCalled = true
@@ -144,6 +151,22 @@ func TestNutanixChecker_Init(t *testing.T) {
144151
return checks
145152
}
146153

154+
checker.storageContainerChecksFactory = func(cd *checkDependencies) []preflight.Check {
155+
checks := []preflight.Check{}
156+
for i := 0; i < tt.storageContainerCheckCount; i++ {
157+
storageContainerCheckCount++
158+
checks = append(checks,
159+
&mockCheck{
160+
name: fmt.Sprintf("NutanixStorageContainer-%d", i),
161+
result: preflight.CheckResult{
162+
Allowed: true,
163+
},
164+
},
165+
)
166+
}
167+
return checks
168+
}
169+
147170
// Call Init
148171
ctx := context.Background()
149172
checks := checker.Init(ctx, nil, &clusterv1.Cluster{
@@ -160,6 +183,12 @@ func TestNutanixChecker_Init(t *testing.T) {
160183
assert.True(t, configCheckCalled, "initNutanixConfiguration should have been called")
161184
assert.True(t, credsCheckCalled, "initCredentialsCheck should have been called")
162185
assert.Equal(t, tt.vmImageCheckCount, vmImageCheckCount, "Wrong number of VM image checks")
186+
assert.Equal(
187+
t,
188+
tt.storageContainerCheckCount,
189+
storageContainerCheckCount,
190+
"Wrong number of storage container checks",
191+
)
163192

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

pkg/webhook/preflight/nutanix/clients.go

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

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

1213
prismgoclient "github.com/nutanix-cloud-native/prism-go-client"
@@ -29,6 +30,24 @@ type client interface {
2930
*vmmv4.ListImagesApiResponse,
3031
error,
3132
)
33+
GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error)
34+
ListClusters(
35+
page_ *int,
36+
limit_ *int,
37+
filter_ *string,
38+
orderby_ *string,
39+
apply_ *string,
40+
select_ *string,
41+
args ...map[string]interface{},
42+
) (*clustermgmtv4.ListClustersApiResponse, error)
43+
ListStorageContainers(
44+
page_ *int,
45+
limit_ *int,
46+
filter_ *string,
47+
orderby_ *string,
48+
select_ *string,
49+
args ...map[string]interface{},
50+
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
3251
}
3352

3453
// clientWrapper implements the client interface and wraps both v3 and v4 clients.
@@ -90,3 +109,57 @@ func (c *clientWrapper) ListImages(page_ *int,
90109
}
91110
return resp, nil
92111
}
112+
113+
func (c *clientWrapper) GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error) {
114+
resp, err := c.v4client.ClustersApiInstance.GetClusterById(id)
115+
if err != nil {
116+
return nil, err
117+
}
118+
return resp, nil
119+
}
120+
121+
func (c *clientWrapper) ListClusters(
122+
page_ *int,
123+
limit_ *int,
124+
filter_ *string,
125+
orderby_ *string,
126+
apply_ *string,
127+
select_ *string,
128+
args ...map[string]interface{},
129+
) (*clustermgmtv4.ListClustersApiResponse, error) {
130+
resp, err := c.v4client.ClustersApiInstance.ListClusters(
131+
page_,
132+
limit_,
133+
filter_,
134+
orderby_,
135+
apply_,
136+
select_,
137+
args...,
138+
)
139+
if err != nil {
140+
return nil, err
141+
}
142+
return resp, nil
143+
}
144+
145+
func (c *clientWrapper) ListStorageContainers(
146+
page_ *int,
147+
limit_ *int,
148+
filter_ *string,
149+
orderby_ *string,
150+
select_ *string,
151+
args ...map[string]interface{},
152+
) (*clustermgmtv4.ListStorageContainersApiResponse, error) {
153+
resp, err := c.v4client.StorageContainerAPI.ListStorageContainers(
154+
page_,
155+
limit_,
156+
filter_,
157+
orderby_,
158+
select_,
159+
args...,
160+
)
161+
if err != nil {
162+
return nil, err
163+
}
164+
return resp, nil
165+
}

pkg/webhook/preflight/nutanix/clients_test.go

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

9+
clustermgmtv4 "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/models/clustermgmt/v4/config"
910
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
1011

1112
prismv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
@@ -35,6 +36,27 @@ type mocknclient struct {
3536
*vmmv4.ListImagesApiResponse,
3637
error,
3738
)
39+
40+
getClusterByIdFunc func(id *string) (*clustermgmtv4.GetClusterApiResponse, error)
41+
42+
listClustersFunc func(
43+
page,
44+
limit *int,
45+
filter,
46+
orderby,
47+
apply,
48+
select_ *string,
49+
args ...map[string]interface{},
50+
) (*clustermgmtv4.ListClustersApiResponse, error)
51+
52+
listStorageContainersFunc func(
53+
page,
54+
limit *int,
55+
filter,
56+
orderby,
57+
select_ *string,
58+
args ...map[string]interface{},
59+
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
3860
}
3961

4062
func (m *mocknclient) GetCurrentLoggedInUser(ctx context.Context) (*prismv3.UserIntentResponse, error) {
@@ -52,3 +74,23 @@ func (m *mocknclient) ListImages(
5274
) (*vmmv4.ListImagesApiResponse, error) {
5375
return m.listImagesFunc(page, limit, filter, orderby, select_)
5476
}
77+
78+
func (m *mocknclient) GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error) {
79+
return m.getClusterByIdFunc(id)
80+
}
81+
82+
func (m *mocknclient) ListClusters(
83+
page, limit *int,
84+
filter, orderby, apply, select_ *string,
85+
args ...map[string]interface{},
86+
) (*clustermgmtv4.ListClustersApiResponse, error) {
87+
return m.listClustersFunc(page, limit, filter, orderby, apply, select_, args...)
88+
}
89+
90+
func (m *mocknclient) ListStorageContainers(
91+
page, limit *int,
92+
filter, orderby, select_ *string,
93+
args ...map[string]interface{},
94+
) (*clustermgmtv4.ListStorageContainersApiResponse, error) {
95+
return m.listStorageContainersFunc(page, limit, filter, orderby, select_, args...)
96+
}

0 commit comments

Comments
 (0)