Skip to content

Commit 0a4b4c6

Browse files
winterhazelDaan Hoogland
authored andcommitted
[20.3] Address limit checks for VM, CPU, memory, volume, and primary storage
1 parent 360b64c commit 0a4b4c6

27 files changed

Lines changed: 595 additions & 507 deletions

File tree

api/src/main/java/com/cloud/projects/ProjectService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public interface ProjectService {
8282

8383
Project updateProject(long id, String name, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
8484

85-
boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType);
85+
boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) throws ResourceAllocationException;
8686

8787
boolean deleteAccountFromProject(long projectId, String accountName);
8888

@@ -100,6 +100,6 @@ public interface ProjectService {
100100

101101
Project findByProjectAccountIdIncludingRemoved(long projectAccountId);
102102

103-
boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole);
103+
boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) throws ResourceAllocationException;
104104

105105
}

api/src/main/java/com/cloud/user/ResourceLimitService.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.cloud.offering.DiskOffering;
3131
import com.cloud.offering.ServiceOffering;
3232
import com.cloud.template.VirtualMachineTemplate;
33+
import org.apache.cloudstack.resourcelimit.Reserver;
3334

3435
public interface ResourceLimitService {
3536

@@ -246,12 +247,12 @@ public interface ResourceLimitService {
246247
List<String> getResourceLimitStorageTags(DiskOffering diskOffering);
247248
void updateTaggedResourceLimitsAndCountsForAccounts(List<AccountResponse> responses, String tag);
248249
void updateTaggedResourceLimitsAndCountsForDomains(List<DomainResponse> responses, String tag);
249-
void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException;
250+
void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException;
250251
List<String> getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering);
251252
void checkVolumeResourceLimitForDiskOfferingChange(Account owner, Boolean display, Long currentSize, Long newSize,
252-
DiskOffering currentOffering, DiskOffering newOffering) throws ResourceAllocationException;
253+
DiskOffering currentOffering, DiskOffering newOffering, List<Reserver> reservations) throws ResourceAllocationException;
253254

254-
void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException;
255+
void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException;
255256

256257
void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
257258
void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
@@ -268,20 +269,18 @@ void updateVolumeResourceCountForDiskOfferingChange(long accountId, Boolean disp
268269

269270
void incrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
270271
void decrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
271-
void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) throws ResourceAllocationException;
272+
void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException;
272273
void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
273274
void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
274275

275276
void checkVmResourceLimitsForServiceOfferingChange(Account owner, Boolean display, Long currentCpu, Long newCpu,
276-
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template) throws ResourceAllocationException;
277+
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException;
277278

278279
void checkVmResourceLimitsForTemplateChange(Account owner, Boolean display, ServiceOffering offering,
279-
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate) throws ResourceAllocationException;
280+
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate, List<Reserver> reservations) throws ResourceAllocationException;
280281

281-
void checkVmCpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu) throws ResourceAllocationException;
282282
void incrementVmCpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu);
283283
void decrementVmCpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu);
284-
void checkVmMemoryResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) throws ResourceAllocationException;
285284
void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
286285
void decrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
287286

api/src/main/java/org/apache/cloudstack/api/command/user/account/AddAccountToProjectCmd.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020

