Skip to content

Commit b61ae4c

Browse files
committed
Add project resource limit checks
1 parent 659ff9a commit b61ae4c

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

pkg/cloud/instance.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,35 @@ func (c *client) CheckDomainLimits(fd *infrav1.CloudStackFailureDomain, offering
257257
return nil
258258
}
259259

260+
// CheckProjectLimits Checks the project's limit of VM, CPU & Memory
261+
func (c *client) CheckProjectLimits(fd *infrav1.CloudStackFailureDomain, offering *cloudstack.ServiceOffering) error {
262+
if c.user.Project.ID == "" {
263+
return nil
264+
}
265+
266+
if c.user.Project.CPUAvailable != "Unlimited" {
267+
cpuAvailable, err := strconv.ParseInt(c.user.Project.CPUAvailable, 10, 0)
268+
if err == nil && int64(offering.Cpunumber) > cpuAvailable {
269+
return fmt.Errorf("CPU available (%d) in project can't fulfil the requirement: %d", cpuAvailable, offering.Cpunumber)
270+
}
271+
}
272+
273+
if c.user.Project.MemoryAvailable != "Unlimited" {
274+
memoryAvailable, err := strconv.ParseInt(c.user.Project.MemoryAvailable, 10, 0)
275+
if err == nil && int64(offering.Memory) > memoryAvailable {
276+
return fmt.Errorf("memory available (%d) in project can't fulfil the requirement: %d", memoryAvailable, offering.Memory)
277+
}
278+
}
279+
280+
if c.user.Project.VMAvailable != "Unlimited" {
281+
vmAvailable, err := strconv.ParseInt(c.user.Project.VMAvailable, 10, 0)
282+
if err == nil && vmAvailable < 1 {
283+
return fmt.Errorf("VM Limit in project has reached it's maximum value")
284+
}
285+
}
286+
return nil
287+
}
288+
260289
// CheckLimits will check the account & domain limits
261290
func (c *client) CheckLimits(
262291
fd *infrav1.CloudStackFailureDomain,
@@ -272,6 +301,11 @@ func (c *client) CheckLimits(
272301
return err
273302
}
274303

304+
err = c.CheckProjectLimits(fd, offering)
305+
if err != nil {
306+
return err
307+
}
308+
275309
return nil
276310
}
277311

pkg/cloud/instance_test.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ var _ = Describe("Instance", func() {
276276
MemoryAvailable: "2048",
277277
VMAvailable: "20",
278278
},
279+
Project: cloud.Project{
280+
ID: "123",
281+
CPUAvailable: "20",
282+
MemoryAvailable: "2048",
283+
VMAvailable: "20",
284+
},
279285
}
280286
c := cloud.NewClientFromCSAPIClient(mockClient, user)
281287
Ω(c.GetOrCreateVMInstance(
@@ -304,13 +310,53 @@ var _ = Describe("Instance", func() {
304310
MemoryAvailable: "2048",
305311
VMAvailable: "20",
306312
},
313+
Project: cloud.Project{
314+
ID: "123",
315+
CPUAvailable: "20",
316+
MemoryAvailable: "2048",
317+
VMAvailable: "20",
318+
},
307319
}
308320
c := cloud.NewClientFromCSAPIClient(mockClient, user)
309321
Ω(c.GetOrCreateVMInstance(
310322
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSFailureDomain1, dummies.CSAffinityGroup, "")).
311323
Should(MatchError(MatchRegexp("CPU available .* in domain can't fulfil the requirement:.*")))
312324
})
313325

