Skip to content

Commit e4f106a

Browse files
committed
fix: concurrent map writes when replicating namespaced objects
Signed-off-by: Dario Tranchitella <[email protected]>
1 parent 1d53811 commit e4f106a

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

controllers/resources/processor.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func (r *Processor) HandlePruning(ctx context.Context, current, desired sets.Set
7979
return updateStatus
8080
}
8181

82+
//nolint:gocognit
8283
func (r *Processor) HandleSection(ctx context.Context, tnt capsulev1beta2.Tenant, allowCrossNamespaceSelection bool, tenantLabel string, resourceIndex int, spec capsulev1beta2.ResourceSpec) ([]string, error) {
8384
log := ctrllog.FromContext(ctx)
8485

@@ -125,7 +126,6 @@ func (r *Processor) HandleSection(ctx context.Context, tnt capsulev1beta2.Tenant
125126

126127
objLabels[Label] = fmt.Sprintf("%d", resourceIndex)
127128
objLabels[tenantLabel] = tnt.GetName()
128-
129129
// processed will contain the sets of resources replicated, both for the raw and the Namespaced ones:
130130
// these are required to perform a final pruning once the replication has been occurred.
131131
processed := sets.NewString()
@@ -173,17 +173,20 @@ func (r *Processor) HandleSection(ctx context.Context, tnt capsulev1beta2.Tenant
173173
var wg sync.WaitGroup
174174

175175
errorsChan := make(chan error, len(objs.Items))
176-
176+
// processedRaw is used to avoid concurrent map writes during iteration of namespaced items:
177+
// the objects will be then added to processed variable if the resulting string is not empty,
178+
// meaning it has been processed correctly.
179+
processedRaw := make([]string, len(objs.Items))
177180
// Iterating over all the retrieved objects from the resource spec to get replicated in all the selected Namespaces:
178181
// in case of error during the create or update function, this will be appended to the list of errors.
179-
for _, o := range objs.Items {
182+
for i, o := range objs.Items {
180183
obj := o
181184
obj.SetNamespace(ns.Name)
182185
obj.SetOwnerReferences(nil)
183186

184187
wg.Add(1)
185188

186-
go func(obj unstructured.Unstructured) {
189+
go func(index int, obj unstructured.Unstructured) {
187190
defer wg.Done()
188191

189192
kv := keysAndValues
@@ -204,8 +207,8 @@ func (r *Processor) HandleSection(ctx context.Context, tnt capsulev1beta2.Tenant
204207
replicatedItem.Namespace = ns.Name
205208
replicatedItem.APIVersion = obj.GetAPIVersion()
206209

207-
processed.Insert(replicatedItem.String())
208-
}(obj)
210+
processedRaw[index] = replicatedItem.String()
211+
}(i, obj)
209212
}
210213

211214
wg.Wait()
@@ -216,6 +219,14 @@ func (r *Processor) HandleSection(ctx context.Context, tnt capsulev1beta2.Tenant
216219
syncErr = errors.Join(syncErr, err)
217220
}
218221
}
222+
223+
for _, p := range processedRaw {
224+
if p == "" {
225+
continue
226+
}
227+
228+
processed.Insert(p)
229+
}
219230
}
220231

221232
for rawIndex, item := range spec.RawItems {

0 commit comments

Comments
 (0)