Skip to content

Commit d61f673

Browse files
ShyamsundarRBenamarMk
authored andcommitted
Refactor haveOverlappingMetroZones to return a list of cluster lists
As a part of deprecating spec.Region from DRCluster, the way to process overlapping metro DRPolicies was amended to return different maps from the corresponsing region based or peerClass based policies. This is now refactored to return only a list of list of clusters as required to detect overlapping metro zones. Signed-off-by: Shyamsundar Ranganathan <[email protected]>
1 parent 0eb89a9 commit d61f673

File tree

4 files changed

+108
-89
lines changed

4 files changed

+108
-89
lines changed

internal/controller/drplacementcontrol.go

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,64 +1890,85 @@ func (d *DRPCInstance) newVRGSpecSync() *rmn.VRGSyncSpec {
18901890
}
18911891
}
18921892

1893-
func dRPolicySupportsMetro(drpolicy *rmn.DRPolicy, drclusters []rmn.DRCluster) (bool, map[string][]string) {
1894-
syncPeerClasses := drpolicy.Status.Sync.PeerClasses
1895-
aSyncPeerClasses := drpolicy.Status.Async.PeerClasses
1896-
1897-
if len(syncPeerClasses) == 0 && len(aSyncPeerClasses) == 0 {
1893+
// dRPolicySupportsMetro returns a boolean indicating that the policy supports a Metro(Sync) DR capability, and a
1894+
// list of list of strings, where each list of strings contains the name of the clusters that are in a Sync
1895+
// relationship
1896+
func dRPolicySupportsMetro(drpolicy *rmn.DRPolicy, drclusters []rmn.DRCluster, drClusterIDsToNames map[string]string) (
1897+
supportsMetro bool,
1898+
metroClustersInPolicy [][]string,
1899+
) {
1900+
if len(drpolicy.Status.Sync.PeerClasses) == 0 && len(drpolicy.Status.Async.PeerClasses) == 0 {
18981901
return checkMetroSupportUsingRegion(drpolicy, drclusters)
18991902
}
19001903

1901-
if len(syncPeerClasses) != 0 {
1902-
return checkMetroSupportUsingPeerClass(drpolicy)
1904+
if len(drpolicy.Status.Sync.PeerClasses) != 0 {
1905+
return checkMetroSupportUsingPeerClass(drpolicy, drClusterIDsToNames)
19031906
}
19041907

19051908
return false, nil
19061909
}
19071910

1908-
func checkMetroSupportUsingPeerClass(drPolicy *rmn.DRPolicy) (bool, map[string][]string) {
1909-
peerClasses := drPolicy.Status.Sync.PeerClasses
1910-
if len(peerClasses) == 0 {
1911+
func checkMetroSupportUsingPeerClass(drPolicy *rmn.DRPolicy, drClusterIDsToNames map[string]string) (bool, [][]string) {
1912+
if len(drPolicy.Status.Sync.PeerClasses) == 0 {
19111913
return false, nil
19121914
}
19131915

1914-
metroMap := make(map[string][]string)
1915-
for _, peerClass := range peerClasses {
1916-
metroMap[peerClass.StorageClassName] = peerClass.ClusterIDs
1916+
if drClusterIDsToNames == nil {
1917+
return true, nil
19171918
}
19181919

1919-
return true, metroMap
1920+
metroClustersInPolicy := [][]string{}
1921+
1922+
for idx := range drPolicy.Status.Sync.PeerClasses {
1923+
if len(drPolicy.Status.Sync.PeerClasses[idx].StorageID) != 1 {
1924+
continue
1925+
}
1926+
1927+
if len(drPolicy.Status.Sync.PeerClasses[idx].ClusterIDs) == 0 {
1928+
return false, nil
1929+
}
1930+
1931+
peerClusterNames := []string{}
1932+
for _, cID := range drPolicy.Status.Sync.PeerClasses[idx].ClusterIDs {
1933+
peerClusterNames = append(peerClusterNames, drClusterIDsToNames[cID])
1934+
}
1935+
1936+
if len(peerClusterNames) != len(drPolicy.Status.Sync.PeerClasses[idx].ClusterIDs) {
1937+
return false, nil
1938+
}
1939+
1940+
metroClustersInPolicy = append(metroClustersInPolicy, peerClusterNames)
1941+
}
1942+
1943+
return true, metroClustersInPolicy
19201944
}
19211945

19221946
func checkMetroSupportUsingRegion(drpolicy *rmn.DRPolicy, drclusters []rmn.DRCluster) (
19231947
supportsMetro bool,
1924-
metroMap map[string][]string,
1948+
metroClustersInPolicy [][]string,
19251949
) {
19261950
allRegionsMap := make(map[rmn.Region][]string)
1927-
metroMap = make(map[string][]string)
1951+
metroClustersInPolicy = [][]string{}
19281952

19291953
for _, managedCluster := range rmnutil.DRPolicyClusterNames(drpolicy) {
19301954
for _, v := range drclusters {
19311955
if v.Name == managedCluster {
1932-
if v.Spec.Region == "" {
1933-
return supportsMetro, metroMap
1934-
}
1935-
19361956
allRegionsMap[v.Spec.Region] = append(
19371957
allRegionsMap[v.Spec.Region],
19381958
managedCluster)
19391959
}
19401960
}
19411961
}
19421962

1943-
for k, v := range allRegionsMap {
1963+
for _, v := range allRegionsMap {
19441964
if len(v) > 1 {
19451965
supportsMetro = true
1946-
metroMap[string(k)] = v
1966+
1967+
metroClustersInPolicy = append(metroClustersInPolicy, v)
19471968
}
19481969
}
19491970

1950-
return supportsMetro, metroMap
1971+
return supportsMetro, metroClustersInPolicy
19511972
}
19521973

19531974
func (d *DRPCInstance) ensureNamespaceManifestWork(homeCluster string) error {

internal/controller/drplacementcontrol_controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ func (r *DRPlacementControlReconciler) createDRPCInstance(
406406

407407
d.drType = DRTypeAsync
408408

409-
isMetro, _ := dRPolicySupportsMetro(drPolicy, drClusters)
409+
isMetro, _ := dRPolicySupportsMetro(drPolicy, drClusters, nil)
410410
if isMetro {
411411
d.volSyncDisabled = true
412412
d.drType = DRTypeSync
@@ -1466,7 +1466,7 @@ func (r *DRPlacementControlReconciler) setDRPCMetrics(ctx context.Context,
14661466
}
14671467

14681468
// do not set sync metrics if metro-dr
1469-
isMetro, _ := dRPolicySupportsMetro(drPolicy, drClusters)
1469+
isMetro, _ := dRPolicySupportsMetro(drPolicy, drClusters, nil)
14701470
if isMetro {
14711471
return nil
14721472
}

internal/controller/drplacementcontrol_watcher.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ func DRPCsFailingOverToCluster(k8sclient client.Client, log logr.Logger, drclust
478478
}
479479

480480
// Skip if policy is of type metro, fake the from and to cluster
481-
if metro, _ := dRPolicySupportsMetro(drpolicy, drClusters); metro {
481+
if metro, _ := dRPolicySupportsMetro(drpolicy, drClusters, nil); metro {
482482
log.Info("Sync DRPolicy detected, skipping!")
483483

484484
break

internal/controller/drpolicy_controller.go

Lines changed: 61 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,9 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
104104
u.validatedSetFalse("NamespaceCreateFailed", err))
105105
}
106106

107-
drclusters := &ramen.DRClusterList{}
108-
109-
if err := r.Client.List(ctx, drclusters); err != nil {
110-
return ctrl.Result{}, fmt.Errorf("drclusters list: %w", u.validatedSetFalse("drClusterListFailed", err))
107+
drclusters, drClusterIDsToNames, err := r.getDRClusterDetails(ctx)
108+
if err != nil {
109+
return ctrl.Result{}, fmt.Errorf("drclusters details: %w", u.validatedSetFalse("drClusterDetailsFailed", err))
111110
}
112111

113112
secretsUtil := &util.SecretsUtil{Client: r.Client, APIReader: r.APIReader, Ctx: ctx, Log: log}
@@ -119,7 +118,7 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
119118

120119
log.Info("create/update")
121120

122-
reason, err := validateDRPolicy(ctx, drpolicy, drclusters, r.APIReader)
121+
reason, err := validateDRPolicy(ctx, drpolicy, drclusters, r.APIReader, drClusterIDsToNames)
123122
if err != nil {
124123
statusErr := u.validatedSetFalse(reason, err)
125124
if !errors.Is(statusErr, err) || reason != ReasonDRClusterNotFound {
@@ -166,7 +165,7 @@ func (r *DRPolicyReconciler) reconcile(
166165
}
167166

168167
func (r *DRPolicyReconciler) initiateDRPolicyMetrics(drpolicy *ramen.DRPolicy, drclusters *ramen.DRClusterList) error {
169-
isMetro, _ := dRPolicySupportsMetro(drpolicy, drclusters.Items)
168+
isMetro, _ := dRPolicySupportsMetro(drpolicy, drclusters.Items, nil)
170169

171170
// Do not set metric for metro-dr
172171
if !isMetro {
@@ -178,10 +177,36 @@ func (r *DRPolicyReconciler) initiateDRPolicyMetrics(drpolicy *ramen.DRPolicy, d
178177
return nil
179178
}
180179

180+
func (r *DRPolicyReconciler) getDRClusterDetails(ctx context.Context) (*ramen.DRClusterList, map[string]string, error) {
181+
drClusters := &ramen.DRClusterList{}
182+
if err := r.Client.List(ctx, drClusters); err != nil {
183+
return nil, nil, fmt.Errorf("drclusters list: %w", err)
184+
}
185+
186+
drClusterIDsToNames := map[string]string{}
187+
188+
for idx := range drClusters.Items {
189+
mc, err := util.NewManagedClusterInstance(ctx, r.Client, drClusters.Items[idx].GetName())
190+
if err != nil {
191+
return nil, nil, fmt.Errorf("drclusters ManagedCluster (%s): %w", drClusters.Items[idx].GetName(), err)
192+
}
193+
194+
clID, err := mc.ClusterID()
195+
if err != nil {
196+
return nil, nil, fmt.Errorf("drclusters cluster ID (%s): %w", drClusters.Items[idx].GetName(), err)
197+
}
198+
199+
drClusterIDsToNames[clID] = drClusters.Items[idx].GetName()
200+
}
201+
202+
return drClusters, drClusterIDsToNames, nil
203+
}
204+
181205
func validateDRPolicy(ctx context.Context,
182206
drpolicy *ramen.DRPolicy,
183207
drclusters *ramen.DRClusterList,
184208
apiReader client.Reader,
209+
drClusterIDsToNames map[string]string,
185210
) (string, error) {
186211
// DRPolicy does not support both Sync and Async configurations in one single DRPolicy
187212
if len(drpolicy.Status.Sync.PeerClasses) > 0 && len(drpolicy.Status.Async.PeerClasses) > 0 {
@@ -200,7 +225,7 @@ func validateDRPolicy(ctx context.Context,
200225
return reason, err
201226
}
202227

203-
err = validatePolicyConflicts(ctx, apiReader, drpolicy, drclusters)
228+
err = validatePolicyConflicts(ctx, apiReader, drpolicy, drclusters, drClusterIDsToNames)
204229
if err != nil {
205230
return ReasonValidationFailed, err
206231
}
@@ -258,13 +283,14 @@ func validatePolicyConflicts(ctx context.Context,
258283
apiReader client.Reader,
259284
drpolicy *ramen.DRPolicy,
260285
drclusters *ramen.DRClusterList,
286+
drClusterIDsToNames map[string]string,
261287
) error {
262288
drpolicies, err := util.GetAllDRPolicies(ctx, apiReader)
263289
if err != nil {
264290
return fmt.Errorf("validate managed cluster in drpolicy %v failed: %w", drpolicy.Name, err)
265291
}
266292

267-
err = hasConflictingDRPolicy(drpolicy, drclusters, drpolicies)
293+
err = hasConflictingDRPolicy(drpolicy, drclusters, drpolicies, drClusterIDsToNames)
268294
if err != nil {
269295
return fmt.Errorf("validate managed cluster in drpolicy failed: %w", err)
270296
}
@@ -274,7 +300,12 @@ func validatePolicyConflicts(ctx context.Context,
274300

275301
// If two drpolicies have common managed cluster(s) and at least one of them is
276302
// a metro supported drpolicy, then fail.
277-
func hasConflictingDRPolicy(match *ramen.DRPolicy, drclusters *ramen.DRClusterList, list ramen.DRPolicyList) error {
303+
func hasConflictingDRPolicy(
304+
match *ramen.DRPolicy,
305+
drclusters *ramen.DRClusterList,
306+
list ramen.DRPolicyList,
307+
drClusterIDsToNames map[string]string,
308+
) error {
278309
// Valid cases
279310
// [e1,w1] [e1,c1]
280311
// [e1,w1] [e1,w1]
@@ -294,80 +325,47 @@ func hasConflictingDRPolicy(match *ramen.DRPolicy, drclusters *ramen.DRClusterLi
294325
continue
295326
}
296327

297-
// None of the common managed clusters should belong to Metro Regions in either of the drpolicies.
298-
if haveOverlappingMetroZones(match, drp, drclusters) {
328+
// None of the common managed clusters should belong to Metro clusters in either of the drpolicies.
329+
if haveOverlappingMetroZones(match, drp, drclusters, drClusterIDsToNames) {
299330
return fmt.Errorf("drpolicy: %v has overlapping metro region with another drpolicy %v", match.Name, drp.Name)
300331
}
301332
}
302333

303334
return nil
304335
}
305336

306-
func getClusterIDSFromPolicy(drpolicy *ramen.DRPolicy) []string {
307-
cids := []string{}
308-
309-
if len(drpolicy.Status.Sync.PeerClasses) > 0 {
310-
for _, pc := range drpolicy.Status.Sync.PeerClasses {
311-
cids = append(cids, pc.ClusterIDs...)
312-
}
313-
314-
return cids
315-
}
316-
317-
if len(drpolicy.Status.Async.PeerClasses) > 0 {
318-
for _, pc := range drpolicy.Status.Async.PeerClasses {
319-
cids = append(cids, pc.ClusterIDs...)
320-
}
321-
322-
return cids
323-
}
324-
325-
return cids
326-
}
327-
328-
func hasOverlapWithMetro(metroMap map[string][]string, commonClusterIDs, commonClusters []string) bool {
329-
for _, v := range metroMap {
330-
if sets.NewString(v...).HasAny(commonClusterIDs...) {
331-
return true
332-
}
333-
334-
if sets.NewString(v...).HasAny(commonClusters...) {
335-
return true
336-
}
337-
}
338-
339-
return false
340-
}
341-
342-
func haveOverlappingMetroZones(d1 *ramen.DRPolicy, d2 *ramen.DRPolicy, drclusters *ramen.DRClusterList) bool {
337+
func haveOverlappingMetroZones(
338+
d1, d2 *ramen.DRPolicy,
339+
drclusters *ramen.DRClusterList,
340+
drClusterIDsToNames map[string]string,
341+
) bool {
343342
d1ClusterNames := sets.NewString(util.DRPolicyClusterNames(d1)...)
344-
d1ClusterIDs := sets.NewString(getClusterIDSFromPolicy(d1)...)
345-
d1SupportsMetro, d1MetroMap := dRPolicySupportsMetro(d1, drclusters.Items)
346-
343+
d1SupportsMetro, d1MetroClusters := dRPolicySupportsMetro(d1, drclusters.Items, drClusterIDsToNames)
347344
d2ClusterNames := sets.NewString(util.DRPolicyClusterNames(d2)...)
348-
d2ClusterIDs := sets.NewString(getClusterIDSFromPolicy(d2)...)
349-
d2SupportsMetro, d2MetroMap := dRPolicySupportsMetro(d2, drclusters.Items)
350-
345+
d2SupportsMetro, d2MetroClusters := dRPolicySupportsMetro(d2, drclusters.Items, drClusterIDsToNames)
351346
commonClusters := d1ClusterNames.Intersection(d2ClusterNames)
352-
commonClusterIDs := d1ClusterIDs.Intersection(d2ClusterIDs)
353347

354348
// No common managed clusters, so we are good
355-
if commonClusterIDs.Len() == 0 && commonClusters.Len() == 0 {
349+
if commonClusters.Len() == 0 {
356350
return false
357351
}
358352

359353
// Lets check if the metro clusters in DRPolicy d2 belong to common managed clusters list
360354
if d2SupportsMetro {
361-
return hasOverlapWithMetro(d2MetroMap,
362-
commonClusterIDs.List(),
363-
commonClusters.List())
355+
for _, v := range d2MetroClusters {
356+
if sets.NewString(v...).HasAny(commonClusters.List()...) {
357+
return true
358+
}
359+
}
364360
}
365361

366362
// Lets check if the metro clusters in DRPolicy d1 belong to common managed clusters list
367363
if d1SupportsMetro {
368-
return hasOverlapWithMetro(d1MetroMap,
369-
commonClusterIDs.List(),
370-
commonClusters.List())
364+
for _, v := range d1MetroClusters {
365+
if sets.NewString(v...).HasAny(commonClusters.List()...) {
366+
return true
367+
}
368+
}
371369
}
372370

373371
return false
@@ -407,7 +405,7 @@ func (u *drpolicyUpdater) deleteDRPolicy(drclusters *ramen.DRClusterList,
407405
}
408406

409407
// proceed to delete metrics if non-metro-dr
410-
isMetro, _ := dRPolicySupportsMetro(u.object, drclusters.Items)
408+
isMetro, _ := dRPolicySupportsMetro(u.object, drclusters.Items, nil)
411409
if !isMetro {
412410
// delete metrics if matching labels are found
413411
metricLabels := DRPolicySyncIntervalMetricLabels(u.object)

0 commit comments

Comments
 (0)