func (c *client) AllocateContainers(requests []executor.AllocationRequest) ([]executor.AllocationFailure, error) { c.resourcesLock.Lock() defer c.resourcesLock.Unlock() logger := c.logger.Session("allocate-containers") failures := make([]executor.AllocationFailure, 0) remainingResources, err := c.remainingResources(logger) if err != nil { return nil, executor.ErrFailureToCheckSpace } for i := range requests { req := &requests[i] err := req.Validate() if err != nil { logger.Error("invalid-request", err) failures = append(failures, executor.NewAllocationFailure(req, err.Error())) continue } ok := remainingResources.Subtract(&req.Resource) if !ok { logger.Error("failed-to-allocate-container", executor.ErrInsufficientResourcesAvailable, lager.Data{"guid": req.Guid}) failures = append(failures, executor.NewAllocationFailure(req, executor.ErrInsufficientResourcesAvailable.Error())) continue } _, err = c.allocationStore.Allocate(logger, req) if err != nil { logger.Error("failed-to-allocate-container", err, lager.Data{"guid": req.Guid}) failures = append(failures, executor.NewAllocationFailure(req, err.Error())) continue } } return failures, nil }
Context("when required memory is more than executor resource limits", func() { BeforeEach(func() { requests = []executor.AllocationRequest{ newAllocationRequest("guid-1", 512, defaultDiskMB), newAllocationRequest("guid-2", 512, defaultDiskMB), newAllocationRequest("guid-3", defaultMemoryMB, defaultDiskMB), } }) It("should allocate first few containers that can fit the available resources", func() { failures, err := depotClient.AllocateContainers(requests) Expect(err).NotTo(HaveOccurred()) Expect(failures).To(HaveLen(1)) expectedFailure := executor.NewAllocationFailure(&requests[2], executor.ErrInsufficientResourcesAvailable.Error()) Expect(failures[0]).To(BeEquivalentTo(expectedFailure)) allocatedContainers := allocationStore.List() Expect(allocatedContainers).To(HaveLen(len(requests) - 1)) allocatedContainersMap := convertSliceToMap(allocatedContainers) Expect(allocatedContainersMap).To(HaveLen(len(requests) - 1)) Expect(allocatedContainersMap["guid-1"].State).To(Equal(executor.StateReserved)) Expect(allocatedContainersMap["guid-2"].State).To(Equal(executor.StateReserved)) Expect(allocatedContainersMap).NotTo(HaveKey("guid-3")) }) }) Context("when required disk space is more than executor resource limits", func() { BeforeEach(func() {
Expect(err).NotTo(HaveOccurred()) Expect(failedWork).To(BeZero()) }) }) Context("when a container fails to be allocated", func() { BeforeEach(func() { resource := executor.NewResource(int(lrpAuctionOne.MemoryMB), int(lrpAuctionOne.DiskMB), "rootfs") tags := executor.Tags{} tags[rep.ProcessGuidTag] = lrpAuctionOne.ProcessGuid allocationRequest := executor.NewAllocationRequest( rep.LRPContainerGuid(lrpAuctionOne.ProcessGuid, expectedGuidOne), &resource, tags, ) allocationFailure := executor.NewAllocationFailure(&allocationRequest, commonErr.Error()) client.AllocateContainersReturns([]executor.AllocationFailure{allocationFailure}, nil) }) It("marks the corresponding LRP Auctions as failed", func() { failedWork, err := cellRep.Perform(rep.Work{LRPs: []rep.LRP{lrpAuctionOne, lrpAuctionTwo}}) Expect(err).NotTo(HaveOccurred()) Expect(failedWork.LRPs).To(ConsistOf(lrpAuctionOne)) }) }) }) Context("when an LRP Auction specifies a preloaded RootFSes for which it cannot determine a RootFS path", func() { BeforeEach(func() { lrpAuctionOne.RootFs = linuxRootFSURL lrpAuctionTwo.RootFs = "preloaded:not-on-cell"