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;