Skip to content

Commit 22cd00f

Browse files
veeam: fix issues with PreSetup and DVS and Solidfire (#9256)
* Veeam: find storage pool by path for PreSetup and VMFS * Veeam: support VMware distributed virtual switch * Veeam: sync volumes on Solidfire after backup restoration user faced the issue that backup is restored but the DATA disk is gone (ROOT disk is ok) ``` 2024-05-03 12:00:32,868 ERROR [o.a.c.b.BackupManagerImpl] (API-Job-Executor-13:ctx-aa8a1d85 job-149661 ctx-73328567) (logid:6510cf06) Failed to import VM [vmInternalName: i-169-9679-VM] from backup restoration [{"backupType":"Full","externalId":"821ca400-a5da-4282-bf3f-7c7e38a6cdb4","id":257,"uuid":"69399101-5cbd-461c-8a48-f0c70eac0b24","vmId":9679}] with hypervisor [type: VMware] due to: [Couldn't find storage pool -iqn.2010-01.com.solidfire:3p53.data-9679.221-0]. ``` On managed storage, the datastore name of DATA disk is determined by the iscsi_name of the volume. * Veeam: set correct path for DATA disks on solidfire
1 parent b22315d commit 22cd00f

File tree

5 files changed

+136
-23
lines changed

5 files changed

+136
-23
lines changed

engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,6 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
156156
VolumeVO findByPoolIdAndPath(long id, String path);
157157

158158
List<VolumeVO> listByIds(List<Long> ids);
159+
160+
VolumeVO findOneByIScsiName(String iScsiName);
159161
}

engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ public VolumeDaoImpl() {
388388
AllFieldsSearch.and("updatedCount", AllFieldsSearch.entity().getUpdatedCount(), Op.EQ);
389389
AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), Op.EQ);
390390
AllFieldsSearch.and("passphraseId", AllFieldsSearch.entity().getPassphraseId(), Op.EQ);
391+
AllFieldsSearch.and("iScsiName", AllFieldsSearch.entity().get_iScsiName(), Op.EQ);
391392
AllFieldsSearch.done();
392393

393394
RootDiskStateSearch = createSearchBuilder();
@@ -840,4 +841,10 @@ public List<VolumeVO> listByIds(List<Long> ids) {
840841
sc.setParameters("idIN", ids.toArray());
841842
return listBy(sc, null);
842843
}
844+
845+
public VolumeVO findOneByIScsiName(String iScsiName) {
846+
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
847+
sc.setParameters("iScsiName", iScsiName);
848+
return findOneIncludingRemovedBy(sc);
849+
}
843850
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
140140

141141
List<StoragePoolVO> findPoolsByStorageType(String storageType);
142142

143+
StoragePoolVO findPoolByZoneAndPath(long zoneId, String datastorePath);
144+
143145
List<StoragePoolVO> listStoragePoolsWithActiveVolumesByOfferingId(long offeringid);
144146