21+
import com.cloud.exception.ResourceAllocationException;
2122
import org.apache.cloudstack.api.ApiArgValidator;
2223
import org.apache.cloudstack.api.ApiCommandResourceType;
2324
import org.apache.cloudstack.api.BaseCmd;
@@ -106,7 +107,7 @@ public ProjectAccount.Role getRoleType() {
106107
/////////////////////////////////////////////////////
107108

108109
@Override
109-
public void execute() {
110+
public void execute() throws ResourceAllocationException {
110111
if (accountName == null && email == null) {
111112
throw new InvalidParameterValueException("Either accountName or email is required");
112113
}

api/src/main/java/org/apache/cloudstack/api/command/user/account/AddUserToProjectCmd.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.cloudstack.api.command.user.account;
1919

20+
import com.cloud.exception.ResourceAllocationException;
2021
import org.apache.cloudstack.acl.RoleType;
2122
import org.apache.cloudstack.api.APICommand;
2223
import org.apache.cloudstack.api.ApiArgValidator;
@@ -111,7 +112,7 @@ public String getEventDescription() {
111112
/////////////////////////////////////////////////////
112113

113114
@Override
114-
public void execute() {
115+
public void execute() throws ResourceAllocationException {
115116
validateInput();
116117
boolean result = _projectService.addUserToProject(getProjectId(), getUsername(), getEmail(), getProjectRoleId(), getRoleType());
117118
if (result) {

server/src/main/java/com/cloud/resourcelimit/Reserver.java renamed to api/src/main/java/org/apache/cloudstack/resourcelimit/Reserver.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
package com.cloud.resourcelimit;
18+
package org.apache.cloudstack.resourcelimit;
1919

20+
/**
21+
* Interface implemented by <code>CheckedReservation</code>.
22+
* </br></br>
23+
* This is defined in <code>cloud-api</code> to allow methods declared in modules that do not depend on <code>cloud-server</code>
24+
* to receive <code>CheckedReservations</code> as parameters.
25+
*/
2026
public interface Reserver extends AutoCloseable {
2127

2228
void close();

api/src/test/java/org/apache/cloudstack/api/command/test/AddAccountToProjectCmdTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.api.command.test;
1818

19+
import com.cloud.exception.ResourceAllocationException;
1920
import junit.framework.Assert;
2021
import junit.framework.TestCase;
2122

@@ -149,6 +150,8 @@ public void testExecuteForNullAccountNameEmail() {
149150
addAccountToProjectCmd.execute();
150151
} catch (InvalidParameterValueException exception) {
151152
Assert.assertEquals("Either accountName or email is required", exception.getLocalizedMessage());
153+
} catch (ResourceAllocationException exception) {
154+
Assert.fail();
152155
}
153156

154157
}

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4757,9 +4757,20 @@ private void removeCustomOfferingDetails(long vmId) {
47574757

47584758
private void saveCustomOfferingDetails(long vmId, ServiceOffering serviceOffering) {
47594759
Map<String, String> details = userVmDetailsDao.listDetailsKeyPairs(vmId);
4760-
details.put(UsageEventVO.DynamicParameters.cpuNumber.name(), serviceOffering.getCpu().toString());
4761-
details.put(UsageEventVO.DynamicParameters.cpuSpeed.name(), serviceOffering.getSpeed().toString());
4762-
details.put(UsageEventVO.DynamicParameters.memory.name(), serviceOffering.getRamSize().toString());
4760+
4761+
// We need to restore only the customizable parameters. If we save a parameter that is not customizable and attempt
4762+
// to restore a VM snapshot, com.cloud.vm.UserVmManagerImpl.validateCustomParameters will fail.
4763+
ServiceOffering unfilledOffering = _serviceOfferingDao.findByIdIncludingRemoved(serviceOffering.getId());
4764+
if (unfilledOffering.getCpu() == null) {
4765+
details.put(UsageEventVO.DynamicParameters.cpuNumber.name(), serviceOffering.getCpu().toString());
4766+
}
4767+
if (unfilledOffering.getSpeed() == null) {
4768+
details.put(UsageEventVO.DynamicParameters.cpuSpeed.name(), serviceOffering.getSpeed().toString());
4769+
}
4770+
if (unfilledOffering.getRamSize() == null) {
4771+
details.put(UsageEventVO.DynamicParameters.memory.name(), serviceOffering.getRamSize().toString());
4772+
}
4773+
47634774
List<UserVmDetailVO> detailList = new ArrayList<>();
47644775
for (Map.Entry<String, String> entry: details.entrySet()) {
47654776
UserVmDetailVO detailVO = new UserVmDetailVO(vmId, entry.getKey(), entry.getValue(), true);

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,9 +3097,6 @@ public Network doInTransaction(final TransactionStatus status) {
30973097
CallContext.current().setEventDetails("Network Id: " + network.getId());
30983098
CallContext.current().putContextParameter(Network.class, network.getUuid());
30993099
return network;
3100-
} catch (Exception e) {
3101-
logger.error(e);
3102-
throw new RuntimeException(e);
31033100
}
31043101
}
31053102

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import javax.naming.ConfigurationException;
4040

4141
import com.cloud.exception.ResourceAllocationException;
42+
import com.cloud.resourcelimit.ReservationHelper;
4243
import com.cloud.storage.DiskOfferingVO;
4344
import com.cloud.storage.VMTemplateVO;
4445
import com.cloud.storage.dao.VMTemplateDao;
@@ -77,6 +78,7 @@
7778
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
7879
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
7980
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
81+
import org.apache.cloudstack.resourcelimit.Reserver;
8082
import org.apache.cloudstack.secret.PassphraseVO;
8183
import org.apache.cloudstack.secret.dao.PassphraseDao;
8284
import org.apache.cloudstack.snapshot.SnapshotHelper;
@@ -1867,24 +1869,32 @@ protected void updateVolumeSize(DataStore store, VolumeVO vol) throws ResourceAl
18671869
template == null ? null : template.getSize(),
18681870
vol.getPassphraseId() != null);
18691871

1870-
if (newSize != vol.getSize()) {
1871-
DiskOfferingVO diskOffering = diskOfferingDao.findByIdIncludingRemoved(vol.getDiskOfferingId());
1872+
if (newSize == vol.getSize()) {
1873+
return;
1874+
}
1875+
1876+
DiskOfferingVO diskOffering = diskOfferingDao.findByIdIncludingRemoved(vol.getDiskOfferingId());
1877+
1878+
List<Reserver> reservations = new ArrayList<>();
1879+
try {
18721880
VMInstanceVO vm = vol.getInstanceId() != null ? vmInstanceDao.findById(vol.getInstanceId()) : null;
18731881
if (vm == null || vm.getType() == VirtualMachine.Type.User) {
18741882
// Update resource count for user vm volumes when volume is attached
18751883
if (newSize > vol.getSize()) {
18761884
_resourceLimitMgr.checkPrimaryStorageResourceLimit(_accountMgr.getActiveAccountById(vol.getAccountId()),
1877-
vol.isDisplay(), newSize - vol.getSize(), diskOffering);
1885+
vol.isDisplay(), newSize - vol.getSize(), diskOffering, reservations);
18781886
_resourceLimitMgr.incrementVolumePrimaryStorageResourceCount(vol.getAccountId(), vol.isDisplay(),
18791887
newSize - vol.getSize(), diskOffering);
18801888
} else {
18811889
_resourceLimitMgr.decrementVolumePrimaryStorageResourceCount(vol.getAccountId(), vol.isDisplay(),
18821890
vol.getSize() - newSize, diskOffering);
18831891
}
18841892
}
1885-
vol.setSize(newSize);
1886-
_volsDao.persist(vol);
1893+
} finally {
1894+
ReservationHelper.closeAll(reservations);
18871895
}
1896+
vol.setSize(newSize);
1897+
_volsDao.persist(vol);
18881898
}
18891899

18901900
@Override

server/src/main/java/com/cloud/projects/ProjectManagerImpl.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ public ProjectVO findByProjectAccountIdIncludingRemoved(long projectAccountId) {
544544

545545
@Override
546546
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_USER_ADD, eventDescription = "adding user to project", async = true)
547-
public boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) {
547+
public boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) throws ResourceAllocationException {
548548
Account caller = CallContext.current().getCallingAccount();
549549

550550
Project project = getProject(projectId);
@@ -614,8 +614,6 @@ public boolean addUserToProject(Long projectId, String username, String email, L
614614
logger.warn("Failed to add user to project: {}", project);
615615
return false;
616616
}
617-
} catch (ResourceAllocationException e) {
618-
throw new RuntimeException(e);
619617
}
620618
}
621619
}
@@ -814,7 +812,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Resour
814812

815813
@Override
816814
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACCOUNT_ADD, eventDescription = "adding account to project", async = true)
817-
public boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) {
815+
public boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) throws ResourceAllocationException {
818816
Account caller = CallContext.current().getCallingAccount();
819817

820818
//check that the project exists
@@ -892,8 +890,6 @@ public boolean addAccountToProject(long projectId, String accountName, String em
892890
logger.warn("Failed to add account {} to project {}", accountName, project);
893891
return false;
894892
}
895-
} catch (ResourceAllocationException e) {
896-
throw new RuntimeException(e);
897893
}
898894
}
899895
}

0 commit comments

Comments
 (0)