Skip to content

Commit 47752d7

Browse files
committed
fixup! feat(preflight): Add a check for storage containers
* Update storagecontainer check to work with latest changes * Combine mock clients into one file * Add storagecontainer unit tests * Fix: If the storagecontainer check does not fail, return "allowed: true" * Fix: Use helpers to correctly handle cluster identifier type
1 parent ed05473 commit 47752d7

File tree

8 files changed

+1472
-124
lines changed

8 files changed

+1472
-124
lines changed

pkg/webhook/preflight/nutanix/checker.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ func New(kclient ctrlclient.Client, cluster *clusterv1.Cluster) preflight.Checke
2525
v3clientFactory: newV3Client,
2626
v4clientFactory: newV4Client,
2727

28-
vmImageCheckFunc: vmImageCheck,
29-
initNutanixConfigurationFunc: initNutanixConfiguration,
30-
initCredentialsCheckFunc: initCredentialsCheck,
31-
initVMImageChecksFunc: initVMImageChecks,
28+
vmImageCheckFunc: vmImageCheck,
29+
storageContainerCheckFunc: storageContainerCheck,
30+
initNutanixConfigurationFunc: initNutanixConfiguration,
31+
initCredentialsCheckFunc: initCredentialsCheck,
32+
initVMImageChecksFunc: initVMImageChecks,
33+
initStorageContainerChecksFunc: initStorageContainerChecks,
3234
}
3335
}
3436

@@ -53,6 +55,13 @@ type nutanixChecker struct {
5355
field string,
5456
) preflight.Check
5557

58+
storageContainerCheckFunc func(
59+
n *nutanixChecker,
60+
nodeSpec *carenv1.NutanixNodeSpec,
61+
field string,
62+
csiSpec *carenv1.CSIProvider,
63+
) preflight.Check
64+
5665
initNutanixConfigurationFunc func(
5766
n *nutanixChecker,
5867
) preflight.Check
@@ -66,6 +75,10 @@ type nutanixChecker struct {
6675
n *nutanixChecker,
6776
) []preflight.Check
6877

78+
initStorageContainerChecksFunc func(
79+
n *nutanixChecker,
80+
) []preflight.Check
81+
6982
log logr.Logger
7083
}
7184

@@ -82,7 +95,7 @@ func (n *nutanixChecker) Init(
8295
}
8396

8497
checks = append(checks, n.initVMImageChecksFunc(n)...)
85-
checks = append(checks, n.initStorageContainerChecks()...)
98+
checks = append(checks, n.initStorageContainerChecksFunc(n)...)
8699

87100
// Add more checks here as needed.
88101

pkg/webhook/preflight/nutanix/checker_test.go

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,24 @@ import (
1717

1818
func TestNutanixChecker_Init(t *testing.T) {
1919
tests := []struct {
20-
name string
21-
nutanixConfig *carenv1.NutanixClusterConfigSpec
22-
workerNodeConfigs map[string]*carenv1.NutanixWorkerNodeConfigSpec
23-
expectedCheckCount int
24-
expectedFirstCheckName string
25-
expectedSecondCheckName string
26-
vmImageCheckCount int
20+
name string
21+
nutanixConfig *carenv1.NutanixClusterConfigSpec
22+
workerNodeConfigs map[string]*carenv1.NutanixWorkerNodeConfigSpec
23+
expectedCheckCount int
24+
expectedFirstCheckName string
25+
expectedSecondCheckName string
26+
vmImageCheckCount int
27+
storageContainerCheckCount int
2728
}{
2829
{
29-
name: "basic initialization with no configs",
30-
nutanixConfig: nil,
31-
workerNodeConfigs: nil,
32-
expectedCheckCount: 2, // config check and credentials check
33-
expectedFirstCheckName: "NutanixConfiguration",
34-
expectedSecondCheckName: "NutanixCredentials",
35-
vmImageCheckCount: 0,
30+
name: "basic initialization with no configs",
31+
nutanixConfig: nil,
32+
workerNodeConfigs: nil,
33+
expectedCheckCount: 2, // config check and credentials check
34+
expectedFirstCheckName: "NutanixConfiguration",
35+
expectedSecondCheckName: "NutanixCredentials",
36+
vmImageCheckCount: 0,
37+
storageContainerCheckCount: 0,
3638
},
3739
{
3840
name: "initialization with control plane config",
@@ -41,11 +43,12 @@ func TestNutanixChecker_Init(t *testing.T) {
4143
Nutanix: &carenv1.NutanixNodeSpec{},
4244
},
4345
},
44-
workerNodeConfigs: nil,
45-
expectedCheckCount: 3, // config check, credentials check, 1 VM image check
46-
expectedFirstCheckName: "NutanixConfiguration",
47-
expectedSecondCheckName: "NutanixCredentials",
48-
vmImageCheckCount: 1,
46+
workerNodeConfigs: nil,
47+
expectedCheckCount: 4, // config check, credentials check, 1 VM image check, 1 storage container check
48+
expectedFirstCheckName: "NutanixConfiguration",
49+
expectedSecondCheckName: "NutanixCredentials",
50+
vmImageCheckCount: 1,
51+
storageContainerCheckCount: 1,
4952
},
5053
{
5154
name: "initialization with worker node configs",
@@ -58,10 +61,11 @@ func TestNutanixChecker_Init(t *testing.T) {
5861
Nutanix: &carenv1.NutanixNodeSpec{},
5962
},
6063
},
61-
expectedCheckCount: 4, // config check, credentials check, 2 VM image checks
62-
expectedFirstCheckName: "NutanixConfiguration",
63-
expectedSecondCheckName: "NutanixCredentials",
64-
vmImageCheckCount: 2,
64+
expectedCheckCount: 6, // config check, credentials check, 2 VM image checks, 2 storage container checks
65+
expectedFirstCheckName: "NutanixConfiguration",
66+
expectedSecondCheckName: "NutanixCredentials",
67+
vmImageCheckCount: 2,
68+
storageContainerCheckCount: 2,
6569
},
6670
{
6771
name: "initialization with both control plane and worker node configs",
@@ -75,10 +79,12 @@ func TestNutanixChecker_Init(t *testing.T) {
7579
Nutanix: &carenv1.NutanixNodeSpec{},
7680
},
7781
},
78-
expectedCheckCount: 4, // config check, credentials check, 2 VM image checks (1 CP + 1 worker)
79-
expectedFirstCheckName: "NutanixConfiguration",
80-
expectedSecondCheckName: "NutanixCredentials",
81-
vmImageCheckCount: 2,
82+
// config check, credentials check, 2 VM image checks (1 CP + 1 worker), 2 storage container checks (1 CP + 1 worker)
83+
expectedCheckCount: 6,
84+
expectedFirstCheckName: "NutanixConfiguration",
85+
expectedSecondCheckName: "NutanixCredentials",
86+
vmImageCheckCount: 2,
87+
storageContainerCheckCount: 2,
8288
},
8389
}
8490

