Skip to content

Commit 5a496e7

Browse files
committed
Merge remote-tracking branch 'apache/4.19'
2 parents 7692b74 + 48e745c commit 5a496e7

11 files changed

Lines changed: 109 additions & 35 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public String getEventType() {
103103

104104
@Override
105105
public String getEventDescription() {
106-
return "Adding user "+getUsername()+" to Project "+getProjectId();
106+
return "Adding user " + getUsername() + " to project: " + getProjectId();
107107
}
108108

109109
/////////////////////////////////////////////////////

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ public String getEventDescription() {
8181
return "Removing user " + userId + " from project: " + projectId;
8282
}
8383

84-
8584
@Override
8685
public long getEntityOwnerId() {
8786
Project project = _projectService.getProject(projectId);

framework/security/src/main/java/org/apache/cloudstack/framework/security/keystore/KeystoreManager.java

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

1919
import com.cloud.agent.api.LogLevel;
2020
import com.cloud.agent.api.LogLevel.Log4jLevel;
21+
import com.cloud.utils.Pair;
2122
import com.cloud.utils.component.Manager;
2223

2324
public interface KeystoreManager extends Manager {
@@ -59,7 +60,7 @@ public String getRootCACert() {
5960
}
6061
}
6162

62-
boolean validateCertificate(String certificate, String key, String domainSuffix);
63+
Pair<Boolean, String> validateCertificate(String certificate, String key, String domainSuffix);
6364

6465
void saveCertificate(String name, String certificate, String key, String domainSuffix);
6566

framework/security/src/main/java/org/apache/cloudstack/framework/security/keystore/KeystoreManagerImpl.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import javax.inject.Inject;
3232

33+
import com.cloud.utils.Pair;
3334
import org.apache.commons.lang3.StringUtils;
3435
import org.springframework.stereotype.Component;
3536

@@ -45,24 +46,28 @@ public class KeystoreManagerImpl extends ManagerBase implements KeystoreManager
4546
private KeystoreDao _ksDao;
4647

4748
@Override
48-
public boolean validateCertificate(String certificate, String key, String domainSuffix) {
49+
public Pair<Boolean, String> validateCertificate(String certificate, String key, String domainSuffix) {
50+
String errMsg = null;
4951
if (StringUtils.isAnyEmpty(certificate, key, domainSuffix)) {
50-
logger.error("Invalid parameter found in (certificate, key, domainSuffix) tuple for domain: " + domainSuffix);
51-
return false;
52+
errMsg = String.format("Invalid parameter found in (certificate, key, domainSuffix) tuple for domain: %s", domainSuffix);
53+
logger.error(errMsg);
54+
return new Pair<>(false, errMsg);
5255
}
5356

5457
try {
5558
String ksPassword = "passwordForValidation";
5659
byte[] ksBits = CertificateHelper.buildAndSaveKeystore(domainSuffix, certificate, getKeyContent(key), ksPassword);
5760
KeyStore ks = CertificateHelper.loadKeystore(ksBits, ksPassword);
58-
if (ks != null)
59-
return true;
60-
61-
logger.error("Unabled to construct keystore for domain: " + domainSuffix);
61+
if (ks != null) {
62+
return new Pair<>(true, errMsg);
63+
}
64+
errMsg = String.format("Unable to construct keystore for domain: %s", domainSuffix);
65+
logger.error(errMsg);
6266
} catch (Exception e) {
63-
logger.error("Certificate validation failed due to exception for domain: " + domainSuffix, e);
67+
errMsg = String.format("Certificate validation failed due to exception for domain: %s", domainSuffix);
68+
logger.error(errMsg, e);
6469
}
65-
return false;
70+
return new Pair<>(false, errMsg);
6671
}
6772

6873
@Override

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import com.vmware.vim25.FolderFileInfo;
5656
import com.vmware.vim25.HostDatastoreBrowserSearchResults;
5757
import com.vmware.vim25.HostDatastoreBrowserSearchSpec;
58+
import com.vmware.vim25.VirtualCdromIsoBackingInfo;
5859
import com.vmware.vim25.VirtualMachineConfigSummary;
5960
import org.apache.cloudstack.api.ApiConstants;
6061
import org.apache.cloudstack.backup.PrepareForBackupRestorationCommand;
@@ -2737,8 +2738,9 @@ private boolean multipleIsosAtached(DiskTO[] sortedDisks) {
27372738

27382739
private DiskTO[] getDisks(DiskTO[] sortedDisks) {
27392740
return Arrays.stream(sortedDisks).filter(vol -> ((vol.getPath() != null &&
2740-
vol.getPath().contains("configdrive"))) || (vol.getType() != Volume.Type.ISO)).toArray(DiskTO[]::new);
2741+
vol.getPath().contains(ConfigDrive.CONFIGDRIVEDIR))) || (vol.getType() != Volume.Type.ISO)).toArray(DiskTO[]::new);
27412742
}
2743+
27422744
private void configureIso(VmwareHypervisorHost hyperHost, VirtualMachineMO vmMo, DiskTO vol,
27432745
VirtualDeviceConfigSpec[] deviceConfigSpecArray, int ideUnitNumber, int i) throws Exception {
27442746
TemplateObjectTO iso = (TemplateObjectTO) vol.getData();
@@ -4447,6 +4449,8 @@ protected Answer execute(StopCommand cmd) {
44474449
msg = "Have problem in powering off VM " + cmd.getVmName() + ", let the process continue";
44484450
logger.warn(msg);
44494451
}
4452+
4453+
disconnectConfigDriveIsoIfExists(vmMo);
44504454
return new StopAnswer(cmd, msg, true);
44514455
}
44524456

@@ -4465,6 +4469,30 @@ protected Answer execute(StopCommand cmd) {
44654469
}
44664470
}
44674471

