Skip to content

Commit 890cb2f

Browse files
committed
Reconcile deleted namespaces out of cluster quota status
1 parent 1023112 commit 890cb2f

File tree

4 files changed

+44
-8
lines changed

4 files changed

+44
-8
lines changed

pkg/quota/controller/clusterquotamapping/mapper.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,13 @@ func (m *clusterQuotaMapper) removeQuota(quotaName string) {
133133
delete(m.requiredQuotaToSelector, quotaName)
134134
delete(m.completedQuotaToSelector, quotaName)
135135
delete(m.quotaToNamespaces, quotaName)
136-
for _, quotas := range m.namespaceToQuota {
137-
quotas.Delete(quotaName)
136+
for namespaceName, quotas := range m.namespaceToQuota {
137+
if quotas.Has(quotaName) {
138+
quotas.Delete(quotaName)
139+
for _, listener := range m.listeners {
140+
listener.RemoveMapping(quotaName, namespaceName)
141+
}
142+
}
138143
}
139144
}
140145

@@ -176,8 +181,13 @@ func (m *clusterQuotaMapper) removeNamespace(namespaceName string) {
176181
delete(m.requiredNamespaceToLabels, namespaceName)
177182
delete(m.completedNamespaceToLabels, namespaceName)
178183
delete(m.namespaceToQuota, namespaceName)
179-
for _, namespaces := range m.quotaToNamespaces {
180-
namespaces.Delete(namespaceName)
184+
for quotaName, namespaces := range m.quotaToNamespaces {
185+
if namespaces.Has(namespaceName) {
186+
namespaces.Delete(namespaceName)
187+
for _, listener := range m.listeners {
188+
listener.RemoveMapping(quotaName, namespaceName)
189+
}
190+
}
181191
}
182192
}
183193

pkg/quota/controller/clusterquotareconciliation/reconciliation_controller.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,19 @@ func (c *ClusterQuotaReconcilationController) calculateAll() {
179179
}
180180

181181
for _, quota := range quotas {
182+
// If we have namespaces we map to, force calculating those namespaces
182183
namespaces, _ := c.clusterQuotaMapper.GetNamespacesFor(quota.Name)
183-
c.forceCalculation(quota.Name, namespaces...)
184+
if len(namespaces) > 0 {
185+
c.forceCalculation(quota.Name, namespaces...)
186+
continue
187+
}
188+
189+
// If the quota status has namespaces when our mapper doesn't think it should,
190+
// add it directly to the queue without any work items
191+
if quota.Status.Namespaces.OrderedKeys().Front() != nil {
192+
c.queue.AddWithData(quota.Name)
193+
continue
194+
}
184195
}
185196
}
186197

@@ -285,6 +296,17 @@ func (c *ClusterQuotaReconcilationController) syncQuotaForNamespaces(originalQuo
285296
quota.Status.Namespaces.Insert(namespaceName, recalculatedStatus)
286297
}
287298

299+
// Remove any namespaces from quota.status that no longer match.
300+
// Needed because we will never get workitems for namespaces that no longer exist if we missed the delete event (e.g. on startup)
301+
for e := quota.Status.Namespaces.OrderedKeys().Front(); e != nil; e = e.Next() {
302+
namespaceName := e.Value.(string)
303+
namespaceTotals, _ := quota.Status.Namespaces.Get(namespaceName)
304+
if !matchingNamespaceNames.Has(namespaceName) {
305+
quota.Status.Total.Used = utilquota.Subtract(quota.Status.Total.Used, namespaceTotals.Used)
306+
quota.Status.Namespaces.Remove(namespaceName)
307+
}
308+
}
309+
288310
quota.Status.Total.Hard = quota.Spec.Quota.Hard
289311

290312
// if there's no change, no update, return early. NewAggregate returns nil on empty input

pkg/quota/controller/clusterquotareconciliation/reconciliation_controller_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func TestSyncFunc(t *testing.T) {
161161
expectedRetries: []workItem{},
162162
},
163163
{
164-
name: "update one, remove two, ignore three, fail four",
164+
name: "update one, remove two, ignore three, fail four, remove deleted",
165165
startingQuota: func() *quotaapi.ClusterResourceQuota {
166166
ret := defaultQuota()
167167
ret.Status.Total.Hard = ret.Spec.Quota.Hard
@@ -178,6 +178,10 @@ func TestSyncFunc(t *testing.T) {
178178
Hard: ret.Spec.Quota.Hard,
179179
Used: kapi.ResourceList{kapi.ResourcePods: resource.MustParse("15")},
180180
})
181+
ret.Status.Namespaces.Insert("deleted", kapi.ResourceQuotaStatus{
182+
Hard: ret.Spec.Quota.Hard,
183+
Used: kapi.ResourceList{kapi.ResourcePods: resource.MustParse("0")},
184+
})
181185
return ret
182186
},
183187
workItems: []workItem{

test/cmd/quota.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ os::cmd::expect_success 'oc new-project asmail [email protected]'
2929
os::cmd::try_until_text 'oc get appliedclusterresourcequota -n bar --as deads -o name' "for-deads-by-annotation"
3030
os::cmd::try_until_text 'oc get appliedclusterresourcequota -n foo --as deads -o name' "for-deads-by-annotation"
3131
os::cmd::try_until_text 'oc get appliedclusterresourcequota -n asmail --as [email protected] -o name' "for-deads-email-by-annotation"
32-
os::cmd::try_until_text 'oc describe appliedclusterresourcequota/for-deads-by-annotation -n bar --as deads' "secrets.*[1-4][0-9]"
33-
32+
os::cmd::try_until_text 'oc describe appliedclusterresourcequota/for-deads-by-annotation -n bar --as deads' "secrets.*1[0-9]"
3433
os::cmd::expect_success 'oc delete project foo'
34+
os::cmd::try_until_text 'oc get clusterresourcequota/for-deads-by-annotation -o jsonpath="{.status.namespaces[*].Namespace}"' '^bar$'
3535
os::cmd::expect_success 'oc delete project bar'
3636
os::cmd::expect_success 'oc delete project asmail'
3737

0 commit comments

Comments
 (0)