diff --git a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java index 8b13f17aed5..2dd4023d98c 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java @@ -55,8 +55,8 @@ public class MigrateVolumeCommand extends Command { this.setWait(timeout); } - public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) { - this(volumeId,volumePath,targetPool, null, Volume.Type.UNKNOWN, -1); + public MigrateVolumeCommand(long volumeId, String volumePath, String attachedVmName, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) { + this(volumeId,volumePath,targetPool, attachedVmName, Volume.Type.UNKNOWN, -1); this.sourcePool = new StorageFilerTO(sourcePool); this.hostGuidInTargetCluster = hostGuidInTargetCluster; } diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 3ca300804f7..5dabc5e270a 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -43,6 +43,7 @@ import com.cloud.offering.ServiceOffering; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; +import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.fsm.NoTransitionException; @@ -260,4 +261,6 @@ public interface VirtualMachineManager extends Manager { boolean unmanage(String vmUuid); UserVm restoreVirtualMachine(long vmId, Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException; + + Pair findClusterAndHostIdForVm(long vmId); } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 1a91ea5e1fd..b2de40deac2 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -2395,43 +2395,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - private Pair findClusterAndHostIdForVm(VMInstanceVO vm) { - Long hostId = vm.getHostId(); - Long clusterId = null; - // OfflineVmwareMigration: probably this is null when vm is stopped - if(hostId == null) { - hostId = vm.getLastHostId(); - if (s_logger.isDebugEnabled()) { - s_logger.debug(String.format("host id is null, using last host id %d", hostId) ); - } - } - if (hostId == null) { - List volumes = _volsDao.findByInstanceAndType(vm.getId(), Type.ROOT); - if (CollectionUtils.isNotEmpty(volumes)) { - for (VolumeVO rootVolume : volumes) { - if (rootVolume.getPoolId() != null) { - StoragePoolVO pool = _storagePoolDao.findById(rootVolume.getPoolId()); - if (pool != null && pool.getClusterId() != null) { - clusterId = pool.getClusterId(); - List hosts = _hostDao.findHypervisorHostInCluster(pool.getClusterId()); - if (CollectionUtils.isNotEmpty(hosts)) { - hostId = hosts.get(0).getId(); - break; - } - } - } - } - } - } - if (clusterId == null && hostId != null) { - HostVO host = _hostDao.findById(hostId); - if (host != null) { - clusterId = host.getClusterId(); - } - } - return new Pair<>(clusterId, hostId); - } - private void migrateThroughHypervisorOrStorage(VMInstanceVO vm, Map volumeToPool) throws StorageUnavailableException, InsufficientCapacityException { final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); Pair vmClusterAndHost = findClusterAndHostIdForVm(vm); @@ -6129,4 +6092,53 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac _jobMgr.marshallResultObject(result)); } + private Pair findClusterAndHostIdForVmFromVolumes(long vmId) { + Long clusterId = null; + Long hostId = null; + List volumes = _volsDao.findByInstance(vmId); + for (VolumeVO volume : volumes) { + if (Volume.State.Ready.equals(volume.getState()) && + volume.getPoolId() != null) { + StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId()); + if (pool != null && pool.getClusterId() != null) { + clusterId = pool.getClusterId(); + // hostId to be used only for sending commands, capacity check skipped + List hosts = _hostDao.findHypervisorHostInCluster(pool.getClusterId()); + if (CollectionUtils.isNotEmpty(hosts)) { + hostId = hosts.get(0).getId(); + break; + } + } + } + } + return new Pair<>(clusterId, hostId); + } + + private Pair findClusterAndHostIdForVm(VirtualMachine vm) { + Long hostId = vm.getHostId(); + Long clusterId = null; + if(hostId == null) { + hostId = vm.getLastHostId(); + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("host id is null, using last host id %d", hostId) ); + } + } + if (hostId == null) { + return findClusterAndHostIdForVmFromVolumes(vm.getId()); + } + HostVO host = _hostDao.findById(hostId); + if (host != null) { + clusterId = host.getClusterId(); + } + return new Pair<>(clusterId, hostId); + } + + @Override + public Pair findClusterAndHostIdForVm(long vmId) { + VMInstanceVO vm = _vmDao.findById(vmId); + if (vm == null) { + return new Pair<>(null, null); + } + return findClusterAndHostIdForVm(vm); + } } diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java index 71c1dce8904..a62921c9d94 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java @@ -33,6 +33,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -42,7 +43,6 @@ import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.StringUtils; -import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -57,7 +57,9 @@ public class DataMotionServiceImpl implements DataMotionService { @Override public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { if (srcData.getDataStore() == null || destData.getDataStore() == null) { - throw new CloudRuntimeException("can't find data store"); + String errMsg = "can't find data store"; + invokeCallback(errMsg, callback); + return; } if (srcData.getDataStore().getDriver().canCopy(srcData, destData)) { @@ -73,8 +75,10 @@ public class DataMotionServiceImpl implements DataMotionService { // OfflineVmware volume migration // Cleanup volumes from target and reset the state of volume at source cleanUpVolumesForFailedMigrations(srcData, destData); - throw new CloudRuntimeException("Can't find strategy to move data. " + "Source: " + srcData.getType().name() + " '" + srcData.getUuid() + ", Destination: " + - destData.getType().name() + " '" + destData.getUuid() + "'"); + String errMsg = "Can't find strategy to move data. " + "Source: " + srcData.getType().name() + " '" + srcData.getUuid() + ", Destination: " + + destData.getType().name() + " '" + destData.getUuid() + "'"; + invokeCallback(errMsg, callback); + return; } strategy.copyAsync(srcData, destData, destHost, callback); @@ -112,10 +116,22 @@ public class DataMotionServiceImpl implements DataMotionService { volumeIds.add(volumeInfo.getUuid()); } - throw new CloudRuntimeException("Can't find strategy to move data. " + "Source Host: " + srcHost.getName() + ", Destination Host: " + destHost.getName() + - ", Volume UUIDs: " + StringUtils.join(volumeIds, ",")); + String errMsg = "Can't find strategy to move data. " + "Source Host: " + srcHost.getName() + ", Destination Host: " + destHost.getName() + + ", Volume UUIDs: " + StringUtils.join(volumeIds, ","); + invokeCallback(errMsg, callback); + return; } strategy.copyAsync(volumeMap, vmTo, srcHost, destHost, callback); } + + private void invokeCallback(String errMsg, AsyncCompletionCallback callback) { + CopyCmdAnswer copyCmdAnswer = new CopyCmdAnswer(errMsg); + + CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); + + result.setResult(errMsg); + + callback.complete(result); + } } diff --git a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java index c720b28b567..155452d37a6 100644 --- a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java +++ b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java @@ -69,7 +69,11 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory { @Override public TemplateInfo getTemplateOnPrimaryStorage(long templateId, DataStore store, String configuration) { - VMTemplateVO templ = imageDataDao.findById(templateId); + VMTemplateVO templ = imageDataDao.findByIdIncludingRemoved(templateId); + if (templ == null) { + s_logger.error("Could not find a template with id " + templateId); + return null; + } if (store.getRole() == DataStoreRole.Primary) { VMTemplateStoragePoolVO templatePoolVO = templatePoolDao.findByPoolTemplate(store.getId(), templateId, configuration); if (templatePoolVO != null) { diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java index afb8a293c3d..d1bce216f18 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java @@ -207,48 +207,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co @Override public VirtualMachineTO implement(VirtualMachineProfile vm) { vmwareVmImplementer.setGlobalNestedVirtualisationEnabled(VmwareEnableNestedVirtualization.value()); vmwareVmImplementer.setGlobalNestedVPerVMEnabled(VmwareEnableNestedVirtualizationPerVM.value()); - return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), getClusterId(vm.getId())); - } - - private Long getClusterIdFromVmVolume(long vmId) { - Long clusterId = null; - List volumes = _volumeDao.findByInstanceAndType(vmId, Volume.Type.ROOT); - if (CollectionUtils.isNotEmpty(volumes)) { - for (VolumeVO rootVolume : volumes) { - if (rootVolume.getPoolId() != null) { - StoragePoolVO pool = _storagePoolDao.findById(rootVolume.getPoolId()); - if (pool != null && pool.getClusterId() != null) { - clusterId = pool.getClusterId(); - break; - } - } - } - } - return clusterId; - } - - private Long getClusterId(long vmId) { - Long clusterId = null; - Long hostId = null; - VMInstanceVO vm = _vmDao.findById(vmId); - if (vm != null) { - hostId = _vmDao.findById(vmId).getHostId(); - } - if (vm != null && hostId == null) { - // If VM is in stopped state then hostId would be undefined. Hence read last host's Id instead. - hostId = _vmDao.findById(vmId).getLastHostId(); - } - HostVO host = null; - if (hostId != null) { - host = _hostDao.findById(hostId); - } - if (host != null) { - clusterId = host.getClusterId(); - } else { - clusterId = getClusterIdFromVmVolume(vmId); - } - - return clusterId; + return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), vmManager.findClusterAndHostIdForVm(vm.getId()).first()); } @Override @DB public Pair getCommandHostDelegation(long hostId, Command cmd) { @@ -446,7 +405,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co @Override public Map getClusterSettings(long vmId) { Map details = new HashMap(); - Long clusterId = getClusterId(vmId); + Long clusterId = vmManager.findClusterAndHostIdForVm(vmId).first(); if (clusterId != null) { details.put(VmwareReserveCpu.key(), VmwareReserveCpu.valueIn(clusterId).toString()); details.put(VmwareReserveMemory.key(), VmwareReserveMemory.valueIn(clusterId).toString()); @@ -1114,7 +1073,6 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co List commands = new ArrayList(); // OfflineVmwareMigration: specialised migration command - List vols = new ArrayList<>(); List> volumeToFilerTo = new ArrayList>(); Long poolClusterId = null; for (Map.Entry entry : volumeToPool.entrySet()) { @@ -1126,10 +1084,9 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co poolClusterId = pool.getClusterId(); } volumeToFilerTo.add(new Pair(volumeTo, filerTo)); - vols.add(volumeTo); } final Long destClusterId = poolClusterId; - final Long srcClusterId = getClusterId(vm.getId()); + final Long srcClusterId = vmManager.findClusterAndHostIdForVm(vm.getId()).first(); final boolean isInterClusterMigration = isInterClusterMigration(destClusterId, srcClusterId); MigrateVmToPoolCommand migrateVmToPoolCommand = new MigrateVmToPoolCommand(vm.getInstanceName(), volumeToFilerTo, getHostGuidInTargetCluster(isInterClusterMigration, destClusterId), true); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index 1584bd003dc..a2aee6b53e1 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -34,11 +34,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import com.cloud.hypervisor.vmware.mo.VirtualStorageObjectManagerMO; -import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; -import com.vmware.vim25.BaseConfigInfoDiskFileBackingInfo; -import com.vmware.vim25.VStorageObject; -import com.vmware.vim25.VirtualDiskType; import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; @@ -84,7 +79,9 @@ import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.NetworkDetails; +import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; +import com.cloud.hypervisor.vmware.mo.VirtualStorageObjectManagerMO; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.resource.VmwareResource; import com.cloud.hypervisor.vmware.util.VmwareContext; @@ -104,6 +101,7 @@ import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VmDetailConstants; import com.google.common.base.Strings; import com.google.gson.Gson; +import com.vmware.vim25.BaseConfigInfoDiskFileBackingInfo; import com.vmware.vim25.DatastoreHostMount; import com.vmware.vim25.HostHostBusAdapter; import com.vmware.vim25.HostInternetScsiHba; @@ -122,11 +120,13 @@ import com.vmware.vim25.HostUnresolvedVmfsResignatureSpec; import com.vmware.vim25.HostUnresolvedVmfsVolume; import com.vmware.vim25.InvalidStateFaultMsg; import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.VStorageObject; import com.vmware.vim25.VirtualDeviceBackingInfo; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualDeviceConfigSpecOperation; import com.vmware.vim25.VirtualDisk; import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo; +import com.vmware.vim25.VirtualDiskType; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VmConfigInfo; import com.vmware.vim25.VmfsDatastoreExpandSpec; @@ -2683,15 +2683,14 @@ public class VmwareStorageProcessor implements StorageProcessor { List virtualDisks = vmMo.getVirtualDisks(); List managedDatastoreNames = getManagedDatastoreNamesFromVirtualDisks(virtualDisks); + // Preserve other disks of the VM + List detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null); + VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks); // let vmMo.destroy to delete volume for us // vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); - if (isManaged) { - List detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null); - VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks); vmMo.unregisterVm(); - } - else { + } else { vmMo.destroy(); } diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index 1a8ca9f0a66..04111bc3b6b 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -31,11 +31,9 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -67,6 +65,8 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.VMInstanceDao; @Component @@ -77,13 +77,13 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { @Inject VolumeDao volDao; @Inject - VolumeDataFactory volFactory; - @Inject PrimaryDataStoreDao storagePoolDao; @Inject VMInstanceDao instanceDao; @Inject - private HostDao hostDao; + HostDao hostDao; + @Inject + VirtualMachineManager vmManager; @Override public StrategyPriority canHandle(DataObject srcData, DataObject destData) { @@ -91,8 +91,7 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { if (isOnVmware(srcData, destData) && isOnPrimary(srcData, destData) && isVolumesOnly(srcData, destData) - && isIntraPodOrZoneWideStoreInvolved(srcData, destData) - && isDettached(srcData)) { + && isDetachedOrAttachedToStoppedVM(srcData)) { if (s_logger.isDebugEnabled()) { String msg = String.format("%s can handle the request because %d(%s) and %d(%s) share the pod" , this.getClass() @@ -107,20 +106,14 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { return StrategyPriority.CANT_HANDLE; } - private boolean isIntraPodOrZoneWideStoreInvolved(DataObject srcData, DataObject destData) { - DataStore srcStore = srcData.getDataStore(); - StoragePoolVO srcPool = storagePoolDao.findById(srcStore.getId()); - DataStore destStore = destData.getDataStore(); - StoragePoolVO destPool = storagePoolDao.findById(destStore.getId()); - if (srcPool.getPodId() != null && destPool.getPodId() != null) { - return srcPool.getPodId().equals(destPool.getPodId()); - } - return (ScopeType.ZONE.equals(srcPool.getScope()) || ScopeType.ZONE.equals(destPool.getScope())); + private boolean isAttachedToStoppedVM(Volume volume) { + VMInstanceVO vm = instanceDao.findById(volume.getInstanceId()); + return vm != null && VirtualMachine.State.Stopped.equals(vm.getState()); } - private boolean isDettached(DataObject srcData) { + private boolean isDetachedOrAttachedToStoppedVM(DataObject srcData) { VolumeVO volume = volDao.findById(srcData.getId()); - return volume.getInstanceId() == null; + return volume.getInstanceId() == null || isAttachedToStoppedVM(volume); } private boolean isVolumesOnly(DataObject srcData, DataObject destData) { @@ -138,11 +131,46 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { && HypervisorType.VMware.equals(destData.getTO().getHypervisorType()); } - private Pair getHostIdForVmAndHostGuidInTargetCluster(DataObject srcData, DataObject destData) { - StoragePool sourcePool = (StoragePool) srcData.getDataStore(); - ScopeType sourceScopeType = srcData.getDataStore().getScope().getScopeType(); - StoragePool targetPool = (StoragePool) destData.getDataStore(); - ScopeType targetScopeType = destData.getDataStore().getScope().getScopeType(); + private String getHostGuidInTargetCluster (Long sourceClusterId, + StoragePool targetPool, + ScopeType targetScopeType) { + String hostGuidInTargetCluster = null; + if (ScopeType.CLUSTER.equals(targetScopeType) && !sourceClusterId.equals(targetPool.getClusterId())) { + // Without host vMotion might fail between non-shared storages with error similar to, + // https://kb.vmware.com/s/article/1003795 + List hosts = hostDao.findHypervisorHostInCluster(targetPool.getClusterId()); + if (CollectionUtils.isNotEmpty(hosts)) { + hostGuidInTargetCluster = hosts.get(0).getGuid(); + } + if (hostGuidInTargetCluster == null) { + throw new CloudRuntimeException("Offline Migration failed, unable to find suitable target host for VM placement while migrating between storage pools of different cluster without shared storages"); + } + } + return hostGuidInTargetCluster; + } + + private VirtualMachine getVolumeVm(DataObject srcData) { + if (srcData instanceof VolumeInfo) { + return ((VolumeInfo)srcData).getAttachedVM(); + } + VolumeVO volume = volDao.findById(srcData.getId()); + return volume.getInstanceId() == null ? null : instanceDao.findById(volume.getInstanceId()); + } + + private Pair getHostIdForVmAndHostGuidInTargetClusterForAttachedVm(VirtualMachine vm, + StoragePool targetPool, + ScopeType targetScopeType) { + Pair clusterAndHostId = vmManager.findClusterAndHostIdForVm(vm.getId()); + if (clusterAndHostId.second() == null) { + throw new CloudRuntimeException(String.format("Offline Migration failed, unable to find host for VM: %s", vm.getUuid())); + } + return new Pair<>(clusterAndHostId.second(), getHostGuidInTargetCluster(clusterAndHostId.first(), targetPool, targetScopeType)); + } + + private Pair getHostIdForVmAndHostGuidInTargetClusterForWorkerVm(StoragePool sourcePool, + ScopeType sourceScopeType, + StoragePool targetPool, + ScopeType targetScopeType) { Long hostId = null; String hostGuidInTargetCluster = null; if (ScopeType.CLUSTER.equals(sourceScopeType)) { @@ -151,17 +179,7 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { if (hostId == null) { throw new CloudRuntimeException("Offline Migration failed, unable to find suitable host for worker VM placement in the cluster of storage pool: " + sourcePool.getName()); } - if (ScopeType.CLUSTER.equals(targetScopeType) && !sourcePool.getClusterId().equals(targetPool.getClusterId())) { - // Without host vMotion might fail between non-shared storages with error similar to, - // https://kb.vmware.com/s/article/1003795 - List hosts = hostDao.findHypervisorHostInCluster(targetPool.getClusterId()); - if (CollectionUtils.isNotEmpty(hosts)) { - hostGuidInTargetCluster = hosts.get(0).getGuid(); - } - if (hostGuidInTargetCluster == null) { - throw new CloudRuntimeException("Offline Migration failed, unable to find suitable target host for worker VM placement while migrating between storage pools of different cluster without shared storages"); - } - } + hostGuidInTargetCluster = getHostGuidInTargetCluster(sourcePool.getClusterId(), targetPool, sourceScopeType); } else if (ScopeType.CLUSTER.equals(targetScopeType)) { hostId = findSuitableHostIdForWorkerVmPlacement(targetPool.getClusterId()); if (hostId == null) { @@ -171,6 +189,19 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { return new Pair<>(hostId, hostGuidInTargetCluster); } + private Pair getHostIdForVmAndHostGuidInTargetCluster(VirtualMachine vm, + DataObject srcData, + StoragePool sourcePool, + DataObject destData, + StoragePool targetPool) { + ScopeType sourceScopeType = srcData.getDataStore().getScope().getScopeType(); + ScopeType targetScopeType = destData.getDataStore().getScope().getScopeType(); + if (vm != null) { + return getHostIdForVmAndHostGuidInTargetClusterForAttachedVm(vm, targetPool, targetScopeType); + } + return getHostIdForVmAndHostGuidInTargetClusterForWorkerVm(sourcePool, sourceScopeType, targetPool, targetScopeType); + } + @Override public StrategyPriority canHandle(Map volumeMap, Host srcHost, Host destHost) { if (srcHost.getHypervisorType() == HypervisorType.VMware && destHost.getHypervisorType() == HypervisorType.VMware) { @@ -205,12 +236,15 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { // OfflineVmwareMigration: we shouldn't be here as we would have refused in the canHandle call throw new UnsupportedOperationException(); } - Pair hostIdForVmAndHostGuidInTargetCluster = getHostIdForVmAndHostGuidInTargetCluster(srcData, destData); - Long hostId = hostIdForVmAndHostGuidInTargetCluster.first(); + VirtualMachine vm = getVolumeVm(srcData); StoragePool sourcePool = (StoragePool) srcData.getDataStore(); StoragePool targetPool = (StoragePool) destData.getDataStore(); + Pair hostIdForVmAndHostGuidInTargetCluster = + getHostIdForVmAndHostGuidInTargetCluster(vm, srcData, sourcePool, destData, targetPool); + Long hostId = hostIdForVmAndHostGuidInTargetCluster.first(); MigrateVolumeCommand cmd = new MigrateVolumeCommand(srcData.getId() , srcData.getTO().getPath() + , vm != null ? vm.getInstanceName() : null , sourcePool , targetPool , hostIdForVmAndHostGuidInTargetCluster.second()); @@ -253,9 +287,11 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { VolumeVO sourceVO = volDao.findById(srcData.getId()); sourceVO.setState(Volume.State.Ready); volDao.update(sourceVO.getId(), sourceVO); - destinationVO.setState(Volume.State.Expunged); - destinationVO.setRemoved(new Date()); - volDao.update(destinationVO.getId(), destinationVO); + if (destinationVO.getId() != sourceVO.getId()) { + destinationVO.setState(Volume.State.Expunged); + destinationVO.setRemoved(new Date()); + volDao.update(destinationVO.getId(), destinationVO); + } throw new CloudRuntimeException("unexpected answer from hypervisor agent: " + answer.getDetails()); } MigrateVolumeAnswer ans = (MigrateVolumeAnswer) answer; @@ -264,6 +300,7 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { s_logger.debug(String.format(format, ans.getVolumePath(), destData.getId())); } // OfflineVmwareMigration: update the volume with new pool/volume path + destinationVO.setPoolId(destData.getDataStore().getId()); destinationVO.setPath(ans.getVolumePath()); volDao.update(destinationVO.getId(), destinationVO); } diff --git a/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java b/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java index 4cc3a77baaa..e59c7978fdc 100644 --- a/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java +++ b/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java @@ -16,6 +16,13 @@ // under the License. package org.apache.cloudstack.storage.motion; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -23,17 +30,6 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.MigrateWithStorageAnswer; -import com.cloud.agent.api.MigrateWithStorageCommand; -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.host.Host; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.utils.component.ComponentContext; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.dao.VMInstanceDao; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; @@ -63,12 +59,18 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.MigrateWithStorageAnswer; +import com.cloud.agent.api.MigrateWithStorageCommand; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.VMInstanceDao; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) @@ -87,7 +89,9 @@ public class VmwareStorageMotionStrategyTest { @Inject VMInstanceDao instanceDao; @Inject - private HostDao hostDao; + HostDao hostDao; + @Inject + VirtualMachineManager vmManager; CopyCommandResult result; @@ -268,6 +272,11 @@ public class VmwareStorageMotionStrategyTest { return Mockito.mock(HostDao.class); } + @Bean + public VirtualMachineManager vmManager() { + return Mockito.mock(VirtualMachineManager.class); + } + public static class Library implements TypeFilter { @Override public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 0ac03742046..d612ad53966 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -663,6 +663,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements if (loadBalancer == null) { throw new InvalidParameterException("Invalid Load balancer Id:" + cmd.getLbRuleId()); } + + _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, loadBalancer); + List stickinessPolicies = _lb2stickinesspoliciesDao.listByLoadBalancerId(cmd.getLbRuleId(), false); for (LBStickinessPolicyVO stickinessPolicy : stickinessPolicies) { if (stickinessPolicy.getId() == cmd.getEntityId()) { @@ -717,6 +720,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements if (loadBalancer == null) { throw new InvalidParameterException("Invalid Load balancer Id:" + cmd.getLbRuleId()); } + _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, loadBalancer); FirewallRule.State backupState = loadBalancer.getState(); loadBalancer.setState(FirewallRule.State.Add); _lbDao.persist(loadBalancer); diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index d8f79e52942..cda3e15399d 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -31,7 +31,6 @@ import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import com.cloud.dc.Pod; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; @@ -104,6 +103,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Pod; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.Domain; import com.cloud.event.ActionEvent; @@ -1835,13 +1835,16 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPDATE, eventDescription = "updating volume", async = true) public Volume updateVolume(long volumeId, String path, String state, Long storageId, Boolean displayVolume, String customId, long entityOwnerId, String chainInfo) { - + Account caller = CallContext.current().getCallingAccount(); VolumeVO volume = _volsDao.findById(volumeId); if (volume == null) { throw new InvalidParameterValueException("The volume id doesn't exist"); } + /* Does the caller have authority to act on this volume? */ + _accountMgr.checkAccess(caller, null, true, volume); + if (path != null) { volume.setPath(path); } @@ -2065,6 +2068,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume") public Volume detachVolumeViaDestroyVM(long vmId, long volumeId) { + Account caller = CallContext.current().getCallingAccount(); + Volume volume = _volsDao.findById(volumeId); + // Permissions check + _accountMgr.checkAccess(caller, null, true, volume); return orchestrateDetachVolumeFromVM(vmId, volumeId); } @@ -2254,6 +2261,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_MIGRATE, eventDescription = "migrating volume", async = true) public Volume migrateVolume(MigrateVolumeCmd cmd) { + Account caller = CallContext.current().getCallingAccount(); Long volumeId = cmd.getVolumeId(); Long storagePoolId = cmd.getStoragePoolId(); @@ -2262,6 +2270,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException("Failed to find the volume id: " + volumeId); } + _accountMgr.checkAccess(caller, null, true, vol); + if (vol.getState() != Volume.State.Ready) { throw new InvalidParameterValueException("Volume must be in ready state"); } @@ -2279,13 +2289,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } // Check that Vm to which this volume is attached does not have VM Snapshots - // OfflineVmwareMigration: considder if this is needed and desirable + // OfflineVmwareMigration: consider if this is needed and desirable if (vm != null && _vmSnapshotDao.findByVm(vm.getId()).size() > 0) { throw new InvalidParameterValueException("Volume cannot be migrated, please remove all VM snapshots for VM to which this volume is attached"); } // OfflineVmwareMigration: extract this block as method and check if it is subject to regression - if (vm != null && vm.getState() == State.Running) { + if (vm != null && State.Running.equals(vm.getState())) { // Check if the VM is GPU enabled. if (_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported"); @@ -2321,10 +2331,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic if (!liveMigrateVolume) { throw new InvalidParameterValueException("Volume needs to be detached from VM"); } + + if (!cmd.isLiveMigrate()) { + throw new InvalidParameterValueException("The volume " + vol + "is attached to a vm and for migrating it " + "the parameter livemigrate should be specified"); + } } - if (liveMigrateVolume && !cmd.isLiveMigrate()) { - throw new InvalidParameterValueException("The volume " + vol + "is attached to a vm and for migrating it " + "the parameter livemigrate should be specified"); + if (vm != null && + HypervisorType.VMware.equals(vm.getHypervisorType()) && + State.Stopped.equals(vm.getState())) { + // For VMware, use liveMigrateVolume=true so that it follows VmwareStorageMotionStrategy + liveMigrateVolume = true; } StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); @@ -2361,7 +2378,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic getStoragePoolTags(destPool), vol.getName(), vol.getUuid(), diskOffering.getTags())); } - if (liveMigrateVolume && destPool.getClusterId() != null && srcClusterId != null) { + if (liveMigrateVolume && State.Running.equals(vm.getState()) && + destPool.getClusterId() != null && srcClusterId != null) { if (!srcClusterId.equals(destPool.getClusterId())) { throw new InvalidParameterValueException("Cannot migrate a volume of a virtual machine to a storage pool in a different cluster"); } @@ -2629,11 +2647,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic private Snapshot takeSnapshotInternal(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup) throws ResourceAllocationException { + Account caller = CallContext.current().getCallingAccount(); VolumeInfo volume = volFactory.getVolume(volumeId); if (volume == null) { throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist"); } + _accountMgr.checkAccess(caller, null, true, volume); + if (volume.getState() != Volume.State.Ready) { throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot."); } @@ -2650,6 +2671,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } if (vm != null) { + _accountMgr.checkAccess(caller, null, true, vm); // serialize VM operation AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 630adde57dc..553d9b3cfb9 100755 --- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -335,6 +335,14 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement Boolean display = cmd.getDisplay(); SnapshotPolicyVO policyVO = _snapshotPolicyDao.findById(id); + VolumeInfo volume = volFactory.getVolume(policyVO.getVolumeId()); + if (volume == null) { + throw new InvalidParameterValueException("No such volume exist"); + } + + // does the caller have the authority to act on this volume + _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, volume); + if (display != null) { boolean previousDisplay = policyVO.isDisplay(); policyVO.setDisplay(display); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 57a8fdfe10c..deb5feb2e81 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1648,6 +1648,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, final Long accountId = CallContext.current().getCallingAccountId(); SnapshotVO snapshot = null; VolumeVO volume = null; + Account caller = CallContext.current().getCallingAccount(); try { TemplateInfo tmplInfo = _tmplFactory.getTemplate(templateId, DataStoreRole.Image); @@ -1686,6 +1687,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new CloudRuntimeException("Cannot find snapshot " + snapshotId + " on secondary and could not create backup"); } } + _accountMgr.checkAccess(caller, null, true, snapInfo); DataStore snapStore = snapInfo.getDataStore(); if (snapStore != null) { @@ -1696,7 +1698,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store); } else if (volumeId != null) { VolumeInfo volInfo = _volFactory.getVolume(volumeId); + if (volInfo == null) { + throw new InvalidParameterValueException("No such volume exist"); + } + _accountMgr.checkAccess(caller, null, true, volInfo); future = _tmpltSvr.createTemplateFromVolumeAsync(volInfo, tmplInfo, store); } else { throw new CloudRuntimeException("Creating private Template need to specify snapshotId or volumeId"); diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java index a20090cf7c1..054c3342204 100644 --- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java +++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java @@ -2487,10 +2487,13 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @DB @ActionEvent(eventType = EventTypes.EVENT_REGISTER_FOR_SECRET_API_KEY, eventDescription = "register for the developer API keys") public String[] createApiKeyAndSecretKey(final long userId) { + Account caller = getCurrentCallingAccount(); User user = getUserIncludingRemoved(userId); if (user == null) { throw new InvalidParameterValueException("Unable to find user by id"); } + Account account = _accountDao.findById(user.getAccountId()); + checkAccess(caller, null, true, account); final String[] keys = new String[2]; Transaction.execute(new TransactionCallbackNoReturn() { @Override diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index fc23028735d..238f736bec0 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -50,6 +50,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -3000,6 +3001,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir checkForUnattachedVolumes(vmId, volumesToBeDeleted); validateVolumes(volumesToBeDeleted); + final ControlledEntity[] volumesToDelete = volumesToBeDeleted.toArray(new ControlledEntity[0]); + _accountMgr.checkAccess(ctx.getCallingAccount(), null, true, volumesToDelete); + stopVirtualMachine(vmId, VmDestroyForcestop.value()); detachVolumesFromVm(volumesToBeDeleted); diff --git a/ui/src/components/view/DedicateDomain.vue b/ui/src/components/view/DedicateDomain.vue index 8214922f823..3cdd80434ad 100644 --- a/ui/src/components/view/DedicateDomain.vue +++ b/ui/src/components/view/DedicateDomain.vue @@ -23,7 +23,7 @@

{{ $t('label.required') }}

- {{ domain.name }} + {{ domain.path || domain.name || domain.description }} diff --git a/ui/src/views/compute/AssignInstance.vue b/ui/src/views/compute/AssignInstance.vue index e534bcb3abc..883e4b3e76f 100644 --- a/ui/src/views/compute/AssignInstance.vue +++ b/ui/src/views/compute/AssignInstance.vue @@ -39,7 +39,7 @@

*{{ $t('label.domain') }}

- {{ domain.path }} + {{ domain.path || domain.name || domain.description }} diff --git a/ui/src/views/compute/CreateSSHKeyPair.vue b/ui/src/views/compute/CreateSSHKeyPair.vue index cefac878f31..81fa7c57b7d 100644 --- a/ui/src/views/compute/CreateSSHKeyPair.vue +++ b/ui/src/views/compute/CreateSSHKeyPair.vue @@ -49,7 +49,7 @@ :placeholder="apiParams.domainid.description" @change="val => { this.handleDomainChanged(this.domains[val]) }"> - {{ opt.name || opt.description }} + {{ opt.path || opt.name || opt.description }} diff --git a/ui/src/views/iam/AddAccount.vue b/ui/src/views/iam/AddAccount.vue index db7e734a3a0..bb0359b2372 100644 --- a/ui/src/views/iam/AddAccount.vue +++ b/ui/src/views/iam/AddAccount.vue @@ -145,7 +145,7 @@ rules: [{ required: true, message: $t('message.error.select') }] }]" :placeholder="apiParams.domainid.description"> - {{ domain.name }} + {{ domain.path || domain.name || domain.description }} diff --git a/ui/src/views/iam/AddUser.vue b/ui/src/views/iam/AddUser.vue index 15eb2c1a3db..8ef88eb64ce 100644 --- a/ui/src/views/iam/AddUser.vue +++ b/ui/src/views/iam/AddUser.vue @@ -125,7 +125,7 @@ v-decorator="['domainid']" :placeholder="apiParams.domainid.description"> - {{ domain.name }} + {{ domain.path || domain.name || domain.description }} @@ -218,7 +218,7 @@ export default { domainid: null } }, - beforeCreate () { + created () { this.form = this.$form.createForm(this) this.apiConfig = this.$store.getters.apis.createUser || {} this.apiParams = {} diff --git a/ui/src/views/infra/network/DedicatedVLANTab.vue b/ui/src/views/infra/network/DedicatedVLANTab.vue index 444e9f6d17f..ffb82179581 100644 --- a/ui/src/views/infra/network/DedicatedVLANTab.vue +++ b/ui/src/views/infra/network/DedicatedVLANTab.vue @@ -92,7 +92,7 @@ rules: [{ required: true, message: `${$t('label.required')}` }] }]" > - {{ domain.name }} + {{ domain.path || domain.name || domain.description }} diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 924f5938bec..285152ec6d8 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -125,7 +125,7 @@ {{ domain.name }} + :value="domain.id">{{ domain.path || domain.name || domain.description }} @@ -187,7 +187,7 @@ {{ domain.name }} + :value="domain.id">{{ domain.path || domain.name || domain.description }} diff --git a/ui/src/views/network/CreateIsolatedNetworkForm.vue b/ui/src/views/network/CreateIsolatedNetworkForm.vue index fb2c9f45cf9..135e6bc3ff1 100644 --- a/ui/src/views/network/CreateIsolatedNetworkForm.vue +++ b/ui/src/views/network/CreateIsolatedNetworkForm.vue @@ -97,7 +97,7 @@ :placeholder="this.$t('label.domainid')" @change="val => { this.handleDomainChange(this.domains[val]) }"> - {{ opt.name || opt.description }} + {{ opt.path || opt.name || opt.description }} diff --git a/ui/src/views/network/CreateL2NetworkForm.vue b/ui/src/views/network/CreateL2NetworkForm.vue index f55b4acd1ec..9771e282238 100644 --- a/ui/src/views/network/CreateL2NetworkForm.vue +++ b/ui/src/views/network/CreateL2NetworkForm.vue @@ -97,7 +97,7 @@ :placeholder="this.$t('label.domainid')" @change="val => { this.handleDomainChange(this.domains[val]) }"> - {{ opt.name || opt.description }} + {{ opt.path || opt.name || opt.description }} diff --git a/ui/src/views/network/CreateSharedNetworkForm.vue b/ui/src/views/network/CreateSharedNetworkForm.vue index 248a32b9a58..a28a40f1e7e 100644 --- a/ui/src/views/network/CreateSharedNetworkForm.vue +++ b/ui/src/views/network/CreateSharedNetworkForm.vue @@ -207,7 +207,7 @@ :placeholder="this.$t('label.domainid')" @change="val => { this.handleDomainChange(this.domains[val]) }"> - {{ opt.name || opt.description }} + {{ opt.path || opt.name || opt.description }}