Skip to content

Commit 68e65fe

Browse files
committed
Fix idempotent restore when setting ControlPlaneEndpoint
1 parent 626738a commit 68e65fe

File tree

5 files changed

+102
-6
lines changed

5 files changed

+102
-6
lines changed

api/v1alpha6/openstackcluster_conversion.go

+13
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ var v1alpha6OpenStackClusterRestorer = conversion.RestorerFor[*OpenStackCluster]
7272
return &c.Spec
7373
},
7474
restorev1alpha6ClusterSpec,
75+
// Filter out Bastion, which is restored separately, and
76+
// ControlPlaneEndpoint, which is written by the cluster controller
77+
conversion.HashedFilterField[*OpenStackCluster](
78+
func(s *OpenStackClusterSpec) *OpenStackClusterSpec {
79+
if s.Bastion != nil || s.ControlPlaneEndpoint != (clusterv1.APIEndpoint{}) {
80+
f := *s
81+
f.Bastion = nil
82+
f.ControlPlaneEndpoint = clusterv1.APIEndpoint{}
83+
return &f
84+
}
85+
return s
86+
},
87+
),
7588
),
7689
"status": conversion.HashedFieldRestorer(
7790
func(c *OpenStackCluster) *OpenStackClusterStatus {

api/v1alpha7/openstackcluster_conversion.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ var v1alpha7OpenStackClusterRestorer = conversion.RestorerFor[*OpenStackCluster]
7878
return &c.Spec
7979
},
8080
restorev1alpha7ClusterSpec,
81-
// Filter out Bastion, which is restored separately
82-
conversion.HashedFilterField[*OpenStackCluster, OpenStackClusterSpec](
81+
// Filter out Bastion, which is restored separately, and
82+
// ControlPlaneEndpoint, which is written by the cluster controller
83+
conversion.HashedFilterField[*OpenStackCluster](
8384
func(s *OpenStackClusterSpec) *OpenStackClusterSpec {
84-
if s.Bastion != nil {
85+
if s.Bastion != nil || s.ControlPlaneEndpoint != (clusterv1.APIEndpoint{}) {
8586
f := *s
8687
f.Bastion = nil
88+
f.ControlPlaneEndpoint = clusterv1.APIEndpoint{}
8789
return &f
8890
}
8991
return s

test/e2e/suites/apivalidations/filters_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ var _ = Describe("Filter API validations", func() {
4747
// Initialise a basic cluster object in the correct namespace
4848
cluster = &infrav1.OpenStackCluster{}
4949
cluster.Namespace = namespace.Name
50-
cluster.GenerateName = "cluster-"
50+
cluster.GenerateName = clusterNamePrefix
5151
})
5252

5353
DescribeTable("Allow valid neutron filter tags", func(tags []infrav1.FilterByNeutronTags) {

test/e2e/suites/apivalidations/openstackcluster_test.go

+77-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2626
"sigs.k8s.io/controller-runtime/pkg/client"
2727

28+
infrav1alpha6 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6"
29+
infrav1alpha7 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7"
2830
infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
2931
)
3032

@@ -52,7 +54,7 @@ var _ = Describe("OpenStackCluster API validations", func() {
5254
// Initialise a basic cluster object in the correct namespace
5355
cluster = &infrav1.OpenStackCluster{}
5456
cluster.Namespace = namespace.Name
55-
cluster.GenerateName = "cluster-"
57+
cluster.GenerateName = clusterNamePrefix
5658
})
5759

5860
It("should allow the smallest permissible cluster spec", func() {
@@ -177,4 +179,78 @@ var _ = Describe("OpenStackCluster API validations", func() {
177179
Expect(create(cluster)).NotTo(Succeed(), "OpenStackCluster creation should not succeed")
178180
})
179181
})
182+
183+
Context("v1alpha7", func() {
184+
var cluster *infrav1alpha7.OpenStackCluster
185+
186+
BeforeEach(func() {
187+
// Initialise a basic cluster object in the correct namespace
188+
cluster = &infrav1alpha7.OpenStackCluster{}
189+
cluster.Namespace = namespace.Name
190+
cluster.GenerateName = clusterNamePrefix
191+
})
192+
193+
It("should restore cluster spec idempotently after controller writes to controlPlaneEndpoint", func() {
194+
// Set identityRef.Kind, as it will be lost if the restorer does not execute
195+
cluster.Spec.IdentityRef = &infrav1alpha7.OpenStackIdentityReference{
196+
Kind: "FakeKind",
197+
Name: "identity-ref",
198+
}
199+
Expect(create(cluster)).To(Succeed(), "OpenStackCluster creation should succeed")
200+
201+
// Fetch the infrav1 version of the cluster
202+
infrav1Cluster := &infrav1.OpenStackCluster{}
203+
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cluster.Name, Namespace: cluster.Namespace}, infrav1Cluster)).To(Succeed(), "OpenStackCluster fetch should succeed")
204+
205+
// Update the infrav1 cluster to set the control plane endpoint
206+
infrav1Cluster.Spec.ControlPlaneEndpoint = &clusterv1.APIEndpoint{
207+
Host: "foo",
208+
Port: 1234,
209+
}
210+
Expect(k8sClient.Update(ctx, infrav1Cluster)).To(Succeed(), "Setting control plane endpoint should succeed")
211+
212+
// Fetch the v1alpha7 version of the cluster and ensure that both the new control plane endpoint and the identityRef.Kind are present
213+
cluster = &infrav1alpha7.OpenStackCluster{}
214+
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: infrav1Cluster.Name, Namespace: infrav1Cluster.Namespace}, cluster)).To(Succeed(), "OpenStackCluster fetch should succeed")
215+
Expect(cluster.Spec.ControlPlaneEndpoint).To(Equal(*infrav1Cluster.Spec.ControlPlaneEndpoint), "Control plane endpoint should be restored")
216+
Expect(cluster.Spec.IdentityRef.Kind).To(Equal("FakeKind"), "IdentityRef.Kind should be restored")
217+
})
218+
})
219+
220+
Context("v1alpha6", func() {
221+
var cluster *infrav1alpha6.OpenStackCluster //nolint:staticcheck
222+
223+
BeforeEach(func() {
224+
// Initialise a basic cluster object in the correct namespace
225+
cluster = &infrav1alpha6.OpenStackCluster{} //nolint:staticcheck
226+
cluster.Namespace = namespace.Name
227+
cluster.GenerateName = clusterNamePrefix
228+
})
229+
230+
It("should restore cluster spec idempotently after controller writes to controlPlaneEndpoint", func() {
231+
// Set identityRef.Kind, as it will be lost if the restorer does not execute
232+
cluster.Spec.IdentityRef = &infrav1alpha6.OpenStackIdentityReference{
233+
Kind: "FakeKind",
234+
Name: "identity-ref",
235+
}
236+
Expect(create(cluster)).To(Succeed(), "OpenStackCluster creation should succeed")
237+
238+
// Fetch the infrav1 version of the cluster
239+
infrav1Cluster := &infrav1.OpenStackCluster{}
240+
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cluster.Name, Namespace: cluster.Namespace}, infrav1Cluster)).To(Succeed(), "OpenStackCluster fetch should succeed")
241+
242+
// Update the infrav1 cluster to set the control plane endpoint
243+
infrav1Cluster.Spec.ControlPlaneEndpoint = &clusterv1.APIEndpoint{
244+
Host: "foo",
245+
Port: 1234,
246+
}
247+
Expect(k8sClient.Update(ctx, infrav1Cluster)).To(Succeed(), "Setting control plane endpoint should succeed")
248+
249+
// Fetch the v1alpha6 version of the cluster and ensure that both the new control plane endpoint and the identityRef.Kind are present
250+
cluster = &infrav1alpha6.OpenStackCluster{} //nolint:staticcheck
251+
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: infrav1Cluster.Name, Namespace: infrav1Cluster.Namespace}, cluster)).To(Succeed(), "OpenStackCluster fetch should succeed")
252+
Expect(cluster.Spec.ControlPlaneEndpoint).To(Equal(*infrav1Cluster.Spec.ControlPlaneEndpoint), "Control plane endpoint should be restored")
253+
Expect(cluster.Spec.IdentityRef.Kind).To(Equal("FakeKind"), "IdentityRef.Kind should be restored")
254+
})
255+
})
180256
})

test/e2e/suites/apivalidations/suite_test.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"path/filepath"
2323
"strconv"
2424
"testing"
25+
"time"
2526

2627
. "github.com/onsi/ginkgo/v2"
2728
. "github.com/onsi/gomega"
@@ -56,6 +57,10 @@ var (
5657
mgrDone chan struct{}
5758
)
5859

60+
const (
61+
clusterNamePrefix = "cluster-"
62+
)
63+
5964
func TestAPIs(t *testing.T) {
6065
RegisterFailHandler(Fail)
6166

@@ -144,7 +149,7 @@ var _ = BeforeSuite(func() {
144149
DeferCleanup(func() {
145150
By("Tearing down manager")
146151
mgrCancel()
147-
Eventually(mgrDone).Should(BeClosed(), "Manager should stop")
152+
Eventually(mgrDone).WithTimeout(time.Second*5).Should(BeClosed(), "Manager should stop")
148153
})
149154
})
150155

0 commit comments

Comments
 (0)