Skip to content

Commit 1cefa78

Browse files
João JandreJoaoJandre
authored andcommitted
Fix validation for password enabled VMs
1 parent 8e27a1a commit 1cefa78

7 files changed

Lines changed: 84 additions & 55 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupOfferingCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public String getValidationSteps() {
143143
sb.append(",");
144144
} catch (IllegalArgumentException ex) {
145145
logger.error("Invalid validation step informed [{}].", step, ex);
146-
throw new InvalidParameterValueException(String.format("Invalid validation step [%s] informed. Accepted values are: wait_for_boot, screenshot and script.", step));
146+
throw new InvalidParameterValueException(String.format("Invalid validation step [%s] informed. Accepted values are: wait_for_boot, screenshot and execute_command.", step));
147147
}
148148
}
149149
sb.deleteCharAt(sb.lastIndexOf(","));

engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,5 @@ public interface NetworkDao extends GenericDao<NetworkVO, Long>, StateDao<State,
136136

137137
List<NetworkVO> getAllPersistentNetworksFromZone(long dataCenterId);
138138

139-
NetworkVO findByZoneIdAndAccountIdAndGuestType(long zoneId, long accountId, GuestType guestType);
139+
NetworkVO findByZoneIdAndAccountIdAndGuestTypeAndName(long zoneId, long accountId, GuestType guestType, String name);
140140
}

engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,12 +910,13 @@ public List<NetworkVO> listByPhysicalNetworkPvlan(long physicalNetworkId, String
910910
}
911911

