Skip to content

Commit 826bc00

Browse files
committed
fixup! feat: Nutanix VM image preflight check
Implement Check interface.
1 parent 0290598 commit 826bc00

File tree

8 files changed

+253
-255
lines changed

8 files changed

+253
-255
lines changed

pkg/webhook/preflight/nutanix/checker.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ func New(kclient ctrlclient.Client, cluster *clusterv1.Cluster) preflight.Checke
2424

2525
nclientFactory: newClient,
2626

27-
vmImageCheckFunc: vmImageCheck,
2827
initNutanixConfigurationFunc: initNutanixConfiguration,
2928
initCredentialsCheckFunc: initCredentialsCheck,
3029
initVMImageChecksFunc: initVMImageChecks,
@@ -41,12 +40,6 @@ type nutanixChecker struct {
4140
nclient client
4241
nclientFactory func(prismgoclient.Credentials) (client, error)
4342

44-
vmImageCheckFunc func(
45-
n *nutanixChecker,
46-
machineDetails *carenv1.NutanixMachineDetails,
47-
field string,
48-
) preflight.Check
49-
5043
initNutanixConfigurationFunc func(
5144
n *nutanixChecker,
5245
) preflight.Check

pkg/webhook/preflight/nutanix/checker_test.go

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ import (
1515
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/preflight"
1616
)
1717

18+
type mockCheck struct {
19+
name string
20+
result preflight.CheckResult
21+
}
22+
23+
func (m *mockCheck) Name() string {
24+
return m.name
25+
}
26+
27+
func (m *mockCheck) Run(ctx context.Context) preflight.CheckResult {
28+
return m.result
29+
}
30+
1831
func TestNutanixChecker_Init(t *testing.T) {
1932
tests := []struct {
2033
name string
@@ -98,31 +111,32 @@ func TestNutanixChecker_Init(t *testing.T) {
98111

99112
checker.initNutanixConfigurationFunc = func(n *nutanixChecker) preflight.Check {
100113
configCheckCalled = true
101-
return func(ctx context.Context) preflight.CheckResult {
102-
return preflight.CheckResult{
103-
Name: tt.expectedFirstCheckName,
104-
}
114+
return &mockCheck{
115+
name: tt.expectedFirstCheckName,
116+
result: preflight.CheckResult{Allowed: true},
105117
}
106118
}
107119

108120
checker.initCredentialsCheckFunc = func(ctx context.Context, n *nutanixChecker) preflight.Check {
109121
credsCheckCalled = true
110-
return func(ctx context.Context) preflight.CheckResult {
111-
return preflight.CheckResult{
112-
Name: tt.expectedSecondCheckName,
113-
}
122+
return &mockCheck{
123+
name: tt.expectedSecondCheckName,
124+
result: preflight.CheckResult{Allowed: true},
114125
}
115126
}
116127

117128
checker.initVMImageChecksFunc = func(n *nutanixChecker) []preflight.Check {
118129
checks := []preflight.Check{}
119130
for i := 0; i < tt.vmImageCheckCount; i++ {
120131
vmImageCheckCount++
121-
checks = append(checks, func(ctx context.Context) preflight.CheckResult {
122-
return preflight.CheckResult{
123-
Name: fmt.Sprintf("VMImageCheck-%d", i),
124-
}
125-
})
132+
checks = append(checks,
133+
&mockCheck{
134+
name: fmt.Sprintf("NutanixVMImage-%d", i),
135+
result: preflight.CheckResult{
136+
Allowed: true,
137+
},
138+
},
139+
)
126140
}
127141
return checks
128142
}
@@ -144,10 +158,8 @@ func TestNutanixChecker_Init(t *testing.T) {
144158

145159
// Verify the first two checks when we have results
146160
if len(checks) >= 2 {
147-
result1 := checks[0](ctx)
148-
result2 := checks[1](ctx)
149-
assert.Equal(t, tt.expectedFirstCheckName, result1.Name)
150-
assert.Equal(t, tt.expectedSecondCheckName, result2.Name)
161+
assert.Equal(t, tt.expectedFirstCheckName, checks[0].Name())
162+
assert.Equal(t, tt.expectedSecondCheckName, checks[1].Name())
151163
}
152164
})
153165
}

pkg/webhook/preflight/nutanix/credentials.go

Lines changed: 50 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,47 @@ import (
1818

1919
const credentialsSecretDataKey = "credentials"
2020

21+
type credentialsCheck struct {
22+
result preflight.CheckResult
23+
}
24+
25+
func (c *credentialsCheck) Name() string {
26+
return "NutanixCredentials"
27+
}
28+
29+
func (c *credentialsCheck) Run(_ context.Context) preflight.CheckResult {
30+
return c.result
31+
}
32+
2133
func initCredentialsCheck(
2234
ctx context.Context,
2335
n *nutanixChecker,
2436
) preflight.Check {
2537
n.log.V(5).Info("Initializing Nutanix credentials check")
2638

27-
result := preflight.CheckResult{
28-
Name: "NutanixCredentials",
29-
Allowed: true,
39+
credentialsCheck := &credentialsCheck{
40+
result: preflight.CheckResult{
41+
Allowed: true,
42+
},
3043
}
3144

3245
if n.nutanixClusterConfigSpec == nil && len(n.nutanixWorkerNodeConfigSpecByMachineDeploymentName) == 0 {
3346
// If there is no Nutanix configuration at all, the credentials check is not needed.
34-
return func(ctx context.Context) preflight.CheckResult {
35-
return result
36-
}
47+
return credentialsCheck
3748
}
3849

3950
// There is some Nutanix configuration, so the credentials check is needed.
4051
// However, the credentials configuration is missing, so we cannot perform the check.
4152
if n.nutanixClusterConfigSpec == nil || n.nutanixClusterConfigSpec.Nutanix == nil {
42-
result.Allowed = false
43-
result.Error = true
44-
result.Causes = append(result.Causes,
53+
credentialsCheck.result.Allowed = false
54+
credentialsCheck.result.Error = true
55+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
4556
preflight.Cause{
4657
Message: "Nutanix cluster configuration is not defined in the cluster spec",
4758
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix",
4859
},
4960
)
50-
return func(ctx context.Context) preflight.CheckResult {
51-
return result
52-
}
61+
return credentialsCheck
5362
}
5463

5564
// Get the credentials data in order to initialize the credentials and clients.
@@ -58,17 +67,15 @@ func initCredentialsCheck(
5867
host, port, err := prismCentralEndpointSpec.ParseURL()
5968
if err != nil {
6069
// Should not happen if the cluster passed CEL validation rules.
61-
result.Allowed = false
62-
result.Error = true
63-
result.Causes = append(result.Causes,
70+
credentialsCheck.result.Allowed = false
71+
credentialsCheck.result.Error = true
72+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
6473
preflight.Cause{
6574
Message: fmt.Sprintf("failed to parse Prism Central endpoint URL: %s", err),
6675
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint.url",
6776
},
6877
)
69-
return func(ctx context.Context) preflight.CheckResult {
70-
return result
71-
}
78+
return credentialsCheck
7279
}
7380

7481
credentialsSecret := &corev1.Secret{}
@@ -81,23 +88,21 @@ func initCredentialsCheck(
8188
credentialsSecret,
8289
)
8390
if err != nil {
84-
result.Allowed = false
85-
result.Error = true
86-
result.Causes = append(result.Causes,
91+
credentialsCheck.result.Allowed = false
92+
credentialsCheck.result.Error = true
93+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
8794
preflight.Cause{
8895
Message: fmt.Sprintf("failed to get Prism Central credentials Secret: %s", err),
8996
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint.credentials.secretRef",
9097
},
9198
)
92-
return func(ctx context.Context) preflight.CheckResult {
93-
return result
94-
}
99+
return credentialsCheck
95100
}
96101

97102
if len(credentialsSecret.Data) == 0 {
98-
result.Allowed = false
99-
result.Error = true
100-
result.Causes = append(result.Causes,
103+
credentialsCheck.result.Allowed = false
104+
credentialsCheck.result.Error = true
105+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
101106
preflight.Cause{
102107
Message: fmt.Sprintf(
103108
"credentials Secret '%s' is empty",
@@ -106,16 +111,14 @@ func initCredentialsCheck(
106111
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint.credentials.secretRef",
107112
},
108113
)
109-
return func(ctx context.Context) preflight.CheckResult {
110-
return result
111-
}
114+
return credentialsCheck
112115
}
113116

114117
data, ok := credentialsSecret.Data[credentialsSecretDataKey]
115118
if !ok {
116-
result.Allowed = false
117-
result.Error = true
118-
result.Causes = append(result.Causes,
119+
credentialsCheck.result.Allowed = false
120+
credentialsCheck.result.Error = true
121+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
119122
preflight.Cause{
120123
Message: fmt.Sprintf(
121124
"credentials Secret '%s' does not contain key '%s'",
@@ -125,24 +128,20 @@ func initCredentialsCheck(
125128
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint.credentials.secretRef",
126129
},
127130
)
128-
return func(ctx context.Context) preflight.CheckResult {
129-
return result
130-
}
131+
return credentialsCheck
131132
}
132133

133134
usernamePassword, err := prismcredentials.ParseCredentials(data)
134135
if err != nil {
135-
result.Allowed = false
136-
result.Error = true
137-
result.Causes = append(result.Causes,
136+
credentialsCheck.result.Allowed = false
137+
credentialsCheck.result.Error = true
138+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
138139
preflight.Cause{
139140
Message: fmt.Sprintf("failed to parse Prism Central credentials: %s", err),
140141
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint.credentials",
141142
},
142143
)
143-
return func(ctx context.Context) preflight.CheckResult {
144-
return result
145-
}
144+
return credentialsCheck
146145
}
147146

148147
// Initialize the credentials.
@@ -157,40 +156,34 @@ func initCredentialsCheck(
157156
// Initialize the Nutanix client.
158157
nclient, err := n.nclientFactory(credentials)
159158
if err != nil {
160-
result.Allowed = false
161-
result.Error = true
162-
result.Causes = append(result.Causes,
159+
credentialsCheck.result.Allowed = false
160+
credentialsCheck.result.Error = true
161+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
163162
preflight.Cause{
164163
Message: fmt.Sprintf("Failed to initialize Nutanix client: %s", err),
165164
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint.credentials",
166165
},
167166
)
168-
return func(ctx context.Context) preflight.CheckResult {
169-
return result
170-
}
167+
return credentialsCheck
171168
}
172169

173170
// Validate the credentials using an API call.
174171
_, err = nclient.GetCurrentLoggedInUser(ctx)
175172
if err != nil {
176-
result.Allowed = false
177-
result.Error = true
178-
result.Causes = append(result.Causes,
173+
credentialsCheck.result.Allowed = false
174+
credentialsCheck.result.Error = true
175+
credentialsCheck.result.Causes = append(credentialsCheck.result.Causes,
179176
preflight.Cause{
180177
Message: fmt.Sprintf("Failed to validate credentials using the v3 API client. "+
181178
"The URL and/or credentials may be incorrect. (Error: %q)", err),
182179
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix.prismCentralEndpoint",
183180
},
184181
)
185-
return func(ctx context.Context) preflight.CheckResult {
186-
return result
187-
}
182+
return credentialsCheck
188183
}
189184

190185
// We initialized both clients, and verified the credentials using the v3 client.
191186
n.nclient = nclient
192187

193-
return func(ctx context.Context) preflight.CheckResult {
194-
return result
195-
}
188+
return credentialsCheck
196189
}

0 commit comments

Comments
 (0)