Updated Branches: refs/heads/master a3cec3802 -> 449b5daa7
VMware changes related to managed storage Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/449b5daa Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/449b5daa Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/449b5daa Branch: refs/heads/master Commit: 449b5daa70f033128f014942e9dcbacd15b09181 Parents: a3cec38 Author: Mike Tutkowski <[email protected]> Authored: Thu Oct 31 08:27:30 2013 -0600 Committer: Mike Tutkowski <[email protected]> Committed: Thu Oct 31 08:30:50 2013 -0600 ---------------------------------------------------------------------- .../vmware/manager/VmwareHostService.java | 3 + .../vmware/resource/VmwareResource.java | 69 +++++++++++++++++--- .../VmwareSecondaryStorageResourceHandler.java | 4 ++ .../resource/VmwareStorageProcessor.java | 51 ++++++++++++++- .../SolidFirePrimaryDataStoreLifeCycle.java | 2 + .../com/cloud/storage/VolumeApiServiceImpl.java | 15 ++++- .../hypervisor/vmware/mo/VirtualMachineMO.java | 16 ++++- 7 files changed, 147 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java index d0147d1..d5a2284 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.hypervisor.vmware.manager; +import java.util.List; + import com.cloud.agent.api.Command; import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; @@ -33,4 +35,5 @@ public interface VmwareHostService { String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception; void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception; void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception; + void removeManagedTargetsFromCluster(List<String> managedIqns) throws Exception; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java ---------------------------------------------------------------------- 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 6d3d34a..a205fb6 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 @@ -2985,7 +2985,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore(); - + Map<String, String> details = vol.getDetails(); + boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid()); if(volumeDsDetails == null) throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); @@ -2997,17 +2999,25 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String disks[] = diskInfo.getDiskChain(); for(int i = 0; i < disks.length; i++) { DatastoreFile file = new DatastoreFile(disks[i]); - if(file.getDir() != null && file.getDir().isEmpty()) { + if (!isManaged && file.getDir() != null && file.getDir().isEmpty()) { s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder"); disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder( dcMo, vmMo.getName(), dsMo, file.getFileBaseName()); } } return disks; - } - - String datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder( - dcMo, vmMo.getName(), dsMo, volumeTO.getPath()); + } + + final String datastoreDiskPath; + + if (isManaged) { + datastoreDiskPath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); + } + else { + datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder( + dcMo, vmMo.getName(), dsMo, volumeTO.getPath()); + } + if(!dsMo.fileExists(datastoreDiskPath)) { s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath); } @@ -3223,7 +3233,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if(diskInfoBuilder != null) { VolumeObjectTO volume = (VolumeObjectTO)vol.getData(); - VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(volume.getPath()); + Map<String, String> details = vol.getDetails(); + boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(isManaged ? new DatastoreFile(volume.getPath()).getFileBaseName() : volume.getPath()); if(diskInfo != null) { s_logger.info("Found existing disk info from volume path: " + volume.getPath()); return diskInfo; @@ -3421,7 +3434,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore(); String poolUuid = primaryStore.getUuid(); if(poolMors.get(poolUuid) == null) { - ManagedObjectReference morDataStore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid); + boolean isManaged = false; + String iScsiName = null; + Map<String, String> details = vol.getDetails(); + + if (details != null) { + isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + iScsiName = details.get(DiskTO.IQN); + } + + ManagedObjectReference morDataStore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : poolUuid); if (morDataStore == null) { String msg = "Failed to get the mounted datastore for the volume's pool " + poolUuid; s_logger.error(msg); @@ -4534,7 +4556,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName()); if (!dsMo.fileExists(volumeDatastorePath)) { - createVmdk(cmd, dsMo, VmwareResource.getDatastoreName(cmd.get_iScsiName()), cmd.getVolumeSize()); + createVmdk(cmd, dsMo, volumeDatastorePath, cmd.getVolumeSize()); } } else { @@ -4592,6 +4614,35 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + @Override + public void removeManagedTargetsFromCluster(List<String> iqns) throws Exception { + List<HostInternetScsiHbaStaticTarget> lstManagedTargets = new ArrayList<HostInternetScsiHbaStaticTarget>(); + + VmwareContext context = getServiceContext(); + VmwareHypervisorHost hyperHost = getHyperHost(context); + ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); + ClusterMO cluster = new ClusterMO(context, morCluster); + List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts(); + HostMO host = new HostMO(context, lstHosts.get(0).first()); + HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); + + for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) { + if (hba instanceof HostInternetScsiHba) { + List<HostInternetScsiHbaStaticTarget> lstTargets = ((HostInternetScsiHba)hba).getConfiguredStaticTarget(); + + if (lstTargets != null) { + for (HostInternetScsiHbaStaticTarget target : lstTargets) { + if (iqns.contains(target.getIScsiName())) { + lstManagedTargets.add(target); + } + } + } + } + } + + addRemoveInternetScsiTargetsToAllHosts(false, lstManagedTargets, lstHosts); + } + private void addRemoveInternetScsiTargetsToAllHosts(final boolean add, final List<HostInternetScsiHbaStaticTarget> lstTargets, final List<Pair<ManagedObjectReference, String>> lstHosts) throws Exception { VmwareContext context = getServiceContext(); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index c84813f..81f7bd9 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -360,4 +360,8 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe public void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception { throw new OperationNotSupportedException(); } + + public void removeManagedTargetsFromCluster(List<String> managedIqns) throws Exception { + throw new OperationNotSupportedException(); + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java ---------------------------------------------------------------------- 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 71ba4e9..70a8769 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -23,6 +23,7 @@ import java.io.OutputStreamWriter; import java.net.URI; import java.rmi.RemoteException; import java.util.HashMap; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -79,6 +80,7 @@ import com.cloud.vm.VirtualMachine.State; import com.google.gson.Gson; import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.VirtualDisk; +import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo; public class VmwareStorageProcessor implements StorageProcessor { private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); @@ -1194,7 +1196,7 @@ public class VmwareStorageProcessor implements StorageProcessor { Map<String, String> details = disk.getDetails(); morDs = hostService.getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort, - VmwareResource.trimIqn(iScsiName), details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), + VmwareResource.trimIqn(iScsiName), details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET)); DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs); @@ -1202,7 +1204,7 @@ public class VmwareStorageProcessor implements StorageProcessor { String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName()); if (!dsMo.fileExists(volumeDatastorePath)) { - hostService.createVmdk(cmd, dsMo, VmwareResource.getDatastoreName(iScsiName), volumeTO.getSize()); + hostService.createVmdk(cmd, dsMo, volumeDatastorePath, volumeTO.getSize()); } } else { @@ -1498,6 +1500,14 @@ public class VmwareStorageProcessor implements StorageProcessor { vmMo.safePowerOff(_shutdown_waitMs); } + // call this before calling detachAllDisksExcept + // when expunging a VM, we need to see if any of its disks are serviced by managed storage + // if there is one or more disk serviced by managed storage, remove the iSCSI connection(s) + // don't remove the iSCSI connection(s) until the supported disk(s) is/are removed from the VM + // (removeManagedTargetsFromCluster should be called after detachAllDisksExcept and vm.destroy) + List<VirtualDisk> virtualDisks = vmMo.getVirtualDisks(); + List<String> managedIqns = getManagedIqnsFromVirtualDisks(virtualDisks); + List<String> detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null); VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks); @@ -1505,6 +1515,9 @@ public class VmwareStorageProcessor implements StorageProcessor { // vmMo.tearDownDevices(new Class<?>[] { VirtualDisk.class, VirtualEthernetCard.class }); vmMo.destroy(); + // this.hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort); + this.hostService.removeManagedTargetsFromCluster(managedIqns); + for (NetworkDetails netDetails : networks) { if (netDetails.getGCTag() != null && netDetails.getGCTag().equalsIgnoreCase("true")) { if (netDetails.getVMMorsOnNetwork() == null || netDetails.getVMMorsOnNetwork().length == 1) { @@ -1555,6 +1568,40 @@ public class VmwareStorageProcessor implements StorageProcessor { } } + private List<String> getManagedIqnsFromVirtualDisks(List<VirtualDisk> virtualDisks) { + List<String> managedIqns = new ArrayList<String>(); + + if (virtualDisks != null) { + for (VirtualDisk virtualDisk : virtualDisks) { + if (virtualDisk.getBacking() instanceof VirtualDiskFlatVer2BackingInfo) { + VirtualDiskFlatVer2BackingInfo backingInfo = (VirtualDiskFlatVer2BackingInfo)virtualDisk.getBacking(); + String path = backingInfo.getFileName(); + + path = new DatastoreFile(path).getFileBaseName(); + + String search = "-"; + int index = path.indexOf(search); + + if (index > -1) { + path = path.substring(index + search.length()); + + index = path.lastIndexOf(search); + + if (index > -1) { + path = path.substring(0, index); + + if (path.startsWith("iqn.")) { + managedIqns.add(path); + } + } + } + } + } + } + + return managedIqns; + } + private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, String backupName) throws Exception { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java index 120a357..be43e1c 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -317,10 +317,12 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC dataStoreHelper.attachZone(dataStore); List<HostVO> xenServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.XenServer, scope.getScopeId()); + List<HostVO> vmWareServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.VMware, scope.getScopeId()); List<HostVO> kvmHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.KVM, scope.getScopeId()); List<HostVO> hosts = new ArrayList<HostVO>(); hosts.addAll(xenServerHosts); + hosts.addAll(vmWareServerHosts); hosts.addAll(kvmHosts); for (HostVO host : hosts) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/server/src/com/cloud/storage/VolumeApiServiceImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index d445381..28df219 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -1233,6 +1233,19 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic String errorMsg = "Failed to detach volume: " + volume.getName() + " from VM: " + vm.getHostName(); boolean sendCommand = (vm.getState() == State.Running); + + Long hostId = vm.getHostId(); + + if (hostId == null) { + hostId = vm.getLastHostId(); + + HostVO host = _hostDao.findById(hostId); + + if (host != null && host.getHypervisorType() == HypervisorType.VMware) { + sendCommand = true; + } + } + Answer answer = null; if (sendCommand) { @@ -1251,7 +1264,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic cmd.set_iScsiName(volume.get_iScsiName()); try { - answer = _agentMgr.send(vm.getHostId(), cmd); + answer = _agentMgr.send(hostId, cmd); } catch (Exception e) { throw new CloudRuntimeException(errorMsg + " due to: " + e.getMessage()); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/449b5daa/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index a9536cf..784c031 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -1985,7 +1985,21 @@ public class VirtualMachineMO extends BaseMO { } throw new Exception("Unable to find device controller"); } - + + public List<VirtualDisk> getVirtualDisks() throws Exception { + List<VirtualDisk> virtualDisks = new ArrayList<VirtualDisk>(); + + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + + for (VirtualDevice device : devices) { + if (device instanceof VirtualDisk) { + virtualDisks.add((VirtualDisk)device); + } + } + + return virtualDisks; + } + public List<String> detachAllDisksExcept(String vmdkBaseName, String deviceBusName) throws Exception { List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
