Skip to content

Commit e85d94e

Browse files
committed
ProjectRequestLimit plugin: ignore projects in terminating state
1 parent 1054eb4 commit e85d94e

File tree

2 files changed

+82
-9
lines changed

2 files changed

+82
-9
lines changed

pkg/project/admission/requestlimit/admission.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import (
1818
projectcache "github.com/openshift/origin/pkg/project/cache"
1919
)
2020

21+
// allowedTerminatingProjects is the number of projects that are owned by a user, are in terminating state,
22+
// and do not count towards the user's limit.
23+
const allowedTerminatingProjects = 2
24+
2125
func init() {
2226
admission.RegisterPlugin("ProjectRequestLimit", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
2327
pluginConfig, err := readConfig(config)
@@ -116,7 +120,24 @@ func (o *projectRequestLimit) projectCountByRequester(userName string) (int, err
116120
if err != nil {
117121
return 0, err
118122
}
119-
return len(namespaces), nil
123+
124+
terminatingCount := 0
125+
for _, obj := range namespaces {
126+
ns, ok := obj.(*kapi.Namespace)
127+
if !ok {
128+
return 0, fmt.Errorf("object in cache is not a namespace: %#v", obj)
129+
}
130+
if ns.Status.Phase == kapi.NamespaceTerminating {
131+
terminatingCount++
132+
}
133+
}
134+
count := len(namespaces)
135+
if terminatingCount > allowedTerminatingProjects {
136+
count -= allowedTerminatingProjects
137+
} else {
138+
count -= terminatingCount
139+
}
140+
return count, nil
120141
}
121142

122143
func (o *projectRequestLimit) SetOpenshiftClient(client client.Interface) {

pkg/project/admission/requestlimit/admission_test.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,45 @@ func TestMaxProjectByRequester(t *testing.T) {
175175
}
176176
}
177177

178+
func TestProjectCountByRequester(t *testing.T) {
179+
pCache := fakeProjectCache(map[string]projectCount{
180+
"user1": {1, 5}, // total 6, expect 4
181+
"user2": {5, 1}, // total 6, expect 5
182+
"user3": {1, 0}, // total 1, expect 1
183+
})
184+
reqLimit := &projectRequestLimit{
185+
cache: pCache,
186+
}
187+
tests := []struct {
188+
user string
189+
expect int
190+
}{
191+
{
192+
user: "user1",
193+
expect: 4,
194+
},
195+
{
196+
user: "user2",
197+
expect: 5,
198+
},
199+
{
200+
user: "user3",
201+
expect: 1,
202+
},
203+
}
204+
205+
for _, test := range tests {
206+
actual, err := reqLimit.projectCountByRequester(test.user)
207+
if err != nil {
208+
t.Errorf("unexpected: %v", err)
209+
}
210+
if actual != test.expect {
211+
t.Errorf("user %s got %d, expected %d", test.user, actual, test.expect)
212+
}
213+
}
214+
215+
}
216+
178217
func TestAdmit(t *testing.T) {
179218
tests := []struct {
180219
config *requestlimitapi.ProjectRequestLimitConfig
@@ -219,10 +258,11 @@ func TestAdmit(t *testing.T) {
219258
}
220259

221260
for _, tc := range tests {
222-
pCache := fakeProjectCache(map[string]int{
223-
"user2": 2,
224-
"user3": 5,
225-
"user4": 1,
261+
pCache := fakeProjectCache(map[string]projectCount{
262+
"user1": {0, 1},
263+
"user2": {2, 2},
264+
"user3": {5, 3},
265+
"user4": {1, 0},
226266
})
227267
client := &testclient.Fake{}
228268
client.AddReactor("get", "users", userFn(map[string]labels.Set{
@@ -296,12 +336,15 @@ func configEquals(a, b *requestlimitapi.ProjectRequestLimitConfig) bool {
296336
return true
297337
}
298338

299-
func fakeNs(name string) *kapi.Namespace {
339+
func fakeNs(name string, terminating bool) *kapi.Namespace {
300340
ns := &kapi.Namespace{}
301341
ns.Name = kapi.SimpleNameGenerator.GenerateName("testns")
302342
ns.Annotations = map[string]string{
303343
"openshift.io/requester": name,
304344
}
345+
if terminating {
346+
ns.Status.Phase = kapi.NamespaceTerminating
347+
}
305348
return ns
306349
}
307350

@@ -312,12 +355,21 @@ func fakeUser(name string, labels map[string]string) *userapi.User {
312355
return user
313356
}
314357

315-
func fakeProjectCache(requesters map[string]int) *projectcache.ProjectCache {
358+
type projectCount struct {
359+
active int
360+
terminating int
361+
}
362+
363+
func fakeProjectCache(requesters map[string]projectCount) *projectcache.ProjectCache {
316364
kclient := &ktestclient.Fake{}
317365
pCache := projectcache.NewFake(kclient.Namespaces(), projectcache.NewCacheStore(cache.MetaNamespaceKeyFunc), "")
318366
for requester, count := range requesters {
319-
for i := 0; i < count; i++ {
320-
pCache.Store.Add(fakeNs(requester))
367+
for i := 0; i < count.active; i++ {
368+
pCache.Store.Add(fakeNs(requester, false))
369+
}
370+
// Add a number of terminating projects which should not affect counts
371+
for i := 0; i < count.terminating; i++ {
372+
pCache.Store.Add(fakeNs(requester, true))
321373
}
322374
}
323375
return pCache

0 commit comments

Comments
 (0)