You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by nv...@apache.org on 2021/06/16 18:39:41 UTC
[cloudstack] 01/01: Merge branch '4.15' into main
This is an automated email from the ASF dual-hosted git repository.
nvazquez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit d2ab350a40cffe4eacf625e1648db7c12341f2cb
Merge: 07cabbe 46a3032
Author: nicolas <ni...@gmail.com>
AuthorDate: Wed Jun 16 15:38:18 2021 -0300
Merge branch '4.15' into main
.../com/cloud/vm/VirtualMachineManagerImpl.java | 3 +
.../hypervisor/kvm/resource/BridgeVifDriver.java | 4 +-
.../hypervisor/kvm/resource/IvsVifDriver.java | 2 +-
.../hypervisor/vmware/resource/VmwareResource.java | 7 +-
.../java/com/cloud/storage/StorageManagerImpl.java | 2 +-
.../com/cloud/storage/VolumeApiServiceImpl.java | 45 +-
.../main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +-
.../cloud/storage/VolumeApiServiceImplTest.java | 56 +-
.../test/java/com/cloud/vm/UserVmManagerTest.java | 5 +-
tools/travis/xunit-reader.py | 2 +-
ui/public/locales/el_GR.json | 3332 ++++++++++++++++++++
ui/public/locales/en.json | 4 +-
ui/src/components/header/TranslationMenu.vue | 1 +
ui/src/config/section/infra/primaryStorages.js | 8 +
ui/src/views/image/RegisterOrUploadTemplate.vue | 6 +-
15 files changed, 3450 insertions(+), 29 deletions(-)
diff --cc engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index e378842,3f435e9..0cb766e
--- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@@ -2395,20 -2297,19 +2395,23 @@@ public class VirtualMachineManagerImpl
}
List<VolumeVO> volumes = _volsDao.findUsableVolumesForInstance(vm.getId());
if(s_logger.isDebugEnabled()) {
- String msg = String.format("found %d volumes for VM %s(uuid:%s, id:%d)", volumes.size(), vm.getInstanceName(), vm.getUuid(), vm.getId());
+ String msg = String.format("Found %d volumes for VM %s(uuid:%s, id:%d)", results.size(), vm.getInstanceName(), vm.getUuid(), vm.getId());
s_logger.debug(msg);
}
- for (VolumeObjectTO result : relevantAnswer.getVolumeTos() ) {
+ for (VolumeObjectTO result : results ) {
if(s_logger.isDebugEnabled()) {
- s_logger.debug(String.format("updating volume (%d) with path '%s' on pool '%d'", result.getId(), result.getPath(), destPool.getId()));
+ s_logger.debug(String.format("Updating volume (%d) with path '%s' on pool '%s'", result.getId(), result.getPath(), result.getDataStoreUuid()));
}
VolumeVO volume = _volsDao.findById(result.getId());
+ StoragePool pool = _storagePoolDao.findPoolByUUID(result.getDataStoreUuid());
+ if (volume == null || pool == null) {
+ continue;
+ }
volume.setPath(result.getPath());
- volume.setPoolId(destPool.getId());
+ volume.setPoolId(pool.getId());
+ if (result.getChainInfo() != null) {
+ volume.setChainInfo(result.getChainInfo());
+ }
_volsDao.update(volume.getId(), volume);
}
}
diff --cc plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index a9a953a,f8fe2d6..f19f7cc
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@@ -7302,281 -7539,6 +7302,282 @@@ public class VmwareResource implements
return new PrepareUnmanageVMInstanceAnswer(cmd, true, "OK");
}
+ /*
+ * Method to relocate a virtual machine. This migrates VM and its volumes to given host, datastores.
+ * It is used for MigrateVolumeCommand (detached volume case), MigrateVmToPoolCommand and MigrateVmWithStorageCommand.
+ */
+
+ private List<VolumeObjectTO> relocateVirtualMachine(final VmwareHypervisorHost hypervisorHost,
+ final String name, final VirtualMachineTO vmTo,
+ final String targetHost, final VmwareHypervisorHost hostInTargetCluster,
+ final String poolUuid, final List<Pair<VolumeTO, StorageFilerTO>> volToFiler) throws Exception {
+ String vmName = name;
+ if (vmName == null && vmTo != null) {
+ vmName = vmTo.getName();
+ }
+ VmwareHypervisorHost sourceHyperHost = hypervisorHost;
+ VmwareHypervisorHost targetHyperHost = hostInTargetCluster;
+ VirtualMachineMO vmMo = null;
+ ManagedObjectReference morSourceHostDc = null;
+ VirtualMachineRelocateSpec relocateSpec = new VirtualMachineRelocateSpec();
+ List<VirtualMachineRelocateSpecDiskLocator> diskLocators = new ArrayList<VirtualMachineRelocateSpecDiskLocator>();
+ Set<String> mountedDatastoresAtSource = new HashSet<String>();
+ List<VolumeObjectTO> volumeToList = new ArrayList<>();
+ Map<Long, Integer> volumeDeviceKey = new HashMap<Long, Integer>();
+
+ try {
+ if (sourceHyperHost == null) {
+ sourceHyperHost = getHyperHost(getServiceContext());
+ }
+ if (targetHyperHost == null && StringUtils.isNotBlank(targetHost)) {
+ targetHyperHost = VmwareHelper.getHostMOFromHostName(getServiceContext(), targetHost);
+ }
+ morSourceHostDc = sourceHyperHost.getHyperHostDatacenter();
+ DatacenterMO dcMo = new DatacenterMO(sourceHyperHost.getContext(), morSourceHostDc);
+ if (targetHyperHost != null) {
+ ManagedObjectReference morTargetHostDc = targetHyperHost.getHyperHostDatacenter();
+ if (!morSourceHostDc.getValue().equalsIgnoreCase(morTargetHostDc.getValue())) {
+ String msg = "VM " + vmName + " cannot be migrated between different datacenter";
+ throw new CloudRuntimeException(msg);
+ }
+ }
+
+ // find VM through source host (VM is not at the target host yet)
+ vmMo = sourceHyperHost.findVmOnHyperHost(vmName);
+ if (vmMo == null) {
+ String msg = "VM " + vmName + " does not exist on host: " + sourceHyperHost.getHyperHostName();
+ s_logger.warn(msg);
+ // find VM through source host (VM is not at the target host yet)
+ vmMo = dcMo.findVm(vmName);
+ if (vmMo == null) {
+ msg = "VM " + vmName + " does not exist on datacenter: " + dcMo.getName();
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ // VM host has changed
+ sourceHyperHost = vmMo.getRunningHost();
+ }
+
+ vmName = vmMo.getName();
+ String srcHostApiVersion = ((HostMO)sourceHyperHost).getHostAboutInfo().getApiVersion();
+
+ if (StringUtils.isNotBlank(poolUuid)) {
+ VmwareHypervisorHost dsHost = targetHyperHost == null ? sourceHyperHost : targetHyperHost;
+ ManagedObjectReference morDatastore = null;
+ String msg;
+ morDatastore = getTargetDatastoreMOReference(poolUuid, dsHost);
+ if (morDatastore == null) {
+ msg = "Unable to find the target datastore: " + poolUuid + " on host: " + dsHost.getHyperHostName() +
+ " to execute migration";
+ s_logger.error(msg);
+ throw new CloudRuntimeException(msg);
+ }
+ relocateSpec.setDatastore(morDatastore);
+ } else if (CollectionUtils.isNotEmpty(volToFiler)) {
+ // Specify destination datastore location for each volume
+ VmwareHypervisorHost dsHost = targetHyperHost == null ? sourceHyperHost : targetHyperHost;
+ for (Pair<VolumeTO, StorageFilerTO> entry : volToFiler) {
+ VolumeTO volume = entry.first();
+ StorageFilerTO filerTo = entry.second();
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug(String.format("Preparing spec for volume: %s to migrate it to datastore: %s", volume.getName(), filerTo.getUuid()));
+ }
+ ManagedObjectReference morVolumeDatastore = getTargetDatastoreMOReference(filerTo.getUuid(), dsHost);
+ if (morVolumeDatastore == null) {
+ String msg = "Unable to find the target datastore: " + filerTo.getUuid() + " in datacenter: " + dcMo.getName() + " to execute migration";
+ s_logger.error(msg);
+ throw new CloudRuntimeException(msg);
+ }
+
+ String mountedDs = getMountedDatastoreName(sourceHyperHost, srcHostApiVersion, filerTo);
+ if (mountedDs != null) {
+ mountedDatastoresAtSource.add(mountedDs);
+ }
+
+ if (volume.getType() == Volume.Type.ROOT) {
+ relocateSpec.setDatastore(morVolumeDatastore);
+ }
+ VirtualMachineRelocateSpecDiskLocator diskLocator = new VirtualMachineRelocateSpecDiskLocator();
+ diskLocator.setDatastore(morVolumeDatastore);
+ Pair<VirtualDisk, String> diskInfo = getVirtualDiskInfo(vmMo, volume.getPath() + VMDK_EXTENSION);
+ String vmdkAbsFile = getAbsoluteVmdkFile(diskInfo.first());
+ if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) {
+ vmMo.updateAdapterTypeIfRequired(vmdkAbsFile);
+ }
+ int diskId = diskInfo.first().getKey();
+ diskLocator.setDiskId(diskId);
+
+ diskLocators.add(diskLocator);
+ volumeDeviceKey.put(volume.getId(), diskId);
+ }
+ // If a target datastore is provided for the VM, then by default all volumes associated with the VM will be migrated to that target datastore.
+ // Hence set the existing datastore as target datastore for volumes that are not to be migrated.
+ List<Pair<Integer, ManagedObjectReference>> diskDatastores = vmMo.getAllDiskDatastores();
+ for (Pair<Integer, ManagedObjectReference> diskDatastore : diskDatastores) {
+ if (!volumeDeviceKey.containsValue(diskDatastore.first().intValue())) {
+ VirtualMachineRelocateSpecDiskLocator diskLocator = new VirtualMachineRelocateSpecDiskLocator();
+ diskLocator.setDiskId(diskDatastore.first().intValue());
+ diskLocator.setDatastore(diskDatastore.second());
+ diskLocators.add(diskLocator);
+ }
+ }
+
+ relocateSpec.getDisk().addAll(diskLocators);
+ }
+
+ // Specific section for MigrateVmWithStorageCommand
+ if (vmTo != null) {
+ // Prepare network at target before migration
+ NicTO[] nics = vmTo.getNics();
+ for (NicTO nic : nics) {
+ // prepare network on the host
+ prepareNetworkFromNicInfo((HostMO)targetHyperHost, nic, false, vmTo.getType());
+ }
+ // Ensure secondary storage mounted on target host
+ VmwareManager mgr = targetHyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+ Pair<String, Long> secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId));
+ String secStoreUrl = secStoreUrlAndId.first();
+ Long secStoreId = secStoreUrlAndId.second();
+ if (secStoreUrl == null) {
+ String msg = "secondary storage for dc " + _dcId + " is not ready yet?";
+ throw new Exception(msg);
+ }
+ mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId);
+ ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, targetHyperHost);
+ if (morSecDs == null) {
+ String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl;
+ throw new Exception(msg);
+ }
+ }
+
+ if (srcHostApiVersion.compareTo("5.1") < 0) {
+ // Migrate VM's volumes to target datastore(s).
+ if (!vmMo.changeDatastore(relocateSpec)) {
+ throw new Exception("Change datastore operation failed during storage migration");
+ } else {
+ s_logger.debug("Successfully migrated storage of VM " + vmName + " to target datastore(s)");
+ }
+ // Migrate VM to target host.
+ if (targetHyperHost != null) {
+ ManagedObjectReference morPool = targetHyperHost.getHyperHostOwnerResourcePool();
+ if (!vmMo.migrate(morPool, targetHyperHost.getMor())) {
+ throw new Exception("VM migration to target host failed during storage migration");
+ } else {
+ s_logger.debug("Successfully migrated VM " + vmName + " from " + sourceHyperHost.getHyperHostName() + " to " + targetHyperHost.getHyperHostName());
+ }
+ }
+ } else {
+ // Add target host to relocate spec
+ if (targetHyperHost != null) {
+ relocateSpec.setHost(targetHyperHost.getMor());
+ relocateSpec.setPool(targetHyperHost.getHyperHostOwnerResourcePool());
+ }
+ if (!vmMo.changeDatastore(relocateSpec)) {
+ throw new Exception("Change datastore operation failed during storage migration");
+ } else {
+ s_logger.debug("Successfully migrated VM " + vmName +
+ (hostInTargetCluster != null ? " from " + sourceHyperHost.getHyperHostName() + " to " + targetHyperHost.getHyperHostName() + " and " : " with ") +
+ "its storage to target datastore(s)");
+ }
+ }
+
+ // Consolidate VM disks.
+ // In case of a linked clone VM, if VM's disks are not consolidated, further VM operations such as volume snapshot, VM snapshot etc. will result in DB inconsistencies.
+ if (!vmMo.consolidateVmDisks()) {
+ s_logger.warn("VM disk consolidation failed after storage migration. Yet proceeding with VM migration.");
+ } else {
+ s_logger.debug("Successfully consolidated disks of VM " + vmName + ".");
+ }
+
+ if (MapUtils.isNotEmpty(volumeDeviceKey)) {
+ // Update and return volume path and chain info for every disk because that could have changed after migration
+ VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
+ for (Pair<VolumeTO, StorageFilerTO> entry : volToFiler) {
+ final VolumeTO volume = entry.first();
+ final long volumeId = volume.getId();
+ VirtualDisk[] disks = vmMo.getAllDiskDevice();
+ for (VirtualDisk disk : disks) {
+ if (volumeDeviceKey.get(volumeId) == disk.getKey()) {
+ VolumeObjectTO newVol = new VolumeObjectTO();
+ newVol.setDataStoreUuid(entry.second().getUuid());
+ String newPath = vmMo.getVmdkFileBaseName(disk);
- String poolName = entry.second().getUuid().replace("-", "");
- VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, poolName);
++ ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(targetHyperHost, entry.second().getUuid());
++ DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
++ VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, dsMo.getName());
+ newVol.setId(volumeId);
+ newVol.setPath(newPath);
+ newVol.setChainInfo(_gson.toJson(diskInfo));
+ volumeToList.add(newVol);
+ break;
+ }
+ }
+ }
+ }
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ s_logger.warn("Encountered remote exception at vCenter, invalidating VMware session context");
+ invalidateServiceContext();
+ }
+ throw e;
+ } finally {
+ // Cleanup datastores mounted on source host
+ for (String mountedDatastore : mountedDatastoresAtSource) {
+ s_logger.debug("Attempting to unmount datastore " + mountedDatastore + " at " + sourceHyperHost.getHyperHostName());
+ try {
+ sourceHyperHost.unmountDatastore(mountedDatastore);
+ } catch (Exception unmountEx) {
+ s_logger.warn("Failed to unmount datastore " + mountedDatastore + " at " + sourceHyperHost.getHyperHostName() + ". Seems the datastore is still being used by " + sourceHyperHost.getHyperHostName() +
+ ". Please unmount manually to cleanup.");
+ }
+ s_logger.debug("Successfully unmounted datastore " + mountedDatastore + " at " + sourceHyperHost.getHyperHostName());
+ }
+ }
+
+ // Only when volToFiler is not empty a filled list of VolumeObjectTO is returned else it will be empty
+ return volumeToList;
+ }
+
+ private String getMountedDatastoreName(VmwareHypervisorHost sourceHyperHost, String sourceHostApiVersion, StorageFilerTO filerTo) throws Exception {
+ String mountedDatastoreName = null;
+ // If host version is below 5.1 then simultaneous change of VM's datastore and host is not supported.
+ // So since only the datastore will be changed first, ensure the target datastore is mounted on source host.
+ if (sourceHostApiVersion.compareTo("5.1") < 0) {
+ s_logger.debug(String.format("Host: %s version is %s, vMotion without shared storage cannot be done. Check source host has target datastore mounted or can be mounted", sourceHyperHost.getHyperHostName(), sourceHostApiVersion));
+ ManagedObjectReference morVolumeDatastoreAtSource = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(sourceHyperHost, filerTo.getUuid());
+ String volumeDatastoreName = filerTo.getUuid().replace("-", "");
+ String volumeDatastoreHost = filerTo.getHost();
+ String volumeDatastorePath = filerTo.getPath();
+ int volumeDatastorePort = filerTo.getPort();
+
+ // If datastore is NFS and target datastore is not already mounted on source host then mount the datastore.
+ if (filerTo.getType().equals(StoragePoolType.NetworkFilesystem)) {
+ if (morVolumeDatastoreAtSource == null) {
+ morVolumeDatastoreAtSource = sourceHyperHost.mountDatastore(false, volumeDatastoreHost, volumeDatastorePort, volumeDatastorePath, volumeDatastoreName, false);
+ if (morVolumeDatastoreAtSource == null) {
+ throw new Exception("Unable to mount NFS datastore " + volumeDatastoreHost + ":/" + volumeDatastorePath + " on host: " + sourceHyperHost.getHyperHostName());
+ }
+ mountedDatastoreName = volumeDatastoreName;
+ s_logger.debug("Mounted NFS datastore " + volumeDatastoreHost + ":/" + volumeDatastorePath + " on host: " + sourceHyperHost.getHyperHostName());
+ }
+ }
+
+ // If datastore is VMFS and target datastore is not mounted or accessible to source host then fail migration.
+ if (filerTo.getType().equals(StoragePoolType.VMFS)) {
+ if (morVolumeDatastoreAtSource == null) {
+ s_logger.warn("Host: " + sourceHyperHost.getHyperHostName() + " version is below 5.1, target VMFS datastore(s) need to be manually mounted on host for successful storage migration.");
+ throw new Exception("Target VMFS datastore: " + volumeDatastorePath + " is not mounted on host: " + sourceHyperHost.getHyperHostName());
+ }
+ DatastoreMO dsAtSourceMo = new DatastoreMO(getServiceContext(), morVolumeDatastoreAtSource);
+ String srcHostValue = sourceHyperHost.getMor().getValue();
+ if (!dsAtSourceMo.isAccessibleToHost(srcHostValue)) {
+ s_logger.warn("Host " + sourceHyperHost.getHyperHostName() + " version is below 5.1, target VMFS datastore(s) need to be accessible to host for a successful storage migration.");
+ throw new Exception("Target VMFS datastore: " + volumeDatastorePath + " is not accessible on host: " + sourceHyperHost.getHyperHostName());
+ }
+ }
+ }
+ return mountedDatastoreName;
+ }
+
private Answer execute(ValidateVcenterDetailsCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource ValidateVcenterDetailsCommand " + _gson.toJson(cmd));
diff --cc server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index bdad40f,ccb91f1..0bd0861
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@@ -223,10 -218,10 +225,12 @@@ public class VolumeApiServiceImpl exten
@Inject
private SnapshotDao _snapshotDao;
@Inject
+ private SnapshotDataStoreDao _snapshotDataStoreDao;
+ @Inject
private ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
@Inject
+ private ServiceOfferingJoinDao serviceOfferingJoinDao;
+ @Inject
private UserVmDao _userVmDao;
@Inject
private UserVmDetailsDao userVmDetailsDao;