Skip to content

Commit a2e323a

Browse files
authored
Merge pull request #298 from hrak/fix_zone_id_race
Fix race condition causing invalid CS API calls when zone id is not resolved yet
2 parents 31460fb + b78d279 commit a2e323a

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

controllers/cloudstackisolatednetwork_controller.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ func (r *CloudStackIsoNetReconciliationRunner) Reconcile() (retRes ctrl.Result,
7575
if err != nil {
7676
return r.ReturnWrappedError(retErr, "setting up CloudStackCluster patcher")
7777
}
78+
if r.FailureDomain.Spec.Zone.ID == "" {
79+
return r.RequeueWithMessage("Zone ID not resolved yet.")
80+
}
7881
if err := r.CSUser.GetOrCreateIsolatedNetwork(r.FailureDomain, r.ReconciliationSubject, r.CSCluster); err != nil {
7982
return ctrl.Result{}, err
8083
}

controllers/cloudstackisolatednetwork_controller_test.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,58 @@ import (
2020
g "github.com/golang/mock/gomock"
2121
. "github.com/onsi/ginkgo/v2"
2222
. "github.com/onsi/gomega"
23+
"k8s.io/apimachinery/pkg/types"
2324
infrav1 "sigs.k8s.io/cluster-api-provider-cloudstack/api/v1beta3"
2425
dummies "sigs.k8s.io/cluster-api-provider-cloudstack/test/dummies/v1beta3"
26+
ctrl "sigs.k8s.io/controller-runtime"
2527
"sigs.k8s.io/controller-runtime/pkg/client"
2628
)
2729

2830
var _ = Describe("CloudStackIsolatedNetworkReconciler", func() {
2931
Context("With k8s like test environment.", func() {
3032
BeforeEach(func() {
31-
SetupTestEnvironment() // Must happen before setting up managers/reconcilers.
33+
SetupTestEnvironment() // Must happen before setting up managers/reconcilers.
34+
dummies.SetDummyVars()
3235
Ω(IsoNetReconciler.SetupWithManager(k8sManager)).Should(Succeed()) // Register CloudStack IsoNetReconciler.
3336
})
3437

3538
It("Should set itself to ready if there are no errors in calls to CloudStack methods.", func() {
3639
mockCloudClient.EXPECT().GetOrCreateIsolatedNetwork(g.Any(), g.Any(), g.Any()).AnyTimes()
3740
mockCloudClient.EXPECT().AddClusterTag(g.Any(), g.Any(), g.Any()).AnyTimes()
3841

42+
// We use CSFailureDomain2 here because CSFailureDomain1 has an empty Spec.Zone.ID
43+
dummies.CSISONet1.Spec.FailureDomainName = dummies.CSFailureDomain2.Spec.Name
44+
Ω(k8sClient.Create(ctx, dummies.CSFailureDomain2)).Should(Succeed())
3945
Ω(k8sClient.Create(ctx, dummies.CSISONet1)).Should(Succeed())
46+
4047
Eventually(func() bool {
4148
tempIsoNet := &infrav1.CloudStackIsolatedNetwork{}
4249
key := client.ObjectKeyFromObject(dummies.CSISONet1)
4350
if err := k8sClient.Get(ctx, key, tempIsoNet); err == nil {
44-
return true
51+
if tempIsoNet.Status.Ready == true {
52+
return true
53+
}
4554
}
4655
return false
4756
}, timeout).WithPolling(pollInterval).Should(BeTrue())
4857
})
4958
})
59+
60+
Context("With a fake ctrlRuntimeClient and no test Env at all.", func() {
61+
BeforeEach(func() {
62+
setupFakeTestClient()
63+
})
64+
65+
It("Should requeue in case the zone ID is not resolved yet.", func() {
66+
// We use CSFailureDomain1 here because it has an empty Spec.Zone.ID
67+
dummies.CSISONet1.Spec.FailureDomainName = dummies.CSFailureDomain1.Spec.Name
68+
Ω(fakeCtrlClient.Create(ctx, dummies.CSFailureDomain1)).Should(Succeed())
69+
Ω(fakeCtrlClient.Create(ctx, dummies.CSISONet1)).Should(Succeed())
70+
71+
requestNamespacedName := types.NamespacedName{Namespace: dummies.ClusterNameSpace, Name: dummies.CSISONet1.Name}
72+
res, err := IsoNetReconciler.Reconcile(ctx, ctrl.Request{NamespacedName: requestNamespacedName})
73+
Ω(err).ShouldNot(HaveOccurred())
74+
Ω(res.RequeueAfter).ShouldNot(BeZero())
75+
})
76+
})
5077
})

0 commit comments

Comments
 (0)