145147
Pair<List<Long>, Integer> searchForIdsAndCount(Long storagePoolId, String storagePoolName, Long zoneId,

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,16 @@ public List<StoragePoolVO> findPoolsByStorageType(String storageType) {
659659
return listBy(sc);
660660
}
661661

662+
@Override
663+
public StoragePoolVO findPoolByZoneAndPath(long zoneId, String datastorePath) {
664+
SearchCriteria<StoragePoolVO> sc = AllFieldSearch.create();
665+
sc.setParameters("datacenterId", zoneId);
666+
if (datastorePath != null) {
667+
sc.addAnd("path", Op.LIKE, "%/" + datastorePath);
668+
}
669+
return findOneBy(sc);
670+
}
671+
662672
@Override
663673
public List<StoragePoolVO> listStoragePoolsWithActiveVolumesByOfferingId(long offeringId) {
664674
TransactionLegacy txn = TransactionLegacy.currentTxn();

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
2020

21+
import java.net.URI;
2122
import java.util.ArrayList;
2223
import java.util.Date;
2324
import java.util.HashMap;
@@ -149,16 +150,22 @@
149150
import com.cloud.vm.dao.UserVmDao;
150151
import com.cloud.vm.dao.VMInstanceDao;
151152
import com.google.gson.Gson;
153+
import com.vmware.vim25.DistributedVirtualPort;
154+
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
155+
import com.vmware.vim25.DistributedVirtualSwitchPortCriteria;
152156
import com.vmware.vim25.ManagedObjectReference;
157+
import com.vmware.vim25.VMwareDVSPortSetting;
153158
import com.vmware.vim25.VirtualDevice;
154159
import com.vmware.vim25.VirtualDeviceBackingInfo;
155160
import com.vmware.vim25.VirtualDeviceConnectInfo;
156161
import com.vmware.vim25.VirtualDisk;
157162
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
158163
import com.vmware.vim25.VirtualEthernetCard;
164+
import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
159165
import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
160166
import com.vmware.vim25.VirtualMachineConfigSummary;
161167
import com.vmware.vim25.VirtualMachineRuntimeInfo;
168+
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
162169

163170
public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable {
164171
private static final Logger s_logger = Logger.getLogger(VMwareGuru.class);
@@ -533,25 +540,43 @@ private void checkBackingInfo(VirtualDeviceBackingInfo backingInfo) {
533540
/**
534541
* Get pool ID from datastore UUID
535542
*/
536-
private Long getPoolIdFromDatastoreUuid(String datastoreUuid) {
537-
String poolUuid = UuidUtils.normalize(datastoreUuid);
538-
StoragePoolVO pool = _storagePoolDao.findByUuid(poolUuid);
543+
private Long getPoolIdFromDatastoreUuid(long zoneId, String datastoreUuid) {
544+
StoragePoolVO pool = null;
545+
try {
546+
String poolUuid = UuidUtils.normalize(datastoreUuid);
547+
s_logger.info("Trying to find pool by UUID: " + poolUuid);
548+
pool = _storagePoolDao.findByUuid(poolUuid);
549+
} catch (CloudRuntimeException ex) {
550+
s_logger.warn("Unable to get pool by datastore UUID: " + ex.getMessage());
551+
}
539552
if (pool == null) {
540-
throw new CloudRuntimeException("Couldn't find storage pool " + poolUuid);
553+
s_logger.info("Trying to find pool by path: " + datastoreUuid);
554+
pool = _storagePoolDao.findPoolByZoneAndPath(zoneId, datastoreUuid);
555+
}
556+
if (pool == null && datastoreUuid.startsWith("-iqn") && datastoreUuid.endsWith("-0")) {
557+
String iScsiName = "/iqn" + datastoreUuid.substring(4, datastoreUuid.length() - 2) + "/0";
558+
s_logger.info("Trying to find volume by iScsi name: " + iScsiName);
559+
VolumeVO volumeVO = _volumeDao.findOneByIScsiName(iScsiName);
560+
if (volumeVO != null) {
561+
pool = _storagePoolDao.findById(volumeVO.getPoolId());
562+
}
563+
}
564+
if (pool == null) {
565+
throw new CloudRuntimeException("Couldn't find storage pool " + datastoreUuid);
541566
}
542567
return pool.getId();
543568
}
544569

545570
/**
546571
* Get pool ID for disk
547572
*/
548-
private Long getPoolId(VirtualDisk disk) {
573+
private Long getPoolId(long zoneId, VirtualDisk disk) {
549574
VirtualDeviceBackingInfo backing = disk.getBacking();
550575
checkBackingInfo(backing);
551576
VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing;
552577
String[] fileNameParts = info.getFileName().split(" ");
553578
String datastoreUuid = StringUtils.substringBetween(fileNameParts[0], "[", "]");
554-
return getPoolIdFromDatastoreUuid(datastoreUuid);
579+
return getPoolIdFromDatastoreUuid(zoneId, datastoreUuid);
555580
}
556581

557582
/**
@@ -588,12 +613,12 @@ private VirtualMachineMO getTemplate(DatacenterMO dcMo, String templatePath) thr
588613
/**
589614
* Get template pool ID
590615
*/
591-
private Long getTemplatePoolId(VirtualMachineMO template) throws Exception {
616+
private Long getTemplatePoolId(long zoneId, VirtualMachineMO template) throws Exception {
592617
VirtualMachineConfigSummary configSummary = template.getConfigSummary();
593618
String vmPathName = configSummary.getVmPathName();
594619
String[] pathParts = vmPathName.split(" ");
595620
String dataStoreUuid = pathParts[0].replace("[", "").replace("]", "");
596-
return getPoolIdFromDatastoreUuid(dataStoreUuid);
621+
return getPoolIdFromDatastoreUuid(zoneId, dataStoreUuid);
597622
}
598623

599624
/**
@@ -643,14 +668,14 @@ private void updateTemplateRef(long templateId, Long poolId, String templatePath
643668
/**
644669
* Get template ID for VM being imported. If it is not found, it is created
645670
*/
646-
private Long getImportingVMTemplate(List<VirtualDisk> virtualDisks, DatacenterMO dcMo, String vmInternalName, Long guestOsId, long accountId, Map<VirtualDisk, VolumeVO> disksMapping, Backup backup) throws Exception {
671+
private Long getImportingVMTemplate(List<VirtualDisk> virtualDisks, long zoneId, DatacenterMO dcMo, String vmInternalName, Long guestOsId, long accountId, Map<VirtualDisk, VolumeVO> disksMapping, Backup backup) throws Exception {
647672
for (VirtualDisk disk : virtualDisks) {
648673
if (isRootDisk(disk, disksMapping, backup)) {
649674
VolumeVO volumeVO = disksMapping.get(disk);
650675
if (volumeVO == null) {
651676
String templatePath = getRootDiskTemplatePath(disk);
652677
VirtualMachineMO template = getTemplate(dcMo, templatePath);
653-
Long poolId = getTemplatePoolId(template);
678+
Long poolId = getTemplatePoolId(zoneId, template);
654679
Long templateSize = getTemplateSize(template, vmInternalName, disksMapping, backup);
655680
long templateId = getTemplateId(templatePath, vmInternalName, guestOsId, accountId);
656681
updateTemplateRef(templateId, poolId, templatePath, templateSize);
@@ -744,7 +769,11 @@ private long getDiskOfferingId(long size, Storage.ProvisioningType provisioningT
744769
protected VolumeVO updateVolume(VirtualDisk disk, Map<VirtualDisk, VolumeVO> disksMapping, VirtualMachineMO vmToImport, Long poolId, VirtualMachine vm) throws Exception {
745770
VolumeVO volume = disksMapping.get(disk);
746771
String volumeName = getVolumeName(disk, vmToImport);
747-
volume.setPath(volumeName);
772+
if (volume.get_iScsiName() != null) {
773+
volume.setPath(String.format("[%s] %s.vmdk", volumeName, volumeName));
774+
} else {
775+
volume.setPath(volumeName);
776+
}
748777
volume.setPoolId(poolId);
749778
VirtualMachineDiskInfo diskInfo = getDiskInfo(vmToImport, poolId, volumeName);
750779
volume.setChainInfo(GSON.toJson(diskInfo));
@@ -779,7 +808,7 @@ private void syncVMVolumes(VMInstanceVO vmInstanceVO, List<VirtualDisk> virtualD
779808

780809
String operation = "";
781810
for (VirtualDisk disk : virtualDisks) {
782-
Long poolId = getPoolId(disk);
811+
Long poolId = getPoolId(zoneId, disk);
783812
Volume volume = null;
784813
if (disksMapping.containsKey(disk) && disksMapping.get(disk) != null) {
785814
volume = updateVolume(disk, disksMapping, vmToImport, poolId, vmInstanceVO);
@@ -903,8 +932,13 @@ private Map<String, NetworkVO> getNetworksMapping(String[] vmNetworkNames, long
903932
Map<String, NetworkVO> mapping = new HashMap<>();
904933
for (String networkName : vmNetworkNames) {
905934
NetworkVO networkVO = getGuestNetworkFromNetworkMorName(networkName, accountId, zoneId, domainId);
906-
s_logger.debug(String.format("Mapping network name [%s] to networkVO [id: %s].", networkName, networkVO.getUuid()));
907-
mapping.put(networkName, networkVO);
935+
URI broadcastUri = networkVO.getBroadcastUri();
936+
if (broadcastUri == null) {
937+
continue;
938+
}
939+
String vlan = broadcastUri.getHost();
940+
s_logger.debug(String.format("Mapping network vlan [%s] to networkVO [id: %s].", vlan, networkVO.getUuid()));
941+
mapping.put(vlan, networkVO);
908942
}
909943
return mapping;
910944
}
@@ -914,30 +948,88 @@ private Map<String, NetworkVO> getNetworksMapping(String[] vmNetworkNames, long
914948
*/
915949
private NetworkMO getNetworkMO(VirtualEthernetCard nic, VmwareContext context) {
916950
VirtualDeviceConnectInfo connectable = nic.getConnectable();
917-
VirtualEthernetCardNetworkBackingInfo info = (VirtualEthernetCardNetworkBackingInfo)nic.getBacking();
951+
VirtualEthernetCardNetworkBackingInfo info = (VirtualEthernetCardNetworkBackingInfo) nic.getBacking();
918952
ManagedObjectReference networkMor = info.getNetwork();
919953
if (networkMor == null) {
920954
throw new CloudRuntimeException("Could not find network for NIC on: " + nic.getMacAddress());
921955
}
922956
return new NetworkMO(context, networkMor);
923957
}
924958

925-
private Pair<String, String> getNicMacAddressAndNetworkName(VirtualDevice nicDevice, VmwareContext context) throws Exception {
959+
private Pair<String, String> getNicMacAddressAndVlan(VirtualDevice nicDevice, VmwareContext context) throws Exception {
926960
VirtualEthernetCard nic = (VirtualEthernetCard)nicDevice;
927961
String macAddress = nic.getMacAddress();
928-
NetworkMO networkMO = getNetworkMO(nic, context);
929-
String networkName = networkMO.getName();
930-
return new Pair<>(macAddress, networkName);
962+
VirtualDeviceBackingInfo backing = nic.getBacking();
963+
if (backing instanceof VirtualEthernetCardNetworkBackingInfo) {
964+
VirtualEthernetCardNetworkBackingInfo backingInfo = (VirtualEthernetCardNetworkBackingInfo) backing;
965+
String deviceName = backingInfo.getDeviceName();
966+
String vlan = getVlanFromDeviceName(deviceName);
967+
return new Pair<>(macAddress, vlan);
968+
} else if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) {
969+
VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing;
970+
DistributedVirtualSwitchPortConnection port = portInfo.getPort();
971+
String portKey = port.getPortKey();
972+
String portGroupKey = port.getPortgroupKey();
973+
String dvSwitchUuid = port.getSwitchUuid();
974+
String vlan = getVlanFromDvsPort(context, dvSwitchUuid, portGroupKey, portKey);
975+
return new Pair<>(macAddress, vlan);
976+
}
977+
return new Pair<>(macAddress, null);
978+
}
979+
980+
private String getVlanFromDeviceName(String networkName) {
981+
String prefix = "cloud.guest.";
982+
if (!networkName.startsWith(prefix)) {
983+
return null;
984+
}
985+
String nameWithoutPrefix = networkName.replace(prefix, "");
986+
String[] parts = nameWithoutPrefix.split("\\.");
987+
String vlan = parts[0];
988+
return vlan;
989+
}
990+
991+
private String getVlanFromDvsPort(VmwareContext context, String dvSwitchUuid, String portGroupKey, String portKey) {
992+
try {
993+
ManagedObjectReference dvSwitchManager = context.getVimClient().getServiceContent().getDvSwitchManager();
994+
ManagedObjectReference dvSwitch = context.getVimClient().getService().queryDvsByUuid(dvSwitchManager, dvSwitchUuid);
995+
996+
// Get all ports
997+
DistributedVirtualSwitchPortCriteria criteria = new DistributedVirtualSwitchPortCriteria();
998+
criteria.setInside(true);
999+
criteria.getPortgroupKey().add(portGroupKey);
1000+
List<DistributedVirtualPort> dvPorts = context.getVimClient().getService().fetchDVPorts(dvSwitch, criteria);
1001+
1002+
for (DistributedVirtualPort dvPort : dvPorts) {
1003+
if (!portKey.equals(dvPort.getKey())) {
1004+
continue;
1005+
}
1006+
VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPort.getConfig().getSetting();
1007+
VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan();
1008+
s_logger.debug("Found port " + dvPort.getKey() + " with vlan " + vlanId.getVlanId());
1009+
return String.valueOf(vlanId.getVlanId());
1010+
}
1011+
} catch (Exception ex) {
1012+
s_logger.error("Got exception while get vlan from DVS port: " + ex.getMessage());
1013+
}
1014+
return null;
9311015
}
9321016

9331017
private void syncVMNics(VirtualDevice[] nicDevices, DatacenterMO dcMo, Map<String, NetworkVO> networksMapping, VMInstanceVO vm) throws Exception {
9341018
VmwareContext context = dcMo.getContext();
9351019
List<NicVO> allNics = nicDao.listByVmId(vm.getId());
9361020
for (VirtualDevice nicDevice : nicDevices) {
937-
Pair<String, String> pair = getNicMacAddressAndNetworkName(nicDevice, context);
1021+
Pair<String, String> pair = getNicMacAddressAndVlan(nicDevice, context);
9381022
String macAddress = pair.first();
939-
String networkName = pair.second();
940-
NetworkVO networkVO = networksMapping.get(networkName);
1023+
String vlanId = pair.second();
1024+
if (vlanId == null) {
1025+
s_logger.warn(String.format("vlanId for MAC address [%s] is null", macAddress));
1026+
continue;
1027+
}
1028+
NetworkVO networkVO = networksMapping.get(vlanId);
1029+
if (networkVO == null) {
1030+
s_logger.warn(String.format("Cannot find network for MAC address [%s] and vlanId [%s]", macAddress, vlanId));
1031+
continue;
1032+
}
9411033
NicVO nicVO = nicDao.findByNetworkIdAndMacAddressIncludingRemoved(networkVO.getId(), macAddress);
9421034
if (nicVO != null) {
9431035
s_logger.warn(String.format("Find NIC in DB with networkId [%s] and MAC Address [%s], so this NIC will be removed from list of unmapped NICs of VM [id: %s, name: %s].",
@@ -1068,7 +1160,7 @@ public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId,
10681160

10691161
long guestOsId = getImportingVMGuestOs(configSummary);
10701162
long serviceOfferingId = getImportingVMServiceOffering(configSummary, runtimeInfo);
1071-
long templateId = getImportingVMTemplate(virtualDisks, dcMo, vmInternalName, guestOsId, accountId, disksMapping, backup);
1163+
long templateId = getImportingVMTemplate(virtualDisks, zoneId, dcMo, vmInternalName, guestOsId, accountId, disksMapping, backup);
10721164

10731165
VMInstanceVO vm = getVM(vmInternalName, templateId, guestOsId, serviceOfferingId, zoneId, accountId, userId, domainId);
10741166
syncVMVolumes(vm, virtualDisks, disksMapping, vmToImport, backup);

0 commit comments

Comments
 (0)