Skip to content

Commit e5198bf

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 ec3280f commit e5198bf

File tree

8 files changed

+1469
-124
lines changed

8 files changed

+1469
-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
@@ -15,22 +15,24 @@ import (
1515

1616
func TestNutanixChecker_Init(t *testing.T) {
1717
tests := []struct {
18-
name string
19-
nutanixConfig *carenv1.NutanixClusterConfigSpec
20-
workerNodeConfigs map[string]*carenv1.NutanixWorkerNodeConfigSpec
21-
expectedCheckCount int
22-
expectedFirstCheckName string
23-
expectedSecondCheckName string
24-
vmImageCheckCount int
18+
name string
19+
nutanixConfig *carenv1.NutanixClusterConfigSpec
20+
workerNodeConfigs map[string]*carenv1.NutanixWorkerNodeConfigSpec
21+
expectedCheckCount int
22+
expectedFirstCheckName string
23+
expectedSecondCheckName string
24+
vmImageCheckCount int
25+
storageContainerCheckCount int
2526
}{
2627
{
27-
name: "basic initialization with no configs",
28-
nutanixConfig: nil,
29-
workerNodeConfigs: nil,
30-
expectedCheckCount: 2, // config check and credentials check
31-
expectedFirstCheckName: "NutanixConfiguration",
32-
expectedSecondCheckName: "NutanixCredentials",
33-
vmImageCheckCount: 0,
28+
name: "basic initialization with no configs",
29+
nutanixConfig: nil,
30+
workerNodeConfigs: nil,
31+
expectedCheckCount: 2, // config check and credentials check
32+
expectedFirstCheckName: "NutanixConfiguration",
33+
expectedSecondCheckName: "NutanixCredentials",
34+
vmImageCheckCount: 0,
35+
storageContainerCheckCount: 0,
3436
},
3537
{
3638
name: "initialization with control plane config",
@@ -39,11 +41,12 @@ func TestNutanixChecker_Init(t *testing.T) {
3941
Nutanix: &carenv1.NutanixNodeSpec{},
4042
},
4143
},
42-
workerNodeConfigs: nil,
43-
expectedCheckCount: 3, // config check, credentials check, 1 VM image check
44-
expectedFirstCheckName: "NutanixConfiguration",
45-
expectedSecondCheckName: "NutanixCredentials",
46-
vmImageCheckCount: 1,
44+
workerNodeConfigs: nil,
45+
expectedCheckCount: 4, // config check, credentials check, 1 VM image check, 1 storage container check
46+
expectedFirstCheckName: "NutanixConfiguration",
47+
expectedSecondCheckName: "NutanixCredentials",
48+
vmImageCheckCount: 1,
49+
storageContainerCheckCount: 1,
4750
},
4851
{
4952
name: "initialization with worker node configs",
@@ -56,10 +59,11 @@ func TestNutanixChecker_Init(t *testing.T) {
5659
Nutanix: &carenv1.NutanixNodeSpec{},
5760
},
5861
},
59-
expectedCheckCount: 4, // config check, credentials check, 2 VM image checks
60-
expectedFirstCheckName: "NutanixConfiguration",
61-
expectedSecondCheckName: "NutanixCredentials",
62-
vmImageCheckCount: 2,
62+
expectedCheckCount: 6, // config check, credentials check, 2 VM image checks, 2 storage container checks
63+
expectedFirstCheckName: "NutanixConfiguration",
64+
expectedSecondCheckName: "NutanixCredentials",
65+
vmImageCheckCount: 2,
66+
storageContainerCheckCount: 2,
6367
},
6468
{
6569
name: "initialization with both control plane and worker node configs",
@@ -73,10 +77,12 @@ func TestNutanixChecker_Init(t *testing.T) {
7377
Nutanix: &carenv1.NutanixNodeSpec{},
7478
},
7579
},
76-
expectedCheckCount: 4, // config check, credentials check, 2 VM image checks (1 CP + 1 worker)
77-
expectedFirstCheckName: "NutanixConfiguration",
78-
expectedSecondCheckName: "NutanixCredentials",
79-
vmImageCheckCount: 2,
80+
// config check, credentials check, 2 VM image checks (1 CP + 1 worker), 2 storage container checks (1 CP + 1 worker)
81+
expectedCheckCount: 6,
82+
expectedFirstCheckName: "NutanixConfiguration",
83+
expectedSecondCheckName: "NutanixCredentials",
84+
vmImageCheckCount: 2,
85+
storageContainerCheckCount: 2,
8086
},
8187
}
8288

@@ -97,6 +103,7 @@ func TestNutanixChecker_Init(t *testing.T) {
97103
configCheckCalled := false
98104
credsCheckCalled := false
99105
vmImageCheckCount := 0
106+
storageContainerCheckCount := 0
100107

101108
checker.initNutanixConfigurationFunc = func(n *nutanixChecker) preflight.Check {
102109
configCheckCalled = true
@@ -129,6 +136,19 @@ func TestNutanixChecker_Init(t *testing.T) {
129136
return checks
130137
}
131138

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

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

pkg/webhook/preflight/nutanix/clients.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package nutanix
33
import (
44
"context"
55

6+
clustermgmtv4 "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/models/clustermgmt/v4/config"
67
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
78

89
prismgoclient "github.com/nutanix-cloud-native/prism-go-client"
@@ -44,6 +45,24 @@ type v4client interface {
4445
*vmmv4.ListImagesApiResponse,
4546
error,
4647
)
48+
GetClusterById(id *string) (*clustermgmtv4.GetClusterApiResponse, error)
49+
ListClusters(
50+
page_ *int,
51+
limit_ *int,
52+
filter_ *string,
53+
orderby_ *string,
54+
apply_ *string,
55+
select_ *string,
56+
args ...map[string]interface{},
57+
) (*clustermgmtv4.ListClustersApiResponse, error)
58+
ListStorageContainers(
59+
page_ *int,
60+
limit_ *int,
61+
filter_ *string,
62+
orderby_ *string,
63+
select_ *string,
64+
args ...map[string]interface{},
65+
) (*clustermgmtv4.ListStorageContainersApiResponse, error)
4766
}
4867

4968
type v4clientWrapper struct {
@@ -81,6 +100,60 @@ func (c *v4clientWrapper) ListImages(page_ *int,
81100
return resp, nil
82101
}
83102

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

0 commit comments

Comments
 (0)