4472+
private void disconnectConfigDriveIsoIfExists(VirtualMachineMO vmMo) {
4473+
try {
4474+
List<VirtualDevice> isoDevices = vmMo.getIsoDevices();
4475+
if (CollectionUtils.isEmpty(isoDevices)) {
4476+
return;
4477+
}
4478+
4479+
for (VirtualDevice isoDevice : isoDevices) {
4480+
if (!(isoDevice.getBacking() instanceof VirtualCdromIsoBackingInfo)) {
4481+
continue;
4482+
}
4483+
String isoFilePath = ((VirtualCdromIsoBackingInfo)isoDevice.getBacking()).getFileName();
4484+
if (!isoFilePath.contains(ConfigDrive.CONFIGDRIVEDIR)) {
4485+
continue;
4486+
}
4487+
logger.info(String.format("Disconnecting config drive at location: %s", isoFilePath));
4488+
vmMo.detachIso(isoFilePath, true);
4489+
return;
4490+
}
4491+
} catch (Exception e) {
4492+
logger.warn(String.format("Couldn't check/disconnect config drive, error: %s", e.getMessage()), e);
4493+
}
4494+
}
4495+
44684496
protected Answer execute(RebootRouterCommand cmd) {
44694497
RebootAnswer answer = (RebootAnswer) execute((RebootCommand) cmd);
44704498

server/src/main/java/com/cloud/event/ActionEventInterceptor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,13 @@ public void interceptComplete(Method method, Object target, Object event) {
8888
for (ActionEvent actionEvent : getActionEvents(method)) {
8989
CallContext ctx = CallContext.current();
9090
long userId = ctx.getCallingUserId();
91-
long accountId = ctx.getProject() != null ? ctx.getProject().getProjectAccountId() : ctx.getCallingAccountId(); //This should be the entity owner id rather than the Calling User Account Id.
9291
long startEventId = ctx.getStartEventId();
9392
String eventDescription = getEventDescription(actionEvent, ctx);
9493
Long eventResourceId = getEventResourceId(actionEvent, ctx);
9594
String eventResourceType = getEventResourceType(actionEvent, ctx);
9695
String eventType = getEventType(actionEvent, ctx);
9796
boolean isEventDisplayEnabled = ctx.isEventDisplayEnabled();
97+
long accountId = ActionEventUtils.getOwnerAccountId(ctx, eventType, ctx.getCallingAccountId());
9898

9999
if (eventType.equals(""))
100100
return;
@@ -118,13 +118,13 @@ public void interceptException(Method method, Object target, Object event) {
118118
for (ActionEvent actionEvent : getActionEvents(method)) {
119119
CallContext ctx = CallContext.current();
120120
long userId = ctx.getCallingUserId();
121-
long accountId = ctx.getCallingAccountId();
122121
long startEventId = ctx.getStartEventId();
123122
String eventDescription = getEventDescription(actionEvent, ctx);
124123
Long eventResourceId = getEventResourceId(actionEvent, ctx);
125124
String eventResourceType = getEventResourceType(actionEvent, ctx);
126125
String eventType = getEventType(actionEvent, ctx);
127126
boolean isEventDisplayEnabled = ctx.isEventDisplayEnabled();
127+
long accountId = ActionEventUtils.getOwnerAccountId(ctx, eventType, ctx.getCallingAccountId());
128128

129129
if (eventType.equals(""))
130130
return;

server/src/main/java/com/cloud/event/ActionEventUtils.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.text.SimpleDateFormat;
2323
import java.util.Date;
2424
import java.util.HashMap;
25+
import java.util.List;
2526
import java.util.Map;
2627

2728
import javax.annotation.PostConstruct;
@@ -112,6 +113,8 @@ public static Long onActionEvent(Long userId, Long accountId, Long domainId, Str
112113
*/
113114
public static Long onScheduledActionEvent(Long userId, Long accountId, String type, String description, Long resourceId, String resourceType, boolean eventDisplayEnabled, long startEventId) {
114115
Ternary<Long, String, String> resourceDetails = getResourceDetails(resourceId, resourceType, type);
116+
CallContext ctx = CallContext.current();
117+
accountId = getOwnerAccountId(ctx, type, accountId);
115118
Event event = persistActionEvent(userId, accountId, null, null, type, Event.State.Scheduled,
116119
eventDisplayEnabled, description, resourceDetails.first(), resourceDetails.third(), startEventId);
117120
publishOnEventBus(event, userId, accountId, EventCategory.ACTION_EVENT.getName(), type,
@@ -127,7 +130,7 @@ public static void startNestedActionEvent(String eventType, String eventDescript
127130
public static void onStartedActionEventFromContext(String eventType, String eventDescription, Long resourceId, String resourceType, boolean eventDisplayEnabled) {
128131
CallContext ctx = CallContext.current();
129132
long userId = ctx.getCallingUserId();
130-
long accountId = ctx.getProject() != null ? ctx.getProject().getProjectAccountId() : ctx.getCallingAccountId(); //This should be the entity owner id rather than the Calling User Account Id.
133+
long accountId = getOwnerAccountId(ctx, eventType, ctx.getCallingAccountId());
131134
long startEventId = ctx.getStartEventId();
132135

133136
if (!eventType.equals(""))
@@ -413,7 +416,11 @@ private static void populateFirstClassEntities(Map<String, String> eventDescript
413416
LOGGER.trace("Caught exception while populating first class entities for event bus, moving on");
414417
}
415418
}
416-
417419
}
418420

421+
public static long getOwnerAccountId(CallContext ctx, String eventType, long callingAccountId) {
422+
List<String> mainProjectEvents = List.of(EventTypes.EVENT_PROJECT_CREATE, EventTypes.EVENT_PROJECT_UPDATE, EventTypes.EVENT_PROJECT_DELETE);
423+
long accountId = ctx.getProject() != null && !mainProjectEvents.stream().anyMatch(eventType::equalsIgnoreCase) ? ctx.getProject().getProjectAccountId() : callingAccountId; //This should be the entity owner id rather than the Calling User Account Id.
424+
return accountId;
425+
}
419426
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,16 +293,16 @@ public Project doInTransaction(TransactionStatus status) {
293293
assignAccountToProject(project, ownerFinal.getId(), ProjectAccount.Role.Admin,
294294
Optional.ofNullable(finalUser).map(User::getId).orElse(null), null);
295295

296-
if (project != null) {
297-
CallContext.current().setEventDetails("Project id=" + project.getId());
298-
CallContext.current().putContextParameter(Project.class, project.getUuid());
299-
}
296+
if (project != null) {
297+
CallContext.current().setEventDetails("Project id=" + project.getId());
298+
CallContext.current().putContextParameter(Project.class, project.getUuid());
299+
}
300300

301-
//Increment resource count
301+
//Increment resource count
302302
_resourceLimitMgr.incrementResourceCount(ownerFinal.getId(), ResourceType.project);
303303

304-
return project;
305-
}
304+
return project;
305+
}
306306
});
307307

308308
messageBus.publish(_name, ProjectManager.MESSAGE_CREATE_TUNGSTEN_PROJECT_EVENT, PublishScope.LOCAL, project);
@@ -1290,7 +1290,7 @@ public List<Long> listPermittedProjectAccounts(long accountId) {
12901290
}
12911291

12921292
@Override
1293-
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACTIVATE, eventDescription = "activating project")
1293+
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACTIVATE, eventDescription = "activating project", async = true)
12941294
@DB
12951295
public Project activateProject(final long projectId) {
12961296
Account caller = CallContext.current().getCallingAccount();

server/src/main/java/com/cloud/server/ManagementServerImpl.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.cloud.server;
1818

1919
import java.lang.reflect.Field;
20+
import java.security.cert.CertificateException;
2021
import java.util.ArrayList;
2122
import java.util.Arrays;
2223
import java.util.Calendar;
@@ -43,6 +44,7 @@
4344
import javax.inject.Inject;
4445
import javax.naming.ConfigurationException;
4546

47+
import com.cloud.utils.security.CertificateHelper;
4648
import org.apache.cloudstack.acl.ControlledEntity;
4749
import org.apache.cloudstack.acl.SecurityChecker;
4850
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
@@ -4572,13 +4574,12 @@ public String uploadCertificate(final UploadCustomCertificateCmd cmd) {
45724574

45734575
final String certificate = cmd.getCertificate();
45744576
final String key = cmd.getPrivateKey();
4577+
String domainSuffix = cmd.getDomainSuffix();
45754578

4576-
if (cmd.getPrivateKey() != null && !_ksMgr.validateCertificate(certificate, key, cmd.getDomainSuffix())) {
4577-
throw new InvalidParameterValueException("Failed to pass certificate validation check");
4578-
}
4579+
validateCertificate(certificate, key, domainSuffix);
45794580

45804581
if (cmd.getPrivateKey() != null) {
4581-
_ksMgr.saveCertificate(ConsoleProxyManager.CERTIFICATE_NAME, certificate, key, cmd.getDomainSuffix());
4582+
_ksMgr.saveCertificate(ConsoleProxyManager.CERTIFICATE_NAME, certificate, key, domainSuffix);
45824583

45834584
// Reboot ssvm here since private key is present - meaning server cert being passed
45844585
final List<SecondaryStorageVmVO> alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(null, State.Running, State.Migrating, State.Starting);
@@ -4595,6 +4596,24 @@ public String uploadCertificate(final UploadCustomCertificateCmd cmd) {
45954596
+ "please give a few minutes for console access and storage services service to be up and working again";
45964597
}
45974598

4599+
private void validateCertificate(String certificate, String key, String domainSuffix) {
4600+
if (key != null) {
4601+
Pair<Boolean, String> result = _ksMgr.validateCertificate(certificate, key, domainSuffix);
4602+
if (!result.first()) {
4603+
throw new InvalidParameterValueException(String.format("Failed to pass certificate validation check with error: %s", result.second()));
4604+
}
4605+
} else {
4606+
try {
4607+
logger.debug(String.format("Trying to validate the root certificate format"));
4608+
CertificateHelper.buildCertificate(certificate);
4609+
} catch (CertificateException e) {
4610+
String errorMsg = String.format("Failed to pass certificate validation check with error: Certificate validation failed due to exception: %s", e.getMessage());
4611+
logger.error(errorMsg);
4612+
throw new InvalidParameterValueException(errorMsg);
4613+
}
4614+
}
4615+
}
4616+
45984617
@Override
45994618
public List<String> getHypervisors(final Long zoneId) {
46004619
final List<String> result = new ArrayList<>();

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4776,17 +4776,24 @@ private void updateVMDiskController(UserVmVO vm, Map<String, String> customParam
47764776
vm.setDetail(VmDetailConstants.DATA_DISK_CONTROLLER, dataDiskControllerSetting);
47774777
}
47784778

4779-
String controllerSetting = StringUtils.defaultIfEmpty(_configDao.getValue(Config.VmwareRootDiskControllerType.key()),
4780-
Config.VmwareRootDiskControllerType.getDefaultValue());
4781-
47824779
// Don't override if VM already has root/data disk controller detail
47834780
if (vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER) == null) {
4784-
vm.setDetail(VmDetailConstants.ROOT_DISK_CONTROLLER, controllerSetting);
4781+
String vmwareRootDiskControllerTypeFromSetting = StringUtils.defaultIfEmpty(_configDao.getValue(Config.VmwareRootDiskControllerType.key()),
4782+
Config.VmwareRootDiskControllerType.getDefaultValue());
4783+
vm.setDetail(VmDetailConstants.ROOT_DISK_CONTROLLER, vmwareRootDiskControllerTypeFromSetting);
47854784
}
4785+
47864786
if (vm.getDetail(VmDetailConstants.DATA_DISK_CONTROLLER) == null) {
4787-
if (controllerSetting.equalsIgnoreCase("scsi")) {
4788-
vm.setDetail(VmDetailConstants.DATA_DISK_CONTROLLER, "scsi");
4787+
String finalRootDiskController = vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER);
4788+
// Set the data disk controller detail same as the final scsi root disk controller if VM doesn't have data disk controller detail
4789+
// This is to ensure the disk controller is available for the data disks, as all the SCSI controllers are created with same controller type
4790+
String scsiControllerPattern = "(?i)\\b(scsi|lsilogic|lsilogicsas|lsisas1068|buslogic|pvscsi)\\b";
4791+
if (finalRootDiskController.matches(scsiControllerPattern)) {
4792+
logger.info(String.format("Data disk controller was not defined, but root disk is using SCSI controller [%s]." +
4793+
"To ensure disk controllers are available for the data disks, the data disk controller is updated to match the root disk controller.", finalRootDiskController));
4794+
vm.setDetail(VmDetailConstants.DATA_DISK_CONTROLLER, finalRootDiskController);
47894795
} else {
4796+
logger.info("Data disk controller was not defined; defaulting to 'osdefault'.");
47904797
vm.setDetail(VmDetailConstants.DATA_DISK_CONTROLLER, "osdefault");
47914798
}
47924799
}

0 commit comments

Comments
 (0)