mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Allow password definition during VM deploy (#6947)
Co-authored-by: Stephan Krug <stephan.krug@scclouds.com.br> Co-authored-by: dahn <daan.hoogland@gmail.com> Co-authored-by: GaOrtiga <49285692+GaOrtiga@users.noreply.github.com> Co-authored-by: Gabriel Pordeus Santos <gabrielpordeus@gmail.com> Co-authored-by: Gabriel <gabriel.fernandes@scclouds.com.br>
This commit is contained in:
parent
9df580cef4
commit
0c14e4603d
@ -105,6 +105,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
@Parameter(name = ApiConstants.DISPLAY_NAME, type = CommandType.STRING, description = "an optional user generated name for the virtual machine")
|
@Parameter(name = ApiConstants.DISPLAY_NAME, type = CommandType.STRING, description = "an optional user generated name for the virtual machine")
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="The password of the virtual machine. If null, a random password will be generated for the VM.",
|
||||||
|
since="4.19.0.0")
|
||||||
|
protected String password;
|
||||||
|
|
||||||
//Owner information
|
//Owner information
|
||||||
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.")
|
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.")
|
||||||
private String accountName;
|
private String accountName;
|
||||||
@ -464,6 +468,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
return zoneId;
|
return zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Long> getNetworkIds() {
|
public List<Long> getNetworkIds() {
|
||||||
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
||||||
if (CollectionUtils.isNotEmpty(networkIds) || ipAddress != null || getIp6Address() != null || MapUtils.isNotEmpty(ipToNetworkList)) {
|
if (CollectionUtils.isNotEmpty(networkIds) || ipAddress != null || getIp6Address() != null || MapUtils.isNotEmpty(ipToNetworkList)) {
|
||||||
|
|||||||
@ -1964,7 +1964,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
|
|||||||
private boolean startNewVM(long vmId) {
|
private boolean startNewVM(long vmId) {
|
||||||
try {
|
try {
|
||||||
CallContext.current().setEventDetails("Vm Id: " + vmId);
|
CallContext.current().setEventDetails("Vm Id: " + vmId);
|
||||||
userVmMgr.startVirtualMachine(vmId, null, null, null);
|
userVmMgr.startVirtualMachine(vmId, null, new HashMap<>(), null);
|
||||||
} catch (final ResourceUnavailableException ex) {
|
} catch (final ResourceUnavailableException ex) {
|
||||||
s_logger.warn("Exception: ", ex);
|
s_logger.warn("Exception: ", ex);
|
||||||
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
||||||
|
|||||||
@ -135,6 +135,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@ -1174,9 +1175,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
private UserVm forceRebootVirtualMachine(long vmId, long hostId, boolean enterSetup) {
|
private UserVm forceRebootVirtualMachine(long vmId, long hostId, boolean enterSetup) {
|
||||||
try {
|
try {
|
||||||
if (stopVirtualMachine(vmId, false) != null) {
|
if (stopVirtualMachine(vmId, false) != null) {
|
||||||
Map<VirtualMachineProfile.Param,Object> params = null;
|
Map<VirtualMachineProfile.Param,Object> params = new HashMap<>();
|
||||||
if (enterSetup) {
|
if (enterSetup) {
|
||||||
params = new HashMap();
|
|
||||||
params.put(VirtualMachineProfile.Param.BootIntoSetup, Boolean.TRUE);
|
params.put(VirtualMachineProfile.Param.BootIntoSetup, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
return startVirtualMachine(vmId, null, null, hostId, params, null, false).first();
|
return startVirtualMachine(vmId, null, null, hostId, params, null, false).first();
|
||||||
@ -4878,6 +4878,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
if (cmd.getBootIntoSetup() != null) {
|
if (cmd.getBootIntoSetup() != null) {
|
||||||
additionalParams.put(VirtualMachineProfile.Param.BootIntoSetup, cmd.getBootIntoSetup());
|
additionalParams.put(VirtualMachineProfile.Param.BootIntoSetup, cmd.getBootIntoSetup());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(cmd.getPassword())) {
|
||||||
|
additionalParams.put(VirtualMachineProfile.Param.VmPassword, cmd.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
return startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, additionalParams, cmd.getDeploymentPlanner());
|
return startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, additionalParams, cmd.getDeploymentPlanner());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5268,21 +5273,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long hostId, Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse)
|
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long hostId, @NotNull Map<VirtualMachineProfile.Param, Object> additionalParams,
|
||||||
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
String deploymentPlannerToUse) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
||||||
return startVirtualMachine(vmId, null, null, hostId, additionalParams, deploymentPlannerToUse);
|
return startVirtualMachine(vmId, null, null, hostId, additionalParams, deploymentPlannerToUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId,
|
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId,
|
||||||
Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse)
|
@NotNull Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse)
|
||||||
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
||||||
return startVirtualMachine(vmId, podId, clusterId, hostId, additionalParams, deploymentPlannerToUse, true);
|
return startVirtualMachine(vmId, podId, clusterId, hostId, additionalParams, deploymentPlannerToUse, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId,
|
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId,
|
||||||
Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse, boolean isExplicitHost)
|
@NotNull Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse, boolean isExplicitHost)
|
||||||
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
||||||
// Input validation
|
// Input validation
|
||||||
final Account callerAccount = CallContext.current().getCallingAccount();
|
final Account callerAccount = CallContext.current().getCallingAccount();
|
||||||
@ -5381,15 +5386,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
// Check that the password was passed in and is valid
|
// Check that the password was passed in and is valid
|
||||||
template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
|
template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
|
||||||
|
|
||||||
String password = "saved_password";
|
String password = getCurrentVmPasswordOrDefineNewPassword(String.valueOf(additionalParams.getOrDefault(VirtualMachineProfile.Param.VmPassword, "")), vm, template);
|
||||||
if (template.isEnablePassword()) {
|
|
||||||
if (vm.getDetail("password") != null) {
|
|
||||||
password = DBEncryptionUtil.decrypt(vm.getDetail("password"));
|
|
||||||
} else {
|
|
||||||
password = _mgr.generateRandomPassword();
|
|
||||||
vm.setPassword(password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validPassword(password)) {
|
if (!validPassword(password)) {
|
||||||
throw new InvalidParameterValueException("A valid password for this virtual machine was not provided.");
|
throw new InvalidParameterValueException("A valid password for this virtual machine was not provided.");
|
||||||
@ -5402,7 +5399,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password);
|
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(null != additionalParams && additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
|
if(additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
|
||||||
if (! HypervisorType.VMware.equals(vm.getHypervisorType())) {
|
if (! HypervisorType.VMware.equals(vm.getHypervisorType())) {
|
||||||
throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType());
|
throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType());
|
||||||
}
|
}
|
||||||
@ -5445,6 +5442,39 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
return vmParamPair;
|
return vmParamPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the template is password enabled and the VM already has a password, returns it.
|
||||||
|
* If the template is password enabled and the VM does not have a password, sets the password to the password defined by the user and returns it. If no password is informed,
|
||||||
|
* sets it to a random password and returns it.
|
||||||
|
* If the template is not password enabled, returns saved_password.
|
||||||
|
* @param newPassword The new password informed by the user in order to set the password of the VM.
|
||||||
|
* @param vm The VM to retrieve the password from.
|
||||||
|
* @param template The template to be checked if the password is enabled or not.
|
||||||
|
* @return The password of the VM or saved_password.
|
||||||
|
*/
|
||||||
|
protected String getCurrentVmPasswordOrDefineNewPassword(String newPassword, UserVmVO vm, VMTemplateVO template) {
|
||||||
|
String password = "saved_password";
|
||||||
|
|
||||||
|
if (template.isEnablePassword()) {
|
||||||
|
if (vm.getDetail("password") != null) {
|
||||||
|
s_logger.debug(String.format("Decrypting VM [%s] current password.", vm));
|
||||||
|
password = DBEncryptionUtil.decrypt(vm.getDetail("password"));
|
||||||
|
} else if (StringUtils.isNotBlank(newPassword)) {
|
||||||
|
s_logger.debug(String.format("A password for VM [%s] was informed. Setting VM password to value defined by user.", vm));
|
||||||
|
password = newPassword;
|
||||||
|
vm.setPassword(password);
|
||||||
|
} else {
|
||||||
|
s_logger.debug(String.format("Setting VM [%s] password to a randomly generated password.", vm));
|
||||||
|
password = _mgr.generateRandomPassword();
|
||||||
|
vm.setPassword(password);
|
||||||
|
}
|
||||||
|
} else if (StringUtils.isNotBlank(newPassword)) {
|
||||||
|
s_logger.debug(String.format("A password was informed; however, the template [%s] is not password enabled. Ignoring the parameter.", template));
|
||||||
|
}
|
||||||
|
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
private Map<VirtualMachineProfile.Param, Object> createParameterInParameterMap(Map<VirtualMachineProfile.Param, Object> params, Map<VirtualMachineProfile.Param, Object> parameterMap, VirtualMachineProfile.Param parameter,
|
private Map<VirtualMachineProfile.Param, Object> createParameterInParameterMap(Map<VirtualMachineProfile.Param, Object> params, Map<VirtualMachineProfile.Param, Object> parameterMap, VirtualMachineProfile.Param parameter,
|
||||||
Object parameterValue) {
|
Object parameterValue) {
|
||||||
if (s_logger.isTraceEnabled()) {
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
|||||||
@ -99,7 +99,6 @@ import com.cloud.vm.UserVmService;
|
|||||||
import com.cloud.vm.UserVmVO;
|
import com.cloud.vm.UserVmVO;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineManager;
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
import com.cloud.vm.VirtualMachineProfile;
|
|
||||||
import com.cloud.vm.VmStats;
|
import com.cloud.vm.VmStats;
|
||||||
import com.cloud.vm.dao.DomainRouterDao;
|
import com.cloud.vm.dao.DomainRouterDao;
|
||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
@ -1495,8 +1494,6 @@ public class AutoScaleManagerImplTest {
|
|||||||
when(autoScaleVmGroupDao.updateState(vmGroupId, AutoScaleVmGroup.State.ENABLED, AutoScaleVmGroup.State.SCALING)).thenReturn(true);
|
when(autoScaleVmGroupDao.updateState(vmGroupId, AutoScaleVmGroup.State.ENABLED, AutoScaleVmGroup.State.SCALING)).thenReturn(true);
|
||||||
when(autoScaleVmGroupDao.updateState(vmGroupId, AutoScaleVmGroup.State.SCALING, AutoScaleVmGroup.State.ENABLED)).thenReturn(true);
|
when(autoScaleVmGroupDao.updateState(vmGroupId, AutoScaleVmGroup.State.SCALING, AutoScaleVmGroup.State.ENABLED)).thenReturn(true);
|
||||||
Mockito.doReturn(virtualMachineId).when(autoScaleManagerImplSpy).createNewVM(asVmGroupMock);
|
Mockito.doReturn(virtualMachineId).when(autoScaleManagerImplSpy).createNewVM(asVmGroupMock);
|
||||||
Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVm = Mockito.mock(Pair.class);
|
|
||||||
when(userVmMgr.startVirtualMachine(virtualMachineId, null, null, null)).thenReturn(startVm);
|
|
||||||
|
|
||||||
when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
|
when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId);
|
||||||
when(lbVmMapDao.listByLoadBalancerId(loadBalancerId)).thenReturn(Arrays.asList(loadBalancerVMMapMock));
|
when(lbVmMapDao.listByLoadBalancerId(loadBalancerId)).thenReturn(Arrays.asList(loadBalancerVMMapMock));
|
||||||
|
|||||||
@ -38,6 +38,7 @@ import com.cloud.network.NetworkModel;
|
|||||||
import com.cloud.network.dao.NetworkDao;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import com.cloud.offering.ServiceOffering;
|
import com.cloud.offering.ServiceOffering;
|
||||||
|
import com.cloud.server.ManagementService;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
import com.cloud.service.dao.ServiceOfferingDao;
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
@ -213,6 +214,12 @@ public class UserVmManagerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
AccountVO account;
|
AccountVO account;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VMTemplateVO vmTemplateVoMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
ManagementService managementServiceMock;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ServiceOfferingVO serviceOffering;
|
private ServiceOfferingVO serviceOffering;
|
||||||
|
|
||||||
@ -1068,4 +1075,58 @@ public class UserVmManagerImplTest {
|
|||||||
Mockito.verify(userVmDao).findById(vmId);
|
Mockito.verify(userVmDao).findById(vmId);
|
||||||
Mockito.verify(userVmDao).update(vmId, userVmVoMock);
|
Mockito.verify(userVmDao).update(vmId, userVmVoMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentVmPasswordOrDefineNewPasswordTestTemplateIsNotPasswordEnabledReturnPreDefinedString() {
|
||||||
|
String expected = "saved_password";
|
||||||
|
|
||||||
|
Mockito.doReturn(false).when(vmTemplateVoMock).isEnablePassword();
|
||||||
|
|
||||||
|
String result = userVmManagerImpl.getCurrentVmPasswordOrDefineNewPassword("", userVmVoMock, vmTemplateVoMock);
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentVmPasswordOrDefineNewPasswordTestVmHasPasswordReturnCurrentPassword() {
|
||||||
|
String expected = "current_password";
|
||||||
|
|
||||||
|
Mockito.doReturn(true).when(vmTemplateVoMock).isEnablePassword();
|
||||||
|
Mockito.doReturn(expected).when(userVmVoMock).getDetail("password");
|
||||||
|
|
||||||
|
String result = userVmManagerImpl.getCurrentVmPasswordOrDefineNewPassword("", userVmVoMock, vmTemplateVoMock);
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentVmPasswordOrDefineNewPasswordTestUserDefinedPasswordReturnNewPasswordAndSetVmPassword() {
|
||||||
|
String expected = "new_password";
|
||||||
|
|
||||||
|
Mockito.doReturn(true).when(vmTemplateVoMock).isEnablePassword();
|
||||||
|
Mockito.doReturn(null).when(userVmVoMock).getDetail("password");
|
||||||
|
Mockito.doCallRealMethod().when(userVmVoMock).setPassword(Mockito.any());
|
||||||
|
Mockito.doCallRealMethod().when(userVmVoMock).getPassword();
|
||||||
|
|
||||||
|
String result = userVmManagerImpl.getCurrentVmPasswordOrDefineNewPassword(expected, userVmVoMock, vmTemplateVoMock);
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, result);
|
||||||
|
Assert.assertEquals(expected, userVmVoMock.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentVmPasswordOrDefineNewPasswordTestUserDefinedPasswordReturnRandomPasswordAndSetVmPassword() {
|
||||||
|
String expected = "random_password";
|
||||||
|
|
||||||
|
Mockito.doReturn(true).when(vmTemplateVoMock).isEnablePassword();
|
||||||
|
Mockito.doReturn(null).when(userVmVoMock).getDetail("password");
|
||||||
|
Mockito.doReturn(expected).when(managementServiceMock).generateRandomPassword();
|
||||||
|
Mockito.doCallRealMethod().when(userVmVoMock).setPassword(Mockito.any());
|
||||||
|
Mockito.doCallRealMethod().when(userVmVoMock).getPassword();
|
||||||
|
|
||||||
|
String result = userVmManagerImpl.getCurrentVmPasswordOrDefineNewPassword("", userVmVoMock, vmTemplateVoMock);
|
||||||
|
|
||||||
|
Assert.assertEquals(expected, result);
|
||||||
|
Assert.assertEquals(expected, userVmVoMock.getPassword());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user