Skip to content

Commit 2abf0a9

Browse files
committed
infrastructure support for Nutanix
1 parent 4b37064 commit 2abf0a9

File tree

12 files changed

+300
-1
lines changed

12 files changed

+300
-1
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ linters-settings:
9494
alias: "ibmpowervsv1"
9595
- pkg: "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
9696
alias: "openstackv1"
97+
- pkg: "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
98+
alias: "nutanixv1"
9799
- pkg: "github.com/openshift/api/machine/v1"
98100
alias: "mapiv1"
99101
- pkg: "github.com/openshift/api/machine/v1beta1"

cmd/cluster-capi-operator/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import (
5252
"sigs.k8s.io/controller-runtime/pkg/manager"
5353
crwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
5454

55+
nutanixv1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
5556
configv1 "github.com/openshift/api/config/v1"
5657
mapiv1 "github.com/openshift/api/machine/v1"
5758
mapiv1beta1 "github.com/openshift/api/machine/v1beta1"
@@ -88,6 +89,7 @@ func initScheme(scheme *runtime.Scheme) {
8889
utilruntime.Must(mapiv1.AddToScheme(scheme))
8990
utilruntime.Must(mapiv1beta1.AddToScheme(scheme))
9091
utilruntime.Must(metal3v1.AddToScheme(scheme))
92+
utilruntime.Must(nutanixv1.AddToScheme(scheme))
9193
}
9294

9395
//nolint:funlen
@@ -287,6 +289,9 @@ func setupPlatformReconcilers(mgr manager.Manager, infra *configv1.Infrastructur
287289
case configv1.BareMetalPlatformType:
288290
setupReconcilers(mgr, infra, platform, &metal3v1.Metal3Cluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace)
289291
setupWebhooks(mgr)
292+
case configv1.NutanixPlatformType:
293+
setupReconcilers(mgr, infra, platform, &nutanixv1.NutanixCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace)
294+
setupWebhooks(mgr)
290295
default:
291296
klog.Infof("Detected platform %q is not supported, skipping capi controllers setup", platform)
292297

e2e/e2e_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
2020
"sigs.k8s.io/controller-runtime/pkg/client/config"
2121

22+
nutanixv1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
2223
configv1 "github.com/openshift/api/config/v1"
2324
mapiv1 "github.com/openshift/api/machine/v1beta1"
2425
"sigs.k8s.io/controller-runtime/pkg/envtest/komega"
@@ -49,6 +50,7 @@ func init() {
4950
utilruntime.Must(vspherev1.AddToScheme(scheme.Scheme))
5051
utilruntime.Must(metal3v1.AddToScheme(scheme.Scheme))
5152
utilruntime.Must(bmov1alpha1.AddToScheme(scheme.Scheme))
53+
utilruntime.Must(nutanixv1.AddToScheme(scheme.Scheme))
5254
}
5355

5456
func TestAPIs(t *testing.T) {

e2e/nutanix_test.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package e2e
2+
3+
import (
4+
nutanixv1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
5+
. "github.com/onsi/ginkgo/v2"
6+
. "github.com/onsi/gomega"
7+
configv1 "github.com/openshift/api/config/v1"
8+
"github.com/openshift/cluster-capi-operator/e2e/framework"
9+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
)
12+
13+
var _ = Describe("Cluster API Nutanix InfraCluster", Ordered, func() {
14+
var nutanixCluster *nutanixv1.NutanixCluster
15+
16+
BeforeAll(func() {
17+
if platform != configv1.NutanixPlatformType {
18+
Skip("Skipping Nutanix E2E tests")
19+
}
20+
})
21+
22+
AfterEach(func() {
23+
if platform != configv1.NutanixPlatformType {
24+
// Because AfterEach always runs, even when tests are skipped, we have to
25+
// explicitly skip it here for other platforms.
26+
Skip("Skipping Nutanix E2E tests")
27+
}
28+
})
29+
30+
It("should have a NutanixCluster created by the infracluster controller", func() {
31+
By("Fetching the NutanixCluster object")
32+
nutanixCluster = &nutanixv1.NutanixCluster{}
33+
err := cl.Get(ctx, client.ObjectKey{
34+
Name: clusterName,
35+
Namespace: framework.CAPINamespace,
36+
}, nutanixCluster)
37+
Expect(err).ToNot(HaveOccurred(), "should be able to get the NutanixCluster")
38+
Expect(nutanixCluster).ToNot(BeNil())
39+
})
40+
41+
It("should have the correct ManagedBy annotation", func() {
42+
By("Validating the ManagedBy annotation")
43+
Expect(nutanixCluster.Annotations).To(HaveKey(clusterv1.ManagedByAnnotation))
44+
Expect(nutanixCluster.Annotations[clusterv1.ManagedByAnnotation]).To(Equal(managedByAnnotationValueClusterCAPIOperatorInfraClusterController))
45+
})
46+
47+
It("should have the control plane endpoint configured", func() {
48+
By("Validating control plane endpoint")
49+
Expect(nutanixCluster.Spec.ControlPlaneEndpoint.Host).ToNot(BeEmpty(), "control plane endpoint host should not be empty")
50+
Expect(nutanixCluster.Spec.ControlPlaneEndpoint.Port).To(BeNumerically(">", 0), "control plane endpoint port should be greater than 0")
51+
})
52+
53+
It("should have PrismCentral configuration if specified in Infrastructure", func() {
54+
By("Checking Infrastructure for Nutanix PrismCentral configuration")
55+
if mapiInfrastructure.Spec.PlatformSpec.Nutanix != nil &&
56+
mapiInfrastructure.Spec.PlatformSpec.Nutanix.PrismCentral.Address != "" {
57+
By("Validating PrismCentral configuration in NutanixCluster")
58+
Expect(nutanixCluster.Spec.PrismCentral).ToNot(BeNil(), "PrismCentral should be configured")
59+
Expect(nutanixCluster.Spec.PrismCentral.Address).To(Equal(mapiInfrastructure.Spec.PlatformSpec.Nutanix.PrismCentral.Address))
60+
Expect(nutanixCluster.Spec.PrismCentral.Port).To(Equal(mapiInfrastructure.Spec.PlatformSpec.Nutanix.PrismCentral.Port))
61+
}
62+
})
63+
64+
It("should have failure domains configured if specified in Infrastructure", func() {
65+
By("Checking Infrastructure for Nutanix failure domains")
66+
if mapiInfrastructure.Spec.PlatformSpec.Nutanix != nil &&
67+
len(mapiInfrastructure.Spec.PlatformSpec.Nutanix.FailureDomains) > 0 {
68+
By("Validating failure domains in NutanixCluster")
69+
Expect(nutanixCluster.Spec.ControlPlaneFailureDomains).ToNot(BeEmpty(), "failure domains should be configured")
70+
Expect(len(nutanixCluster.Spec.ControlPlaneFailureDomains)).To(Equal(len(mapiInfrastructure.Spec.PlatformSpec.Nutanix.FailureDomains)))
71+
72+
// Verify that each failure domain from Infrastructure is present in NutanixCluster
73+
infraFDNames := make(map[string]bool)
74+
for _, fd := range mapiInfrastructure.Spec.PlatformSpec.Nutanix.FailureDomains {
75+
infraFDNames[fd.Name] = true
76+
}
77+
78+
for _, fd := range nutanixCluster.Spec.ControlPlaneFailureDomains {
79+
Expect(infraFDNames).To(HaveKey(fd.Name), "failure domain %s should exist in Infrastructure spec", fd.Name)
80+
}
81+
}
82+
})
83+
84+
It("should eventually become ready", func() {
85+
By("Waiting for NutanixCluster to become ready")
86+
Eventually(func() bool {
87+
updatedCluster := &nutanixv1.NutanixCluster{}
88+
err := cl.Get(ctx, client.ObjectKey{
89+
Name: clusterName,
90+
Namespace: framework.CAPINamespace,
91+
}, updatedCluster)
92+
if err != nil {
93+
return false
94+
}
95+
return updatedCluster.Status.Ready
96+
}, framework.WaitLong).Should(BeTrue(), "NutanixCluster should eventually become ready")
97+
})
98+
})
99+
100+
var _ = Describe("Cluster API Nutanix Cluster", Ordered, func() {
101+
var capiCluster *clusterv1.Cluster
102+
103+
BeforeAll(func() {
104+
if platform != configv1.NutanixPlatformType {
105+
Skip("Skipping Nutanix E2E tests")
106+
}
107+
})
108+
109+
It("should have a CAPI Cluster with NutanixCluster infrastructure reference", func() {
110+
By("Fetching the CAPI Cluster object")
111+
capiCluster = &clusterv1.Cluster{}
112+
err := cl.Get(ctx, client.ObjectKey{
113+
Name: clusterName,
114+
Namespace: framework.CAPINamespace,
115+
}, capiCluster)
116+
Expect(err).ToNot(HaveOccurred(), "should be able to get the CAPI Cluster")
117+
Expect(capiCluster).ToNot(BeNil())
118+
119+
By("Validating infrastructure reference")
120+
Expect(capiCluster.Spec.InfrastructureRef).ToNot(BeNil())
121+
Expect(capiCluster.Spec.InfrastructureRef.Kind).To(Equal("NutanixCluster"))
122+
Expect(capiCluster.Spec.InfrastructureRef.Name).To(Equal(clusterName))
123+
Expect(capiCluster.Spec.InfrastructureRef.Namespace).To(Equal(framework.CAPINamespace))
124+
})
125+
126+
It("should have control plane endpoint initialized", func() {
127+
By("Validating CAPI Cluster control plane endpoint")
128+
Expect(capiCluster.Spec.ControlPlaneEndpoint.Host).ToNot(BeEmpty())
129+
Expect(capiCluster.Spec.ControlPlaneEndpoint.Port).To(BeNumerically(">", 0))
130+
})
131+
})

manifests/0000_30_cluster-api_01_images.configmap.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ data:
2020
"ibmcloud-cluster-api-controllers": "registry.ci.openshift.org/openshift:ibmcloud-cluster-api-controllers",
2121
"vsphere-cluster-api-controllers": "registry.ci.openshift.org/openshift:vsphere-cluster-api-controllers",
2222
"baremetal-cluster-api-controllers": "registry.ci.openshift.org/openshift:baremetal-cluster-api-controllers",
23+
"nutanix-cluster-api-controllers": "registry.ci.openshift.org/openshift:nutanix-cluster-api-controllers",
2324
"kube-rbac-proxy": "registry.ci.openshift.org/openshift:kube-rbac-proxy"
2425
}

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

manifests/image-references

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,7 @@ spec:
4646
from:
4747
kind: DockerImage
4848
name: registry.ci.openshift.org/openshift:baremetal-cluster-api-controllers
49+
- name: nutanix-cluster-api-controllers
50+
from:
51+
kind: DockerImage
52+
name: registry.ci.openshift.org/openshift:nutanix-cluster-api-controllers

pkg/controllers/capiinstaller/component_customizer.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ func providerNameToImageKey(name string) string {
3232
return "baremetal-cluster-api-controllers"
3333
case "ibmcloud":
3434
return "ibmcloud-cluster-api-controllers"
35+
case "nutanix":
36+
return "nutanix-cluster-api-controllers"
3537
case "cluster-api":
3638
return "cluster-capi-controllers"
3739
default:
@@ -41,7 +43,7 @@ func providerNameToImageKey(name string) string {
4143

4244
func providerNameToCommand(name string) string {
4345
switch name {
44-
case "aws", "gcp", "ibmcloud":
46+
case "aws", "gcp", "ibmcloud", "nutanix":
4547
return "./bin/cluster-api-provider-" + name + "-controller-manager"
4648
case "cluster-api":
4749
return "./bin/cluster-api-controller-manager"

pkg/controllers/common.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121

22+
nutanixv1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
2223
configv1 "github.com/openshift/api/config/v1"
2324
awsv1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
2425
ibmpowervsv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
@@ -46,6 +47,8 @@ func InitInfraMachineAndInfraClusterFromProvider(platform configv1.PlatformType)
4647
return &openstackv1.OpenStackMachine{}, &openstackv1.OpenStackCluster{}, nil
4748
case configv1.PowerVSPlatformType:
4849
return &ibmpowervsv1.IBMPowerVSMachine{}, &ibmpowervsv1.IBMPowerVSCluster{}, nil
50+
case configv1.NutanixPlatformType:
51+
return &nutanixv1.NutanixMachine{}, &nutanixv1.NutanixCluster{}, nil
4952
default:
5053
return nil, nil, fmt.Errorf("%w: %s", errPlatformNotSupported, platform)
5154
}
@@ -63,6 +66,8 @@ func InitInfraMachineTemplateAndInfraClusterFromProvider(platform configv1.Platf
6366
return &openstackv1.OpenStackMachineTemplate{}, &openstackv1.OpenStackCluster{}, nil
6467
case configv1.PowerVSPlatformType:
6568
return &ibmpowervsv1.IBMPowerVSMachineTemplate{}, &ibmpowervsv1.IBMPowerVSCluster{}, nil
69+
case configv1.NutanixPlatformType:
70+
return &nutanixv1.NutanixMachineTemplate{}, &nutanixv1.NutanixCluster{}, nil
6671
default:
6772
return nil, nil, fmt.Errorf("%w: %s", errPlatformNotSupported, platform)
6873
}

pkg/controllers/corecluster/corecluster_controller.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ func mapOCPPlatformToInfraClusterKindAndVersion(platform configv1.PlatformType)
235235
return "ibmpowervscluster", capiInfraClusterAPIVersionV1Beta1, nil
236236
case configv1.BareMetalPlatformType:
237237
return "Metal3Cluster", capiInfraClusterAPIVersionV1Beta1, nil
238+
case configv1.NutanixPlatformType:
239+
return "NutanixCluster", capiInfraClusterAPIVersionV1Beta1, nil
238240
default:
239241
return "", "", fmt.Errorf("%w: %q", errUnsupportedPlatformType, platform)
240242
}

0 commit comments

Comments
 (0)