Skip to content

Commit 5c2cd84

Browse files
committed
add infra support for nutanix
1 parent 4a81309 commit 5c2cd84

25 files changed

+2875
-0
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ require (
1111
github.com/google/uuid v1.6.0
1212
github.com/klauspost/compress v1.18.0
1313
github.com/metal3-io/cluster-api-provider-metal3/api v1.10.1
14+
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.2
15+
github.com/nutanix-cloud-native/prism-go-client v0.5.4
1416
github.com/onsi/ginkgo/v2 v2.23.4
1517
github.com/onsi/gomega v1.38.0
1618
github.com/openshift/api v0.0.0-20250731015415-ed654edbd7c6

go.sum

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ github.com/ghostiam/protogetter v0.3.9 h1:j+zlLLWzqLay22Cz/aYwTHKQ88GE2DQ6GkWSYF
165165
github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
166166
github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w=
167167
github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w=
168+
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
169+
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
168170
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
169171
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
170172
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -269,6 +271,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
269271
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
270272
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
271273
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
274+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
275+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
272276
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
273277
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
274278
github.com/gophercloud/gophercloud/v2 v2.7.0 h1:o0m4kgVcPgHlcXiWAjoVxGd8QCmvM5VU+YM71pFbn0E=
@@ -395,6 +399,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
395399
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
396400
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
397401
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
402+
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
403+
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
398404
github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
399405
github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
400406
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@@ -407,6 +413,10 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm
407413
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
408414
github.com/nunnatsa/ginkgolinter v0.19.1 h1:mjwbOlDQxZi9Cal+KfbEJTCz327OLNfwNvoZ70NJ+c4=
409415
github.com/nunnatsa/ginkgolinter v0.19.1/go.mod h1:jkQ3naZDmxaZMXPWaS9rblH+i+GWXQCaS/JFIWcOH2s=
416+
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.2 h1:+ppriYkMNsQPE6+pa0WOPOXsY/G8ZIZmF5gRjhi2RZU=
417+
github.com/nutanix-cloud-native/cluster-api-provider-nutanix v1.7.2/go.mod h1:6AJwae8W/nGmITlnuTnvMxCxxztctEAUJulxC9z/jgU=
418+
github.com/nutanix-cloud-native/prism-go-client v0.5.4 h1:MUZ3dSDRhBQWAYn1HQ0JRb/O0N13GILwiMHMlMT92Zo=
419+
github.com/nutanix-cloud-native/prism-go-client v0.5.4/go.mod h1:N/O9fz5fimjb30RxlPbKbGs/Z2lqMgDqrb6CrsZvQrA=
410420
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
411421
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
412422
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
@@ -573,6 +583,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
573583
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
574584
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
575585
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
586+
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
587+
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
576588
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
577589
github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
578590
github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs=
@@ -831,6 +843,10 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7np
831843
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
832844
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek=
833845
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96/go.mod h1:EOBQyBowOUsd7U4CJnMHNE0ri+zCXyouGdLwC/jZU+I=
846+
sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo=
847+
sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U=
848+
sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E=
849+
sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo=
834850
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
835851
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
836852
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=

manifests/0000_30_cluster-api_12_clusteroperator.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,16 @@ status:
138138
name: ""
139139
namespace: openshift-cluster-api
140140
resource: vspheremachinetemplates
141+
142+
- group: "infrastructure.cluster.x-k8s.io"
143+
name: ""
144+
namespace: openshift-cluster-api
145+
resource: nutanixclusters
146+
- group: "infrastructure.cluster.x-k8s.io"
147+
name: ""
148+
namespace: openshift-cluster-api
149+
resource: nutanixmachines
150+
- group: "infrastructure.cluster.x-k8s.io"
151+
name: ""
152+
namespace: openshift-cluster-api
153+
resource: nutanixmachinetemplates

pkg/controllers/infracluster/infracluster_controller.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,13 @@ func (r *InfraClusterController) ensureInfraCluster(ctx context.Context, log log
228228
}
229229

230230
infraCluster = openstackCluster
231+
case configv1.NutanixPlatformType:
232+
var err error
233+
234+
infraCluster, err = r.ensureNutanixCluster(ctx, log)
235+
if err != nil {
236+
return nil, fmt.Errorf("error ensuring NutanixCluster: %w", err)
237+
}
231238
default:
232239
return nil, errPlatformNotSupported
233240
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
Copyright 2024 Red Hat, Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package infracluster
17+
18+
import (
19+
"context"
20+
"fmt"
21+
"net/url"
22+
"strconv"
23+
24+
"github.com/go-logr/logr"
25+
nutanixv1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
26+
credentialTypes "github.com/nutanix-cloud-native/prism-go-client/environment/credentials"
27+
cerrors "k8s.io/apimachinery/pkg/api/errors"
28+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
30+
"sigs.k8s.io/controller-runtime/pkg/client"
31+
)
32+
33+
// ensureNutanixCluster ensures the NutanixCluster cluster object exists.
34+
func (r *InfraClusterController) ensureNutanixCluster(ctx context.Context, log logr.Logger) (client.Object, error) {
35+
target := &nutanixv1.NutanixCluster{ObjectMeta: metav1.ObjectMeta{
36+
Name: r.Infra.Status.InfrastructureName,
37+
Namespace: defaultCAPINamespace,
38+
}}
39+
40+
// Checking whether InfraCluster object exists. If it doesn't, create it.
41+
if err := r.Get(ctx, client.ObjectKeyFromObject(target), target); err != nil && !cerrors.IsNotFound(err) {
42+
return nil, fmt.Errorf("failed to get InfraCluster: %w", err)
43+
} else if err == nil {
44+
return target, nil
45+
}
46+
47+
log.Info(fmt.Sprintf("NutanixCluster %s/%s does not exist, creating it", target.Namespace, target.Name))
48+
49+
apiURL, err := url.Parse(r.Infra.Status.APIServerInternalURL)
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to parse apiURL: %w", err)
52+
}
53+
54+
port, err := strconv.ParseInt(apiURL.Port(), 10, 32)
55+
if err != nil {
56+
return nil, fmt.Errorf("failed to parse apiURL port: %w", err)
57+
}
58+
59+
if r.Infra.Status.PlatformStatus == nil {
60+
return nil, fmt.Errorf("infrastructure PlatformStatus should not be nil")
61+
}
62+
63+
// Build the NutanixCluster spec
64+
clusterSpec := nutanixv1.NutanixClusterSpec{
65+
ControlPlaneEndpoint: clusterv1.APIEndpoint{
66+
Host: apiURL.Hostname(),
67+
Port: int32(port),
68+
},
69+
}
70+
71+
// Add PrismCentral configuration if available in the Infrastructure spec
72+
if r.Infra.Spec.PlatformSpec.Nutanix != nil && r.Infra.Spec.PlatformSpec.Nutanix.PrismCentral.Address != "" {
73+
clusterSpec.PrismCentral = &credentialTypes.NutanixPrismEndpoint{
74+
// Address holds the IP address or FQDN of the Nutanix Prism Central
75+
Address: r.Infra.Spec.PlatformSpec.Nutanix.PrismCentral.Address,
76+
Port: r.Infra.Spec.PlatformSpec.Nutanix.PrismCentral.Port,
77+
}
78+
}
79+
80+
// Add failure domains if available in the Infrastructure spec
81+
if r.Infra.Spec.PlatformSpec.Nutanix != nil && len(r.Infra.Spec.PlatformSpec.Nutanix.FailureDomains) > 0 {
82+
failureDomains := make([]nutanixv1.NutanixFailureDomainConfig, 0, len(r.Infra.Spec.PlatformSpec.Nutanix.FailureDomains))
83+
for _, fd := range r.Infra.Spec.PlatformSpec.Nutanix.FailureDomains {
84+
failureDomains = append(failureDomains, nutanixv1.NutanixFailureDomainConfig{
85+
Name: fd.Name,
86+
})
87+
}
88+
clusterSpec.FailureDomains = failureDomains
89+
}
90+
91+
target = &nutanixv1.NutanixCluster{
92+
ObjectMeta: metav1.ObjectMeta{
93+
Name: r.Infra.Status.InfrastructureName,
94+
Namespace: defaultCAPINamespace,
95+
// The ManagedBy Annotation is set so CAPI infra providers ignore the InfraCluster object,
96+
// as that's managed externally, in this case by this controller.
97+
Annotations: map[string]string{
98+
clusterv1.ManagedByAnnotation: managedByAnnotationValueClusterCAPIOperatorInfraClusterController,
99+
},
100+
},
101+
Spec: clusterSpec,
102+
}
103+
104+
if err := r.Create(ctx, target); err != nil {
105+
return nil, fmt.Errorf("failed to create InfraCluster: %w", err)
106+
}
107+
108+
log.Info(fmt.Sprintf("InfraCluster '%s/%s' successfully created", defaultCAPINamespace, r.Infra.Status.InfrastructureName))
109+
110+
return target, nil
111+
}

0 commit comments

Comments
 (0)