912912
@Override
913-
public NetworkVO findByZoneIdAndAccountIdAndGuestType(long zoneId, long accountId, GuestType guestType) {
913+
public NetworkVO findByZoneIdAndAccountIdAndGuestTypeAndName(long zoneId, long accountId, GuestType guestType, String name) {
914914
SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();
915915

916916
sc.setParameters("datacenter", zoneId);
917917
sc.setParameters("account", accountId);
918918
sc.setParameters("guestType", guestType);
919+
sc.setParameters("name", name);
919920

920921
return findOneBy(sc);
921922
}

plugins/backup/kboss/src/main/java/org/apache/cloudstack/backup/KbossBackupProvider.java

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,19 +1175,18 @@ protected boolean validateWithHash(long backupId, BackupVO backupVO, BackupDetai
11751175
}
11761176

11771177
protected boolean validateWithValidationVm(long backupId, long hostId, BackupVO backupVO) {
1178-
UserVmVO validationVm;
1179-
validationVm = allocateValidationVm(backupId, backupVO);
1180-
if (validationVm == null) {
1181-
return false;
1182-
}
1183-
1184-
HostVO hostVo = hostDao.findById(hostId);
1185-
1186-
List<VolumeObjectTO> volumeToList = new ArrayList<>();
11871178
boolean startedVm = false;
1188-
VirtualMachineTO vmTO = null;
1189-
List<VolumeVO> volumeVOs = volumeDao.findByInstance(validationVm.getId());
1179+
UserVmVO validationVm = null;
1180+
List<VolumeVO> volumeVOs = List.of();
11901181
try {
1182+
validationVm = allocateValidationVm(backupId, backupVO);
1183+
if (validationVm == null) {
1184+
return false;
1185+
}
1186+
1187+
HostVO hostVo = hostDao.findById(hostId);
1188+
List<VolumeObjectTO> volumeToList = new ArrayList<>();
1189+
volumeVOs = volumeDao.findByInstance(validationVm.getId());
11911190
createValidationVolumesOnPrimaryStorage(volumeVOs, validationVm, backupVO, hostVo, volumeToList);
11921191

11931192
List<InternalBackupDataStoreVO> backupDeltas = internalBackupDataStoreDao.listByBackupId(backupId);
@@ -1205,7 +1204,7 @@ protected boolean validateWithValidationVm(long backupId, long hostId, BackupVO
12051204

12061205
HypervisorGuru hvGuru = hypervisorGuruManager.getGuru(validationVm.getHypervisorType());
12071206
VirtualMachineProfileImpl profile = new VirtualMachineProfileImpl(validationVm);
1208-
vmTO = hvGuru.implement(profile);
1207+
VirtualMachineTO vmTO = hvGuru.implement(profile);
12091208

12101209
if (!validateBackup(backupId, vmTO, backupDeltaAndVolumePairs, backupVO, validationVm, hostVo)) {
12111210
endBackupChainIfConfigured(backupVO);
@@ -1410,6 +1409,7 @@ protected boolean prepareForValidation(long hostId, Set<Pair<BackupDeltaTO, Volu
14101409

14111410
protected void createValidationVolumesOnPrimaryStorage(List<VolumeVO> volumeVOs, UserVmVO validationVm, BackupVO backupVO, HostVO hostVo, List<VolumeObjectTO> volumeToList) throws NoTransitionException {
14121411
for (VolumeVO volume : volumeVOs) {
1412+
logger.debug("Creating validation volume [{}] for validation VM [{}].", volume.getUuid(), validationVm.getUuid());
14131413
VolumeInfo volumeInfo = volumeDataFactory.getVolume(volume.getId());
14141414
volumeInfo = volumeOrchestrationService.createVolumeOnPrimaryStorage(validationVm, volumeInfo, Hypervisor.HypervisorType.KVM, null, hostVo.getClusterId(),
14151415
hostVo.getPodId());
@@ -2676,8 +2676,9 @@ protected void validateVmState(VirtualMachine vm, String operation, VirtualMachi
26762676

26772677
protected Pair<Boolean, BackupVO> validateCompressionStateForRestoreAndGetBackup(long backupId) {
26782678
return Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<Pair<Boolean, BackupVO>>) result -> {
2679+
BackupVO backupVO = null;
26792680
try {
2680-
BackupVO backupVO = lockBackup(backupId);
2681+
backupVO = lockBackup(backupId);
26812682
if (backupVO == null) {
26822683
logger.warn("Unable to get lock on backup [{}]. Cannot restore it.", backupId);
26832684
return new Pair<>(false, null);
@@ -2692,7 +2693,9 @@ protected Pair<Boolean, BackupVO> validateCompressionStateForRestoreAndGetBackup
26922693
backupDao.update(backupId, backupVO);
26932694
return new Pair<>(true, backupVO);
26942695
} finally {
2695-
releaseBackup(backupId);
2696+
if (backupVO != null) {
2697+
releaseBackup(backupId);
2698+
}
26962699
}
26972700
});
26982701
}
@@ -2703,8 +2706,9 @@ protected Pair<Boolean, BackupVO> validateCompressionStateForRestoreAndGetBackup
27032706
* */
27042707
protected boolean validateBackupStateForRemoval(long backupId) {
27052708
return Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<Boolean>) result -> {
2709+
BackupVO backupVO = null;
27062710
try {
2707-
BackupVO backupVO = lockBackup(backupId);
2711+
backupVO = lockBackup(backupId);
27082712
if (backupVO == null) {
27092713
logger.warn("Unable to acquire lock for backup [{}]. Cannot remove it.", backupId);
27102714
return false;
@@ -2727,7 +2731,9 @@ protected boolean validateBackupStateForRemoval(long backupId) {
27272731
}
27282732
return true;
27292733
} finally {
2730-
releaseBackup(backupId);
2734+
if (backupVO != null) {
2735+
releaseBackup(backupId);
2736+
}
27312737
}
27322738
});
27332739
}
@@ -2738,8 +2744,9 @@ protected boolean validateBackupStateForRemoval(long backupId) {
27382744
* */
27392745
protected Pair<Boolean, BackupVO> validateBackupStateForStartCompressionAndUpdateCompressionStatus(long backupId) {
27402746
return Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<Pair<Boolean, BackupVO>>) result -> {
2747+
BackupVO backupVO = null;
27412748
try {
2742-
BackupVO backupVO = lockBackup(backupId);
2749+
backupVO = lockBackup(backupId);
27432750
if (backupVO == null) {
27442751
logger.warn("Unable to get lock on backup [{}]. Will abort the start of the compression process. We might try again later.", backupId);
27452752
return new Pair<>(false, null);
@@ -2755,7 +2762,9 @@ protected Pair<Boolean, BackupVO> validateBackupStateForStartCompressionAndUpdat
27552762
backupDao.update(backupVO.getId(), backupVO);
27562763
return new Pair<>(true, backupVO);
27572764
} finally {
2758-
releaseBackup(backupId);
2765+
if (backupVO != null) {
2766+
releaseBackup(backupId);
2767+
}
27592768
}
27602769
});
27612770
}
@@ -2766,8 +2775,9 @@ protected Pair<Boolean, BackupVO> validateBackupStateForStartCompressionAndUpdat
27662775
* */
27672776
protected Pair<Boolean, BackupVO> validateBackupStateForFinalizeCompression(long backupId) {
27682777
return Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<Pair<Boolean, BackupVO>>) result -> {
2778+
BackupVO backupVO = null;
27692779
try {
2770-
BackupVO backupVO = lockBackup(backupId);
2780+
backupVO = lockBackup(backupId);
27712781
if (backupVO == null) {
27722782
logger.warn("Unable to get lock on backup [{}]. Will abort the finalize compression process. We might try again later.", backupId);
27732783
return new Pair<>(false, null);
@@ -2786,23 +2796,25 @@ protected Pair<Boolean, BackupVO> validateBackupStateForFinalizeCompression(long
27862796
backupVO.setCompressionStatus(Backup.CompressionStatus.FinalizingCompression);
27872797
backupDao.update(backupId, backupVO);
27882798
} else {
2789-
logger.warn(
2790-
"Backup [{}] is in [{}] state. Aborting compression and cleaning up compressed data. We can only finish compression process if backup is in [{}] " + "state.",
2791-
backupVO.getUuid(), backupVO.getStatus(), Backup.Status.BackedUp);
2799+
logger.warn("Backup [{}] is in [{}] state. Aborting compression and cleaning up compressed data. We can only finish compression process if backup is in [{}] "
2800+
+ "state.", backupVO.getUuid(), backupVO.getStatus(), Backup.Status.BackedUp);
27922801
backupVO.setCompressionStatus(Backup.CompressionStatus.CompressionError);
27932802
backupDao.update(backupId, backupVO);
27942803
}
27952804
return new Pair<>(true, backupVO);
27962805
} finally {
2797-
releaseBackup(backupId);
2806+
if (backupVO != null) {
2807+
releaseBackup(backupId);
2808+
}
27982809
}
27992810
});
28002811
}
28012812

28022813
protected Pair<Boolean, Backup.Status> validateBackupStateForRestoreBackupToVM(long backupId) {
28032814
return Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<Pair<Boolean, Backup.Status>>) result -> {
2815+
BackupVO backupVO = null;
28042816
try {
2805-
BackupVO backupVO = lockBackup(backupId);
2817+
backupVO = lockBackup(backupId);
28062818
if (backupVO == null) {
28072819
logger.warn("Unable to get lock on backup [{}]. Cannot create VM from this backup right now.", backupId);
28082820
return new Pair<>(false, null);
@@ -2815,13 +2827,14 @@ protected Pair<Boolean, Backup.Status> validateBackupStateForRestoreBackupToVM(l
28152827
backupDao.update(backupId, backupVO);
28162828
return new Pair<>(true, oldStatus);
28172829
} else {
2818-
logger.warn(
2819-
"Backup [{}] is in [{}] state. Aborting restore. We can only restore the backup if backup is in [{}] states.",
2830+
logger.warn("Backup [{}] is in [{}] state. Aborting VM creation from backup. We can only create VM from backup if backup is in [{}] state.",
28202831
backupVO.getUuid(), backupVO.getStatus(), List.of(Backup.Status.BackedUp, Backup.Status.Restoring));
28212832
return new Pair<>(false, null);
28222833
}
28232834
} finally {
2824-
releaseBackup(backupId);
2835+
if (backupVO != null) {
2836+
releaseBackup(backupId);
2837+
}
28252838
}
28262839
});
28272840
}
@@ -2832,10 +2845,11 @@ protected Pair<Boolean, Backup.Status> validateBackupStateForRestoreBackupToVM(l
28322845
* */
28332846
protected boolean validateBackupStateForValidation(long backupId) {
28342847
return Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<Boolean>) result -> {
2848+
BackupVO backupVO = null;
28352849
try {
2836-
BackupVO backupVO = lockBackup(backupId);
2850+
backupVO = lockBackup(backupId);
28372851
if (backupVO == null) {
2838-
logger.warn("Unable to acquire lock for backup [{}]. Cannot validate it.", backupId);
2852+
logger.warn("Unable to acquire lock for backup [{}]. Cannot validate it. It might have been removed.", backupId);
28392853
return false;
28402854
}
28412855

@@ -2846,7 +2860,9 @@ protected boolean validateBackupStateForValidation(long backupId) {
28462860
}
28472861
return true;
28482862
} finally {
2849-
releaseBackup(backupId);
2863+
if (backupVO != null) {
2864+
releaseBackup(backupId);
2865+
}
28502866
}
28512867
});
28522868
}

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

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
427427
private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3;
428428

429429
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
430+
private static final String BACKUP_VALIDATION_NETWORK = "BackupValidationNetwork";
431+
private static final String DEFAULT_SHARED_NETWORK_OFFERING_WITH_NO_SERVICE = "DefaultSharedNetworkOfferingWithNoService";
430432

431433
@Inject
432434
private EntityManager _entityMgr;
@@ -4584,19 +4586,7 @@ private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, Stri
45844586
}
45854587

45864588
profile.setDefaultNic(true);
4587-
if (!_networkModel.areServicesSupportedInNetwork(network.getId(), new Service[]{Service.UserData})) {
4588-
if ((userData != null) && (!userData.isEmpty())) {
4589-
throw new InvalidParameterValueException(String.format("Unable to deploy VM as UserData is provided while deploying the VM, but there is no support for %s service in the default network %s/%s.", Service.UserData.getName(), network.getName(), network.getUuid()));
4590-
}
4591-
4592-
if ((sshPublicKeys != null) && (!sshPublicKeys.isEmpty())) {
4593-
throw new InvalidParameterValueException(String.format("Unable to deploy VM as SSH keypair is provided while deploying the VM, but there is no support for %s service in the default network %s/%s", Service.UserData.getName(), network.getName(), network.getUuid()));
4594-
}
4595-
4596-
if (template.isEnablePassword()) {
4597-
throw new InvalidParameterValueException(String.format("Unable to deploy VM as template %s is password enabled, but there is no support for %s service in the default network %s/%s", template, Service.UserData.getName(), network.getName(), network.getUuid()));
4598-
}
4599-
}
4589+
validateUserdataSupport(userData, vmType, template, network, sshPublicKeys);
46004590
}
46014591

46024592
if (_networkModel.isSecurityGroupSupportedInNetwork(network)) {
@@ -4703,6 +4693,30 @@ private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, Stri
47034693
}
47044694
}
47054695

4696+
/**
4697+
* Validates that the network supports the necessary UserData-related features for the VM
4698+
* <br/>
4699+
* Validation VMs are not validated, there VMs should be in a no-service network regardless of the original VM's settings.
4700+
* */
4701+
private void validateUserdataSupport(String userData, String vmType, VMTemplateVO template, NetworkVO network, String sshPublicKeys) {
4702+
if (VALIDATION_VM.equals(vmType)) {
4703+
return;
4704+
}
4705+
if (!_networkModel.areServicesSupportedInNetwork(network.getId(), new Service[]{Service.UserData})) {
4706+
if ((userData != null) && (!userData.isEmpty())) {
4707+
throw new InvalidParameterValueException(String.format("Unable to deploy VM as UserData is provided while deploying the VM, but there is no support for %s service in the default network %s/%s.", Service.UserData.getName(), network.getName(), network.getUuid()));
4708+
}
4709+
4710+
if ((sshPublicKeys != null) && (!sshPublicKeys.isEmpty())) {
4711+
throw new InvalidParameterValueException(String.format("Unable to deploy VM as SSH keypair is provided while deploying the VM, but there is no support for %s service in the default network %s/%s", Service.UserData.getName(), network.getName(), network.getUuid()));
4712+
}
4713+
4714+
if (template.isEnablePassword()) {
4715+
throw new InvalidParameterValueException(String.format("Unable to deploy VM as template %s is password enabled, but there is no support for %s service in the default network %s/%s", template.getId(), Service.UserData.getName(), network.getName(), network.getUuid()));
4716+
}
4717+
}
4718+
}
4719+
47064720
private void assignInstanceToGroup(String group, long id) {
47074721
// Assign instance to the group
47084722
try {
@@ -10128,13 +10142,11 @@ public UserVm allocateVMForValidation(long backupId, HypervisorType hypervisor)
1012810142
throw new CloudRuntimeException(String.format("Unable to find service offering with the uuid stored in backup [%s]. Unable to validate the backup.", backup.getUuid()));
1012910143
}
1013010144

10131-
VirtualMachineTemplate template;
10132-
1013310145
String templateUuid = backup.getDetail(ApiConstants.TEMPLATE_ID);
1013410146
if (templateUuid == null) {
1013510147
throw new CloudRuntimeException(String.format("Backup [%s] doesn't contain a template uuid. Unable to validate it.", backup.getUuid()));
1013610148
}
10137-
template = _templateDao.findByUuidIncludingRemoved(templateUuid);
10149+
VirtualMachineTemplate template = _templateDao.findByUuidIncludingRemoved(templateUuid);
1013810150
if (template == null) {
1013910151
throw new CloudRuntimeException(String.format("Unable to find template associated with the backup [%s]. Unable to validate it.", backup.getUuid()));
1014010152
}
@@ -10183,25 +10195,25 @@ public UserVm allocateVMForValidation(long backupId, HypervisorType hypervisor)
1018310195
}
1018410196

1018510197
private Network getValidationNetwork(long zoneId) {
10186-
NetworkVO networkVo = _networkDao.findByZoneIdAndAccountIdAndGuestType(zoneId, Account.ACCOUNT_ID_SYSTEM, GuestType.Shared);
10198+
NetworkVO networkVo = _networkDao.findByZoneIdAndAccountIdAndGuestTypeAndName(zoneId, Account.ACCOUNT_ID_SYSTEM, GuestType.Shared, BACKUP_VALIDATION_NETWORK);
1018710199
AccountVO accountVO = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM);
1018810200

1018910201
if (networkVo != null) {
1019010202
return networkVo;
1019110203
}
1019210204

10193-
NetworkOfferingVO offeringVo = _networkOfferingDao.findByUniqueName("DefaultSharedNetworkOfferingWithNoService");
10205+
NetworkOfferingVO offeringVo = _networkOfferingDao.findByUniqueName(DEFAULT_SHARED_NETWORK_OFFERING_WITH_NO_SERVICE);
1019410206

1019510207
if (offeringVo == null) {
10196-
offeringVo = new NetworkOfferingVO("DefaultSharedNetworkOfferingWithNoService",
10208+
offeringVo = new NetworkOfferingVO(DEFAULT_SHARED_NETWORK_OFFERING_WITH_NO_SERVICE,
1019710209
"Default shared offering with no services.", TrafficType.Guest, false, false, null, null, true, Availability.Optional, null, GuestType.Shared, false, true,
1019810210
false, false, false, false);
1019910211
offeringVo.setState(NetworkOffering.State.Enabled);
1020010212
offeringVo = _networkOfferingDao.persistDefaultNetworkOffering(offeringVo);
1020110213
}
1020210214

1020310215
try {
10204-
CreateNetworkCmd cmd = new CreateNetworkCmd(offeringVo.getId(), "BackupValidationNetwork", "System network for validating backups", "192.168.0.1", "255.255.0.0",
10216+
CreateNetworkCmd cmd = new CreateNetworkCmd(offeringVo.getId(), BACKUP_VALIDATION_NETWORK, "System network for validating backups", "192.168.0.1", "255.255.0.0",
1020510217
"192.168.0.2", "192.168.255.255", accountVO.getDomainId(), accountVO.getAccountName(), zoneId, ACLType.Domain.name(), true, false);
1020610218
ComponentContext.inject(cmd);
1020710219
return networkService.createGuestNetwork(cmd);

server/src/main/java/org/apache/cloudstack/backup/InternalBackupServiceJobController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ protected void submitQueuedJobsForExecution(List<InternalBackupServiceJobVO> job
251251
}
252252

253253
if (busyInstances.contains(job.getInstanceId())) {
254-
VirtualMachine vm = instanceDao.findById(job.getInstanceId());
254+
VirtualMachine vm = instanceDao.findByIdIncludingRemoved(job.getInstanceId());
255255
logger.debug("Instance [{}] has another backup service job running, will not schedule a {} job for it now.", vm.getUuid(), controllerType);
256256
continue;
257257
}

0 commit comments

Comments
 (0)