This is an automated email from the ASF dual-hosted git repository. harikrishna pushed a commit to branch CheckVolumeAPI in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 61a63a9307d72e635afd8677da1ae4b1905ff46a Author: Harikrishna Patnala <harikrishna.patn...@gmail.com> AuthorDate: Thu Feb 1 12:28:40 2024 +0530 Code refactored --- .../engine/orchestration/VolumeOrchestrator.java | 17 ++-- .../LibvirtCheckAndRepairVolumeCommandWrapper.java | 102 ++++++++++++------- .../com/cloud/storage/VolumeApiServiceImpl.java | 111 +++++++++++---------- 3 files changed, 139 insertions(+), 91 deletions(-) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 4e157303b71..cde997be62b 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -1916,12 +1916,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati } } } else { - Host host = _hostDao.findById(vm.getVirtualMachine().getHostId()); - try { - volService.checkAndRepairVolumeBasedOnConfig(volFactory.getVolume(vol.getId()), host); - } catch (Exception e) { - s_logger.debug(String.format("Unable to check and repair volume [%s] on host [%s], due to %s.", volToString, host, e.getMessage())); - } + handleCheckAndRepairVolume(vol, vm.getVirtualMachine().getHostId()); } } else if (task.type == VolumeTaskType.MIGRATE) { pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); @@ -1964,6 +1959,16 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati } } + private void handleCheckAndRepairVolume(Volume vol, Long hostId) { + Host host = _hostDao.findById(hostId); + try { + volService.checkAndRepairVolumeBasedOnConfig(volFactory.getVolume(vol.getId()), host); + } catch (Exception e) { + String volumeToString = getReflectOnlySelectedFields(vol); + s_logger.debug(String.format("Unable to check and repair volume [%s] on host [%s], due to %s.", volumeToString, host, e.getMessage())); + } + } + private boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException { return _volStateMachine.transitTo(vol, event, null, _volsDao); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckAndRepairVolumeCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckAndRepairVolumeCommandWrapper.java index a9d9cd948e6..e31a4a0287a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckAndRepairVolumeCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckAndRepairVolumeCommandWrapper.java @@ -30,6 +30,7 @@ import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; import com.cloud.utils.exception.CloudRuntimeException; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.JsonNode; import org.apache.cloudstack.utils.cryptsetup.KeyFile; @@ -38,6 +39,7 @@ import org.apache.cloudstack.utils.qemu.QemuImg; import org.apache.cloudstack.utils.qemu.QemuImgException; import org.apache.cloudstack.utils.qemu.QemuImgFile; import org.apache.cloudstack.utils.qemu.QemuObject; +import org.apache.cloudstack.utils.qemu.QemuObject.EncryptFormat; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -61,47 +63,23 @@ public class LibvirtCheckAndRepairVolumeCommandWrapper extends CommandWrapper<Ch final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr(); KVMStoragePool pool = storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid()); - final KVMPhysicalDisk vol = pool.getPhysicalDisk(volumeId); - QemuObject.EncryptFormat encryptFormat = QemuObject.EncryptFormat.enumValue(command.getEncryptFormat()); byte[] passphrase = command.getPassphrase(); + try { - String checkVolumeResult = checkAndRepairVolume(vol, null, encryptFormat, passphrase, serverResource); - s_logger.info(String.format("Check Volume result for the volume %s is %s", vol.getName(), checkVolumeResult)); - CheckAndRepairVolumeAnswer answer = new CheckAndRepairVolumeAnswer(command, true, checkVolumeResult); - answer.setVolumeCheckExecutionResult(checkVolumeResult); - - int leaks = 0; - if (StringUtils.isNotEmpty(checkVolumeResult) && StringUtils.isNotEmpty(repair) && repair.equals("leaks")) { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode jsonNode = objectMapper.readTree(checkVolumeResult); - JsonNode leaksNode = jsonNode.get("leaks"); - if (leaksNode != null) { - leaks = leaksNode.asInt(); - } - - if (leaks == 0) { - String msg = String.format("no leaks found while checking for the volume %s, so skipping repair", vol.getName()); - s_logger.info(msg); - String jsonStringFormat = String.format("{ \"message\": \"%s\" }", msg); - String finalResult = (checkVolumeResult != null ? checkVolumeResult.concat(",") : "") + jsonStringFormat; - answer = new CheckAndRepairVolumeAnswer(command, true, finalResult); - answer.setVolumeRepairExecutionResult(jsonStringFormat); - answer.setVolumeCheckExecutionResult(checkVolumeResult); - - return answer; - } + CheckAndRepairVolumeAnswer answer = checkVolume(vol, command, serverResource); + String checkVolumeResult = answer.getVolumeCheckExecutionResult(); + + CheckAndRepairVolumeAnswer resultAnswer = checkIfRepairLeaksIsRequired(command, checkVolumeResult, vol.getName()); + // resultAnswer is not null when repair is not required, so return from here + if (resultAnswer != null) { + return resultAnswer; } if (StringUtils.isNotEmpty(repair)) { - String repairVolumeResult = checkAndRepairVolume(vol, repair, encryptFormat, passphrase, serverResource); - String finalResult = (checkVolumeResult != null ? checkVolumeResult.concat(",") : "") + repairVolumeResult; - s_logger.info(String.format("Repair Volume result for the volume %s is %s", vol.getName(), repairVolumeResult)); - - answer = new CheckAndRepairVolumeAnswer(command, true, finalResult); - answer.setVolumeRepairExecutionResult(repairVolumeResult); - answer.setVolumeCheckExecutionResult(checkVolumeResult); + answer = repairVolume(vol, command, serverResource, checkVolumeResult); } + return answer; } catch (Exception e) { return new CheckAndRepairVolumeAnswer(command, false, e.toString()); @@ -112,7 +90,61 @@ public class LibvirtCheckAndRepairVolumeCommandWrapper extends CommandWrapper<Ch } } - protected String checkAndRepairVolume(final KVMPhysicalDisk vol, final String repair, final QemuObject.EncryptFormat encryptFormat, byte[] passphrase, final LibvirtComputingResource libvirtComputingResource) throws CloudRuntimeException { + private CheckAndRepairVolumeAnswer checkVolume(KVMPhysicalDisk vol, CheckAndRepairVolumeCommand command, LibvirtComputingResource serverResource) { + EncryptFormat encryptFormat = EncryptFormat.enumValue(command.getEncryptFormat()); + byte[] passphrase = command.getPassphrase(); + String checkVolumeResult = checkAndRepairVolume(vol, null, encryptFormat, passphrase, serverResource); + s_logger.info(String.format("Check Volume result for the volume %s is %s", vol.getName(), checkVolumeResult)); + CheckAndRepairVolumeAnswer answer = new CheckAndRepairVolumeAnswer(command, true, checkVolumeResult); + answer.setVolumeCheckExecutionResult(checkVolumeResult); + + return answer; + } + + private CheckAndRepairVolumeAnswer repairVolume(KVMPhysicalDisk vol, CheckAndRepairVolumeCommand command, LibvirtComputingResource serverResource, String checkVolumeResult) { + EncryptFormat encryptFormat = EncryptFormat.enumValue(command.getEncryptFormat()); + byte[] passphrase = command.getPassphrase(); + final String repair = command.getRepair(); + + String repairVolumeResult = checkAndRepairVolume(vol, repair, encryptFormat, passphrase, serverResource); + String finalResult = (checkVolumeResult != null ? checkVolumeResult.concat(",") : "") + repairVolumeResult; + s_logger.info(String.format("Repair Volume result for the volume %s is %s", vol.getName(), repairVolumeResult)); + + CheckAndRepairVolumeAnswer answer = new CheckAndRepairVolumeAnswer(command, true, finalResult); + answer.setVolumeRepairExecutionResult(repairVolumeResult); + answer.setVolumeCheckExecutionResult(checkVolumeResult); + + return answer; + } + + private CheckAndRepairVolumeAnswer checkIfRepairLeaksIsRequired(CheckAndRepairVolumeCommand command, String checkVolumeResult, String volumeName) throws JsonProcessingException { + final String repair = command.getRepair(); + int leaks = 0; + if (StringUtils.isNotEmpty(checkVolumeResult) && StringUtils.isNotEmpty(repair) && repair.equals("leaks")) { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(checkVolumeResult); + JsonNode leaksNode = jsonNode.get("leaks"); + if (leaksNode != null) { + leaks = leaksNode.asInt(); + } + + if (leaks == 0) { + String msg = String.format("no leaks found while checking for the volume %s, so skipping repair", volumeName); + s_logger.info(msg); + String jsonStringFormat = String.format("{ \"message\": \"%s\" }", msg); + String finalResult = (checkVolumeResult != null ? checkVolumeResult.concat(",") : "") + jsonStringFormat; + CheckAndRepairVolumeAnswer answer = new CheckAndRepairVolumeAnswer(command, true, finalResult); + answer.setVolumeRepairExecutionResult(jsonStringFormat); + answer.setVolumeCheckExecutionResult(checkVolumeResult); + + return answer; + } + } + + return null; + } + + protected String checkAndRepairVolume(final KVMPhysicalDisk vol, final String repair, final EncryptFormat encryptFormat, byte[] passphrase, final LibvirtComputingResource libvirtComputingResource) throws CloudRuntimeException { List<QemuObject> passphraseObjects = new ArrayList<>(); QemuImageOptions imgOptions = null; if (ArrayUtils.isEmpty(passphrase)) { diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 36b0aee98c5..6a89ac4d4d9 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -1834,54 +1834,60 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic Long vmId = volume.getInstanceId(); if (vmId != null) { // serialize VM operation - AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); - if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { - // avoid re-entrance + return handleCheckAndRepairVolumeJob(vmId, volumeId, repair); + } else { + return handleCheckAndRepairVolume(volumeId, repair); + } + } - VmWorkJobVO placeHolder = null; - placeHolder = createPlaceHolderWork(vmId); - try { - Pair<String, String> result = orchestrateCheckAndRepairVolume(volumeId, repair); - return result; - } finally { - _workJobDao.expunge(placeHolder.getId()); - } - } else { - Outcome<Pair> outcome = checkAndRepairVolumeThroughJobQueue(vmId, volumeId, repair); + private Pair<String, String> handleCheckAndRepairVolume(Long volumeId, String repair) { + CheckAndRepairVolumePayload payload = new CheckAndRepairVolumePayload(repair); + VolumeInfo volumeInfo = volFactory.getVolume(volumeId); + volumeInfo.addPayload(payload); - try { - outcome.get(); - } catch (InterruptedException e) { - throw new RuntimeException("Operation is interrupted", e); - } catch (ExecutionException e) { - throw new RuntimeException("Execution exception--", e); - } + Pair<String, String> result = volService.checkAndRepairVolume(volumeInfo); + return result; + } - Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); - if (jobResult != null) { - if (jobResult instanceof ConcurrentOperationException) { - throw (ConcurrentOperationException)jobResult; - } else if (jobResult instanceof ResourceAllocationException) { - throw (ResourceAllocationException)jobResult; - } else if (jobResult instanceof Throwable) { - throw new RuntimeException("Unexpected exception", (Throwable)jobResult); - } - } + private Pair<String, String> handleCheckAndRepairVolumeJob(Long vmId, Long volumeId, String repair) throws ResourceAllocationException { + AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + // avoid re-entrance + VmWorkJobVO placeHolder = null; + placeHolder = createPlaceHolderWork(vmId); + try { + Pair<String, String> result = orchestrateCheckAndRepairVolume(volumeId, repair); + return result; + } finally { + _workJobDao.expunge(placeHolder.getId()); + } + } else { + Outcome<Pair> outcome = checkAndRepairVolumeThroughJobQueue(vmId, volumeId, repair); + try { + outcome.get(); + } catch (InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (ExecutionException e) { + throw new RuntimeException("Execution exception--", e); + } - // retrieve the entity url from job result - if (jobResult != null && jobResult instanceof Pair) { - return (Pair<String, String>) jobResult; + Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof ConcurrentOperationException) { + throw (ConcurrentOperationException)jobResult; + } else if (jobResult instanceof ResourceAllocationException) { + throw (ResourceAllocationException)jobResult; + } else if (jobResult instanceof Throwable) { + throw new RuntimeException("Unexpected exception", (Throwable)jobResult); } + } - return null; + // retrieve the entity url from job result + if (jobResult != null && jobResult instanceof Pair) { + return (Pair<String, String>) jobResult; } - } else { - CheckAndRepairVolumePayload payload = new CheckAndRepairVolumePayload(repair); - VolumeInfo volumeInfo = volFactory.getVolume(volumeId); - volumeInfo.addPayload(payload); - Pair<String, String> result = volService.checkAndRepairVolume(volumeInfo); - return result; + return null; } } @@ -1892,16 +1898,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic Long volumeId = volume.getId(); Long vmId = volume.getInstanceId(); if (vmId != null) { - UserVmVO vm = _userVmDao.findById(vmId); - if (vm == null) { - throw new InvalidParameterValueException(String.format("VM not found, please check the VM to which this volume %d is attached", volumeId)); - } - - _accountMgr.checkAccess(caller, null, true, vm); - - if (vm.getState() != State.Stopped) { - throw new InvalidParameterValueException(String.format("VM to which the volume %d is attached should be in stopped state", volumeId)); - } + validateVMforCheckVolumeOperation(vmId, volumeId); } if (volume.getState() != Volume.State.Ready) { @@ -1914,6 +1911,20 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } } + private void validateVMforCheckVolumeOperation(Long vmId, Long volumeId) { + Account caller = CallContext.current().getCallingAccount(); + UserVmVO vm = _userVmDao.findById(vmId); + if (vm == null) { + throw new InvalidParameterValueException(String.format("VM not found, please check the VM to which this volume %d is attached", volumeId)); + } + + _accountMgr.checkAccess(caller, null, true, vm); + + if (vm.getState() != State.Stopped) { + throw new InvalidParameterValueException(String.format("VM to which the volume %d is attached should be in stopped state", volumeId)); + } + } + private Pair<String, String> orchestrateCheckAndRepairVolume(Long volumeId, String repair) { VolumeInfo volume = volFactory.getVolume(volumeId);