326+
It("returns errors when there are not enough available CPU in project", func() {
327+
expectVMNotFound()
328+
dummies.CSMachine1.Spec.DiskOffering.CustomSize = 0
329+
sos.EXPECT().GetServiceOfferingByName(dummies.CSMachine1.Spec.Offering.Name, gomock.Any()).
330+
Return(&cloudstack.ServiceOffering{
331+
Id: dummies.CSMachine1.Spec.Offering.ID,
332+
Name: dummies.CSMachine1.Spec.Offering.Name,
333+
Cpunumber: 2,
334+
Memory: 1024,
335+
}, 1, nil)
336+
user := &cloud.User{
337+
Account: cloud.Account{
338+
Domain: cloud.Domain{
339+
CPUAvailable: "20",
340+
MemoryAvailable: "2048",
341+
VMAvailable: "20",
342+
},
343+
CPUAvailable: "20",
344+
MemoryAvailable: "2048",
345+
VMAvailable: "20",
346+
},
347+
Project: cloud.Project{
348+
ID: "123",
349+
CPUAvailable: "1",
350+
MemoryAvailable: "2048",
351+
VMAvailable: "20",
352+
},
353+
}
354+
c := cloud.NewClientFromCSAPIClient(mockClient, user)
355+
Ω(c.GetOrCreateVMInstance(
356+
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSFailureDomain1, dummies.CSAffinityGroup, "")).
357+
Should(MatchError(MatchRegexp("CPU available .* in project can't fulfil the requirement:.*")))
358+
})
359+
314360
It("returns errors when there is not enough available memory in account", func() {
315361
expectVMNotFound()
316362
dummies.CSMachine1.Spec.DiskOffering.CustomSize = 0
@@ -332,6 +378,12 @@ var _ = Describe("Instance", func() {
332378
MemoryAvailable: "512",
333379
VMAvailable: "20",
334380
},
381+
Project: cloud.Project{
382+
ID: "123",
383+
CPUAvailable: "20",
384+
MemoryAvailable: "2048",
385+
VMAvailable: "20",
386+
},
335387
}
336388
c := cloud.NewClientFromCSAPIClient(mockClient, user)
337389
Ω(c.GetOrCreateVMInstance(
@@ -360,13 +412,53 @@ var _ = Describe("Instance", func() {
360412
MemoryAvailable: "2048",
361413
VMAvailable: "20",
362414
},
415+
Project: cloud.Project{
416+
ID: "123",
417+
CPUAvailable: "20",
418+
MemoryAvailable: "2048",
419+
VMAvailable: "20",
420+
},
363421
}
364422
c := cloud.NewClientFromCSAPIClient(mockClient, user)
365423
Ω(c.GetOrCreateVMInstance(
366424
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSFailureDomain1, dummies.CSAffinityGroup, "")).
367425
Should(MatchError(MatchRegexp("memory available .* in domain can't fulfil the requirement:.*")))
368426
})
369427

428+
It("returns errors when there is not enough available memory in project", func() {
429+
expectVMNotFound()
430+
dummies.CSMachine1.Spec.DiskOffering.CustomSize = 0
431+
sos.EXPECT().GetServiceOfferingByName(dummies.CSMachine1.Spec.Offering.Name, gomock.Any()).
432+
Return(&cloudstack.ServiceOffering{
433+
Id: dummies.CSMachine1.Spec.Offering.ID,
434+
Name: dummies.CSMachine1.Spec.Offering.Name,
435+
Cpunumber: 2,
436+
Memory: 1024,
437+
}, 1, nil)
438+
user := &cloud.User{
439+
Account: cloud.Account{
440+
Domain: cloud.Domain{
441+
CPUAvailable: "20",
442+
MemoryAvailable: "2048",
443+
VMAvailable: "20",
444+
},
445+
CPUAvailable: "20",
446+
MemoryAvailable: "2048",
447+
VMAvailable: "20",
448+
},
449+
Project: cloud.Project{
450+
ID: "123",
451+
CPUAvailable: "20",
452+
MemoryAvailable: "512",
453+
VMAvailable: "20",
454+
},
455+
}
456+
c := cloud.NewClientFromCSAPIClient(mockClient, user)
457+
Ω(c.GetOrCreateVMInstance(
458+
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSFailureDomain1, dummies.CSAffinityGroup, "")).
459+
Should(MatchError(MatchRegexp("memory available .* in project can't fulfil the requirement:.*")))
460+
})
461+
370462
It("returns errors when there is not enough available VM limit in account", func() {
371463
expectVMNotFound()
372464
dummies.CSMachine1.Spec.DiskOffering.CustomSize = 0
@@ -388,6 +480,12 @@ var _ = Describe("Instance", func() {
388480
MemoryAvailable: "2048",
389481
VMAvailable: "0",
390482
},
483+
Project: cloud.Project{
484+
ID: "123",
485+
CPUAvailable: "20",
486+
MemoryAvailable: "2048",
487+
VMAvailable: "20",
488+
},
391489
}
392490
c := cloud.NewClientFromCSAPIClient(mockClient, user)
393491
Ω(c.GetOrCreateVMInstance(
@@ -416,12 +514,52 @@ var _ = Describe("Instance", func() {
416514
MemoryAvailable: "2048",
417515
VMAvailable: "10",
418516
},
517+
Project: cloud.Project{
518+
ID: "123",
519+
CPUAvailable: "20",
520+
MemoryAvailable: "2048",
521+
VMAvailable: "20",
522+
},
419523
}
420524
c := cloud.NewClientFromCSAPIClient(mockClient, user)
421525
Ω(c.GetOrCreateVMInstance(
422526
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSFailureDomain1, dummies.CSAffinityGroup, "")).
423527
Should(MatchError("VM Limit in domain has reached it's maximum value"))
424528
})
529+
530+
It("returns errors when there is not enough available VM limit in project", func() {
531+
expectVMNotFound()
532+
dummies.CSMachine1.Spec.DiskOffering.CustomSize = 0
533+
sos.EXPECT().GetServiceOfferingByName(dummies.CSMachine1.Spec.Offering.Name, gomock.Any()).
534+
Return(&cloudstack.ServiceOffering{
535+
Id: dummies.CSMachine1.Spec.Offering.ID,
536+
Name: dummies.CSMachine1.Spec.Offering.Name,
537+
Cpunumber: 2,
538+
Memory: 1024,
539+
}, 1, nil)
540+
user := &cloud.User{
541+
Account: cloud.Account{
542+
Domain: cloud.Domain{
543+
CPUAvailable: "20",
544+
MemoryAvailable: "2048",
545+
VMAvailable: "10",
546+
},
547+
CPUAvailable: "20",
548+
MemoryAvailable: "2048",
549+
VMAvailable: "10",
550+
},
551+
Project: cloud.Project{
552+
ID: "123",
553+
CPUAvailable: "20",
554+
MemoryAvailable: "2048",
555+
VMAvailable: "0",
556+
},
557+
}
558+
c := cloud.NewClientFromCSAPIClient(mockClient, user)
559+
Ω(c.GetOrCreateVMInstance(
560+
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSFailureDomain1, dummies.CSAffinityGroup, "")).
561+
Should(MatchError("VM Limit in project has reached it's maximum value"))
562+
})
425563
})
426564

427565
It("handles deployment errors", func() {

0 commit comments

Comments
 (0)