@@ -95,6 +101,7 @@ func TestNutanixChecker_Init(t *testing.T) {
95101
configCheckCalled := false
96102
credsCheckCalled := false
97103
vmImageCheckCount := 0
104+
storageContainerCheckCount := 0
98105

99106
checker.initNutanixConfigurationFunc = func(n *nutanixChecker) preflight.Check {
100107
configCheckCalled = true
@@ -127,6 +134,19 @@ func TestNutanixChecker_Init(t *testing.T) {
127134
return checks
128135
}
129136

137+
checker.initStorageContainerChecksFunc = func(n *nutanixChecker) []preflight.Check {
138+
checks := []preflight.Check{}
139+
for i := 0; i < tt.storageContainerCheckCount; i++ {
140+
storageContainerCheckCount++
141+
checks = append(checks, func(ctx context.Context) preflight.CheckResult {
142+
return preflight.CheckResult{
143+
Name: fmt.Sprintf("StorageContainerCheck-%d", i),
144+
}
145+
})
146+
}
147+
return checks
148+
}
149+
130150
// Call Init
131151
ctx := context.Background()
132152
checks := checker.Init(ctx)
@@ -141,6 +161,12 @@ func TestNutanixChecker_Init(t *testing.T) {
141161
assert.True(t, configCheckCalled, "initNutanixConfiguration should have been called")
142162
assert.True(t, credsCheckCalled, "initCredentialsCheck should have been called")
143163
assert.Equal(t, tt.vmImageCheckCount, vmImageCheckCount, "Wrong number of VM image checks")
164+
assert.Equal(
165+
t,
166+
tt.storageContainerCheckCount,
167+
storageContainerCheckCount,
168+
"Wrong number of storage container checks",
169+
)
144170

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

pkg/webhook/preflight/nutanix/clients.go

Lines changed: 73 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
prismgoclient "github.com/nutanix-cloud-native/prism-go-client"
@@ -47,6 +48,24 @@ type v4client interface {
4748
*vmmv4.ListImagesApiResponse,
4849
error,
4950
)
51+
GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error)
52+
ListClusters(
53+
page_ *int,
54+
limit_ *int,
55+
filter_ *string,
56+
orderby_ *string,
57+
apply_ *string,
58+
select_ *string,
59+
args ...map[string]interface{},
60+
) (*clustermgmtv4.ListClustersApiResponse, error)
61+
ListStorageContainers(
62+
page_ *int,
63+
limit_ *int,
64+
filter_ *string,
65+
orderby_ *string,
66+
select_ *string,
67+
args ...map[string]interface{},
68+
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
5069
}
5170

5271
type v4clientWrapper struct {
@@ -84,6 +103,60 @@ func (c *v4clientWrapper) ListImages(page_ *int,
84103
return resp, nil
85104
}
86105

106+
func (c *v4clientWrapper) GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error) {
107+
resp, err := c.client.ClustersApiInstance.GetClusterById(id)
108+
if err != nil {
109+
return nil, err
110+
}
111+
return resp, nil
112+
}
113+
114+
func (c *v4clientWrapper) ListClusters(
115+
page_ *int,
116+
limit_ *int,
117+
filter_ *string,
118+
orderby_ *string,
119+
apply_ *string,
120+
select_ *string,
121+
args ...map[string]interface{},
122+
) (*clustermgmtv4.ListClustersApiResponse, error) {
123+
resp, err := c.client.ClustersApiInstance.ListClusters(
124+
page_,
125+
limit_,
126+
filter_,
127+
orderby_,
128+
apply_,
129+
select_,
130+
args...,
131+
)
132+
if err != nil {
133+
return nil, err
134+
}
135+
return resp, nil
136+
}
137+
138+
func (c *v4clientWrapper) ListStorageContainers(
139+
page_ *int,
140+
limit_ *int,
141+
filter_ *string,
142+
orderby_ *string,
143+
select_ *string,
144+
args ...map[string]interface{},
145+
) (*clustermgmtv4.ListStorageContainersApiResponse, error) {
146+
resp, err := c.client.StorageContainerAPI.ListStorageContainers(
147+
page_,
148+
limit_,
149+
filter_,
150+
orderby_,
151+
select_,
152+
args...,
153+
)
154+
if err != nil {
155+
return nil, err
156+
}
157+
return resp, nil
158+
}
159+
87160
func newV4Client(
88161
credentials prismgoclient.Credentials, //nolint:gocritic // hugeParam is fine
89162
) (v4client, error) {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2024 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package nutanix
5+
6+
import (
7+
"context"
8+
9+
clustermgmtv4 "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/models/clustermgmt/v4/config"
10+
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
11+
12+
prismv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
13+
)
14+
15+
type mockv3client struct {
16+
user *prismv3.UserIntentResponse
17+
err error
18+
}
19+
20+
func (m *mockv3client) GetCurrentLoggedInUser(ctx context.Context) (*prismv3.UserIntentResponse, error) {
21+
return m.user, m.err
22+
}
23+
24+
type mockv4client struct {
25+
getImageByIdFunc func(
26+
uuid *string,
27+
) (
28+
*vmmv4.GetImageApiResponse, error,
29+
)
30+
31+
listImagesFunc func(
32+
page,
33+
limit *int,
34+
filter,
35+
orderby,
36+
select_ *string,
37+
args ...map[string]interface{},
38+
) (
39+
*vmmv4.ListImagesApiResponse,
40+
error,
41+
)
42+
43+
getClusterByIdFunc func(id *string) (*clustermgmtv4.GetClusterApiResponse, error)
44+
45+
listClustersFunc func(
46+
page,
47+
limit *int,
48+
filter,
49+
orderby,
50+
apply,
51+
select_ *string,
52+
args ...map[string]interface{},
53+
) (*clustermgmtv4.ListClustersApiResponse, error)
54+
55+
listStorageContainersFunc func(
56+
page,
57+
limit *int,
58+
filter,
59+
orderby,
60+
select_ *string,
61+
args ...map[string]interface{},
62+
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
63+
}
64+
65+
func (m *mockv4client) GetImageById(uuid *string) (*vmmv4.GetImageApiResponse, error) {
66+
return m.getImageByIdFunc(uuid)
67+
}
68+
69+
func (m *mockv4client) ListImages(
70+
page, limit *int,
71+
filter, orderby, select_ *string,
72+
args ...map[string]interface{},
73+
) (*vmmv4.ListImagesApiResponse, error) {
74+
return m.listImagesFunc(page, limit, filter, orderby, select_)
75+
}
76+
77+
func (m *mockv4client) GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error) {
78+
return m.getClusterByIdFunc(id)
79+
}
80+
81+
func (m *mockv4client) ListClusters(
82+
page, limit *int,
83+
filter, orderby, apply, select_ *string,
84+
args ...map[string]interface{},
85+
) (*clustermgmtv4.ListClustersApiResponse, error) {
86+
return m.listClustersFunc(page, limit, filter, orderby, apply, select_, args...)
87+
}
88+
89+
func (m *mockv4client) ListStorageContainers(
90+
page, limit *int,
91+
filter, orderby, select_ *string,
92+
args ...map[string]interface{},
93+
) (*clustermgmtv4.ListStorageContainersApiResponse, error) {
94+
return m.listStorageContainersFunc(page, limit, filter, orderby, select_, args...)
95+
}

0 commit comments

Comments
 (0)