diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index 9cb37f576bb..77c45b26b7d 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -29,10 +29,16 @@ import javax.inject.Inject; import org.apache.log4j.Logger; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.DeleteCommand; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import com.cloud.agent.api.BackupSnapshotCommand; @@ -48,6 +54,7 @@ import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.cluster.ClusterManager; @@ -76,7 +83,10 @@ import com.cloud.secstorage.CommandExecLogVO; import com.cloud.storage.DataStoreRole; import com.cloud.storage.GuestOSVO; import com.cloud.storage.Storage; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.utils.Pair; @@ -123,6 +133,12 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co private VMInstanceDao _vmDao; @Inject private ClusterManager _clusterMgr; + @Inject + VolumeDao _volumeDao; + @Inject + PrimaryDataStoreDao _storagePoolDao; + @Inject + VolumeDataFactory _volFactory; protected VMwareGuru() { super(); @@ -476,4 +492,43 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co public ConfigKey[] getConfigKeys() { return new ConfigKey[] {VmwareReserveCpu, VmwareReserveMemory}; } + + @Override + public List finalizeExpungeVolumes(VirtualMachine vm) { + List commands = new ArrayList(); + + List volumes = _volumeDao.findByInstance(vm.getId()); + + if (volumes != null) { + for (VolumeVO volume : volumes) { + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + + // storagePool should be null if we are expunging a volume that was never + // attached to a VM that was started (the "trick" for storagePool to be null + // is that none of the VMs this volume may have been attached to were ever started, + // so the volume was never assigned to a storage pool) + if (storagePool != null && storagePool.isManaged() && volume.getVolumeType() == Volume.Type.ROOT) { + VolumeInfo volumeInfo = _volFactory.getVolume(volume.getId()); + PrimaryDataStore primaryDataStore = (PrimaryDataStore)volumeInfo.getDataStore(); + Map details = primaryDataStore.getDetails(); + + if (details == null) { + details = new HashMap(); + + primaryDataStore.setDetails(details); + } + + details.put(DiskTO.MANAGED, Boolean.TRUE.toString()); + + DeleteCommand cmd = new DeleteCommand(volumeInfo.getTO()); + + commands.add(cmd); + + break; + } + } + } + + return commands; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index f84d6824386..85fe91b69cb 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1412,9 +1412,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa DiskTO[] disks = validateDisks(vmSpec.getDisks()); assert (disks.length > 0); NicTO[] nics = vmSpec.getNics(); - Map iqnToPath = new HashMap(); - HashMap> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks, iqnToPath, cmd); + HashMap> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks, cmd); if ((dataStoresDetails == null) || (dataStoresDetails.isEmpty())) { String msg = "Unable to locate datastore details of the volumes to be attached"; s_logger.error(msg); @@ -1471,9 +1470,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa Pair rootDiskDataStoreDetails = null; for (DiskTO vol : disks) { if (vol.getType() == Volume.Type.ROOT) { - DataStoreTO primaryStore = vol.getData().getDataStore(); - /** @todo Mike T. update this in 4.4 to support root disks on managed storage */ - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + if (managed) { + String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); + + rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); + } + else { + DataStoreTO primaryStore = vol.getData().getDataStore(); + + rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + } } } @@ -1759,7 +1772,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMask)); postNvpConfigBeforeStart(vmMo, vmSpec); - postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey); + + Map iqnToPath = new HashMap(); + + postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToPath); // // Power-on VM @@ -1891,7 +1907,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa final String datastoreDiskPath; if (isManaged) { - datastoreDiskPath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); + if (volumeTO.getVolumeType() == Volume.Type.ROOT) { + datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, dsMo.getName()); + } + else { + datastoreDiskPath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); + } } else { datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getPath()); } @@ -2177,9 +2198,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return controllerKey; } - private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, int ideControllerKey, int scsiControllerKey) - throws Exception { - + private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, int ideControllerKey, + int scsiControllerKey, Map iqnToPath) throws Exception { VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); for (DiskTO vol : sortedDisks) { @@ -2194,14 +2214,45 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String[] diskChain = diskInfo.getDiskChain(); assert (diskChain.length > 0); + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + DatastoreFile file = new DatastoreFile(diskChain[0]); - if (!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) { - if (s_logger.isInfoEnabled()) - s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + file.getFileBaseName()); + + if (managed) { + DatastoreFile originalFile = new DatastoreFile(volumeTO.getPath()); + + if (!file.getFileBaseName().equalsIgnoreCase(originalFile.getFileBaseName())) { + if (s_logger.isInfoEnabled()) + s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + diskChain[0]); + } + } + else { + if (!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) { + if (s_logger.isInfoEnabled()) + s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + file.getFileBaseName()); + } } VolumeObjectTO volInSpec = getVolumeInSpec(vmSpec, volumeTO); - volInSpec.setPath(file.getFileBaseName()); + + if (managed) { + String datastoreVolumePath = diskChain[0]; + + iqnToPath.put(details.get(DiskTO.IQN), datastoreVolumePath); + + vol.setPath(datastoreVolumePath); + volumeTO.setPath(datastoreVolumePath); + volInSpec.setPath(datastoreVolumePath); + } + else { + volInSpec.setPath(file.getFileBaseName()); + } + volInSpec.setChainInfo(_gson.toJson(diskInfo)); } } @@ -2263,7 +2314,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, - DiskTO[] disks, Map iqnToPath, Command cmd) throws Exception { + DiskTO[] disks, Command cmd) throws Exception { HashMap> mapIdToMors = new HashMap>(); assert (hyperHost != null) && (context != null); @@ -2299,8 +2350,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDatastore); String datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); - iqnToPath.put(iScsiName, datastoreVolumePath); - volumeTO.setPath(datastoreVolumePath); vol.setPath(datastoreVolumePath); } @@ -3462,6 +3511,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } addRemoveInternetScsiTargetsToAllHosts(false, lstManagedTargets, lstHosts); + + rescanAllHosts(lstHosts); } private void addRemoveInternetScsiTargetsToAllHosts(final boolean add, final List lstTargets, @@ -4281,7 +4332,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa public Answer execute(DeleteCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource DestroyCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource DeleteCommand: " + _gson.toJson(cmd)); } /* diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 9d86b16d6a4..86e655467bd 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -1420,10 +1421,17 @@ public class VmwareStorageProcessor implements StorageProcessor { return new CreateObjectAnswer(newSnapshot); } + // format: [datastore_name] file_name.vmdk (the '[' and ']' chars should only be used to denote the datastore) + private String getManagedDatastoreNameFromPath(String path) { + int lastIndexOf = path.lastIndexOf("]"); + + return path.substring(1, lastIndexOf); + } + @Override public Answer deleteVolume(DeleteCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource DestroyCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource DeleteCommand: " + _gson.toJson(cmd)); } try { @@ -1431,8 +1439,23 @@ public class VmwareStorageProcessor implements StorageProcessor { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null); VolumeObjectTO vol = (VolumeObjectTO)cmd.getData(); DataStoreTO store = vol.getDataStore(); + PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO)store; + + Map details = primaryDataStoreTO.getDetails(); + boolean isManaged = false; + String managedDatastoreName = null; + + if (details != null) { + isManaged = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.MANAGED)); + + if (isManaged) { + managedDatastoreName = getManagedDatastoreNameFromPath(vol.getPath()); + } + } + + ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, + isManaged ? managedDatastoreName : store.getUuid()); - ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, store.getUuid()); if (morDs == null) { String msg = "Unable to find datastore based on volume mount point " + store.getUuid(); s_logger.error(msg);