Skip to content

Commit 46a03bd

Browse files
committed
Initialize Nutanix client in Init
1 parent 171bbf0 commit 46a03bd

File tree

3 files changed

+93
-71
lines changed

3 files changed

+93
-71
lines changed

pkg/webhook/preflight/nutanix/checker.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ package nutanix
55

66
import (
77
"context"
8+
"fmt"
89

910
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
1011
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
1112

13+
prismv4 "github.com/nutanix-cloud-native/prism-go-client/v4"
14+
1215
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/preflight"
1316
preflightutil "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/preflight/util"
1417
)
@@ -17,7 +20,7 @@ type Checker struct {
1720
client ctrlclient.Client
1821
cluster *clusterv1.Cluster
1922

20-
clientGetter *ClientGetter
23+
nutanixClient *prismv4.Client
2124
variablesGetter *preflightutil.VariablesGetter
2225
}
2326

@@ -28,8 +31,48 @@ func (n *Checker) Init(
2831
) []preflight.Check {
2932
n.client = client
3033
n.cluster = cluster
31-
n.clientGetter = &ClientGetter{client: client, cluster: cluster}
3234
n.variablesGetter = preflightutil.NewVariablesGetter(cluster)
35+
36+
// Initialize the Nutanix client. If it fails, return a check that indicates the error.
37+
clusterConfig, err := n.variablesGetter.ClusterConfig()
38+
if err != nil {
39+
return []preflight.Check{
40+
func(ctx context.Context) preflight.CheckResult {
41+
return preflight.CheckResult{
42+
Name: "NutanixClientInitialization",
43+
Allowed: false,
44+
Error: true,
45+
Causes: []preflight.Cause{
46+
{
47+
Message: fmt.Sprintf("failed to read clusterConfig variable: %s", err),
48+
Field: "cluster.spec.topology.variables",
49+
},
50+
},
51+
}
52+
},
53+
}
54+
}
55+
56+
n.nutanixClient, err = v4client(ctx, client, cluster, clusterConfig.Nutanix)
57+
// TODO Verify the credentials by making a users API call.
58+
if err != nil {
59+
return []preflight.Check{
60+
func(ctx context.Context) preflight.CheckResult {
61+
return preflight.CheckResult{
62+
Name: "NutanixClientInitialization",
63+
Allowed: false,
64+
Error: true,
65+
Causes: []preflight.Cause{
66+
{
67+
Message: fmt.Sprintf("failed to initialize Nutanix client: %s", err),
68+
Field: "cluster.spec.topology.variables[.name=clusterConfig].nutanix",
69+
},
70+
},
71+
}
72+
},
73+
}
74+
}
75+
3376
return []preflight.Check{
3477
n.VMImages,
3578
}

pkg/webhook/preflight/nutanix/client.go

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package nutanix
33
import (
44
"context"
55
"fmt"
6-
"sync"
76

87
corev1 "k8s.io/api/core/v1"
98
"k8s.io/apimachinery/pkg/types"
@@ -14,63 +13,57 @@ import (
1413
prismcredentials "github.com/nutanix-cloud-native/prism-go-client/environment/credentials"
1514
prismv4 "github.com/nutanix-cloud-native/prism-go-client/v4"
1615

17-
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables"
16+
carenv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
1817
)
1918

20-
// ClientGetter provides methods to create Prism Central clients.
21-
// These methods are thread-safe and cache the results for efficiency.
22-
type ClientGetter struct {
23-
client ctrlclient.Client
24-
cluster *clusterv1.Cluster
25-
nutanixClient *prismv4.Client
26-
}
19+
func v4client(ctx context.Context,
20+
client ctrlclient.Client,
21+
cluster *clusterv1.Cluster,
22+
nutanixSpec *carenv1.NutanixSpec,
23+
) (
24+
*prismv4.Client,
25+
error,
26+
) {
27+
if nutanixSpec == nil {
28+
return nil, fmt.Errorf("nutanixSpec is nil")
29+
}
2730

28-
// V4 creates a new Prism V4 client for the Nutanix cluster using Prism Central credentials
29-
// referenced in the clusterConfig. The client is cached for future use. The function returns an
30-
// error if the credentials cannot be retrieved or if the Prism Central endpoint cannot be parsed.
31-
func (g *ClientGetter) V4(ctx context.Context, clusterConfig *variables.ClusterConfigSpec) (*prismv4.Client, error) {
32-
return sync.OnceValues(func() (*prismv4.Client, error) {
33-
if clusterConfig == nil || clusterConfig.Nutanix == nil {
34-
return nil, fmt.Errorf("clusterConfig variable is nil or does not contain Nutanix config")
35-
}
31+
if nutanixSpec.PrismCentralEndpoint.Credentials.SecretRef.Name == "" {
32+
return nil, fmt.Errorf("prism Central credentials reference SecretRef.Name has no value")
33+
}
3634

37-
if clusterConfig.Nutanix.PrismCentralEndpoint.Credentials.SecretRef.Name == "" {
38-
return nil, fmt.Errorf("prism Central credentials reference SecretRef.Name has no value")
39-
}
35+
credentialsSecret := &corev1.Secret{}
36+
if err := client.Get(
37+
ctx,
38+
types.NamespacedName{
39+
Namespace: cluster.Namespace,
40+
Name: nutanixSpec.PrismCentralEndpoint.Credentials.SecretRef.Name,
41+
},
42+
credentialsSecret,
43+
); err != nil {
44+
return nil, fmt.Errorf("failed to get Prism Central credentials Secret: %w", err)
45+
}
4046

41-
credentialsSecret := &corev1.Secret{}
42-
if err := g.client.Get(
43-
ctx,
44-
types.NamespacedName{
45-
Namespace: g.cluster.Namespace,
46-
Name: clusterConfig.Nutanix.PrismCentralEndpoint.Credentials.SecretRef.Name,
47-
},
48-
credentialsSecret,
49-
); err != nil {
50-
return nil, fmt.Errorf("failed to get Prism Central credentials Secret: %w", err)
51-
}
47+
// Get username and password
48+
credentials, err := prismcredentials.ParseCredentials(credentialsSecret.Data["credentials"])
49+
if err != nil {
50+
return nil, fmt.Errorf("failed to parse Prism Central credentials from Secret: %w", err)
51+
}
5252

53-
// Get username and password
54-
credentials, err := prismcredentials.ParseCredentials(credentialsSecret.Data["credentials"])
55-
if err != nil {
56-
return nil, fmt.Errorf("failed to parse Prism Central credentials from Secret: %w", err)
57-
}
53+
host, port, err := nutanixSpec.PrismCentralEndpoint.ParseURL()
54+
if err != nil {
55+
return nil, fmt.Errorf("failed to parse Prism Central endpoint: %w", err)
56+
}
5857

59-
host, port, err := clusterConfig.Nutanix.PrismCentralEndpoint.ParseURL()
60-
if err != nil {
61-
return nil, fmt.Errorf("failed to parse Prism Central endpoint: %w", err)
62-
}
58+
nutanixClient, err := prismv4.NewV4Client(prism.Credentials{
59+
Endpoint: fmt.Sprintf("%s:%d", host, port),
60+
Username: credentials.Username,
61+
Password: credentials.Password,
62+
Insecure: nutanixSpec.PrismCentralEndpoint.Insecure,
63+
})
64+
if err != nil {
65+
return nil, fmt.Errorf("failed to create Prism V4 client: %w", err)
66+
}
6367

64-
nutanixClient, err := prismv4.NewV4Client(prism.Credentials{
65-
Endpoint: fmt.Sprintf("%s:%d", host, port),
66-
Username: credentials.Username,
67-
Password: credentials.Password,
68-
Insecure: clusterConfig.Nutanix.PrismCentralEndpoint.Insecure,
69-
})
70-
if err != nil {
71-
return nil, fmt.Errorf("failed to create Prism V4 client: %w", err)
72-
}
73-
g.nutanixClient = nutanixClient
74-
return g.nutanixClient, nil
75-
})()
68+
return nutanixClient, nil
7669
}

pkg/webhook/preflight/nutanix/image.go

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import (
44
"context"
55
"fmt"
66

7-
prismv4 "github.com/nutanix-cloud-native/prism-go-client/v4"
87
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
98

9+
prismv4 "github.com/nutanix-cloud-native/prism-go-client/v4"
10+
1011
capxv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
1112
carenv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
12-
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables"
1313
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/preflight"
1414
)
1515

@@ -32,7 +32,6 @@ func (n *Checker) VMImages(ctx context.Context) preflight.CheckResult {
3232
if clusterConfig != nil && clusterConfig.ControlPlane != nil && clusterConfig.ControlPlane.Nutanix != nil {
3333
n.vmImageCheckForMachineDetails(
3434
ctx,
35-
clusterConfig,
3635
&clusterConfig.ControlPlane.Nutanix.MachineDetails,
3736
"cluster.spec.topology.variables[.name=clusterConfig].controlPlane.nutanix.machineDetails",
3837
&result,
@@ -56,7 +55,6 @@ func (n *Checker) VMImages(ctx context.Context) preflight.CheckResult {
5655
if workerConfig != nil && workerConfig.Nutanix != nil {
5756
n.vmImageCheckForMachineDetails(
5857
ctx,
59-
clusterConfig,
6058
&workerConfig.Nutanix.MachineDetails,
6159
fmt.Sprintf(
6260
"workers.machineDeployments[.name=%s].variables.overrides[.name=workerConfig].value.nutanix.machineDetails",
@@ -73,7 +71,6 @@ func (n *Checker) VMImages(ctx context.Context) preflight.CheckResult {
7371

7472
func (n *Checker) vmImageCheckForMachineDetails(
7573
ctx context.Context,
76-
clusterConfig *variables.ClusterConfigSpec,
7774
details *carenv1.NutanixMachineDetails,
7875
field string,
7976
result *preflight.CheckResult,
@@ -89,18 +86,7 @@ func (n *Checker) vmImageCheckForMachineDetails(
8986
}
9087

9188
if details.Image != nil {
92-
client, err := n.clientGetter.V4(ctx, clusterConfig)
93-
if err != nil {
94-
result.Allowed = false
95-
result.Error = true
96-
result.Causes = append(result.Causes, preflight.Cause{
97-
Message: fmt.Sprintf("failed to get Nutanix client: %s", err),
98-
Field: field,
99-
})
100-
return
101-
}
102-
103-
images, err := getVMImages(client, details.Image)
89+
images, err := getVMImages(n.nutanixClient, details.Image)
10490
if err != nil {
10591
result.Allowed = false
10692
result.Error = true

0 commit comments

Comments
 (0)