From 48786b2d312550e7b724783b9ac2f3ca5c58e186 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Mon, 13 Jul 2020 22:14:01 +0530 Subject: [PATCH] DataStore Clusters addition as a storage pool --- .../main/java/com/cloud/storage/Storage.java | 7 +- .../java/com/cloud/storage/StorageTest.java | 2 + .../provider/DefaultHostListener.java | 32 ++--- .../vmware/resource/VmwareResource.java | 123 +++++++++------- .../resource/VmwareStorageProcessor.java | 2 +- ...oudStackPrimaryDataStoreLifeCycleImpl.java | 56 ++++---- .../hypervisor/vmware/mo/DatastoreMO.java | 21 +-- .../vmware/mo/HostDatastoreSystemMO.java | 135 +++++++++++++++++- .../cloud/hypervisor/vmware/mo/HostMO.java | 16 ++- .../vmware/mo/HypervisorHostHelper.java | 16 ++- .../hypervisor/vmware/util/VmwareContext.java | 18 +++ 11 files changed, 305 insertions(+), 123 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java index 82bc5f6d4e5..7a229b67674 100644 --- a/api/src/main/java/com/cloud/storage/Storage.java +++ b/api/src/main/java/com/cloud/storage/Storage.java @@ -16,11 +16,11 @@ // under the License. package com.cloud.storage; +import org.apache.commons.lang.NotImplementedException; + import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang.NotImplementedException; - public class Storage { public static enum ImageFormat { QCOW2(true, true, false, "qcow2"), @@ -135,7 +135,8 @@ public class Storage { OCFS2(true, false), SMB(true, false), Gluster(true, false), - ManagedNFS(true, false); + ManagedNFS(true, false), + DatastoreCluster(true, true); // for VMware, to abstract pool of clusters private final boolean shared; private final boolean overprovisioning; diff --git a/api/src/test/java/com/cloud/storage/StorageTest.java b/api/src/test/java/com/cloud/storage/StorageTest.java index 332a8060d08..c57130f5418 100644 --- a/api/src/test/java/com/cloud/storage/StorageTest.java +++ b/api/src/test/java/com/cloud/storage/StorageTest.java @@ -45,6 +45,7 @@ public class StorageTest { Assert.assertTrue(StoragePoolType.SMB.isShared()); Assert.assertTrue(StoragePoolType.Gluster.isShared()); Assert.assertTrue(StoragePoolType.ManagedNFS.isShared()); + Assert.assertTrue(StoragePoolType.DatastoreCluster.isShared()); } @Test @@ -66,5 +67,6 @@ public class StorageTest { Assert.assertFalse(StoragePoolType.SMB.supportsOverProvisioning()); Assert.assertFalse(StoragePoolType.Gluster.supportsOverProvisioning()); Assert.assertFalse(StoragePoolType.ManagedNFS.supportsOverProvisioning()); + Assert.assertFalse(StoragePoolType.DatastoreCluster.supportsOverProvisioning()); } } diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index 1b9682a2fa3..3ba45191147 100644 --- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -18,20 +18,6 @@ */ package org.apache.cloudstack.storage.datastore.provider; -import java.util.List; - -import javax.inject.Inject; - -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolAnswer; @@ -43,6 +29,17 @@ import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.List; public class DefaultHostListener implements HypervisorHostListener { private static final Logger s_logger = Logger.getLogger(DefaultHostListener.class); @@ -108,8 +105,11 @@ public class DefaultHostListener implements HypervisorHostListener { poolVO.setUsedBytes(mspAnswer.getPoolInfo().getCapacityBytes() - mspAnswer.getPoolInfo().getAvailableBytes()); poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); if(StringUtils.isNotEmpty(mspAnswer.getPoolType())) { - StoragePoolDetailVO storagePoolDetailVO = new StoragePoolDetailVO(poolId, "pool_type", mspAnswer.getPoolType(), false); - storagePoolDetailsDao.persist(storagePoolDetailVO); + StoragePoolDetailVO poolType = storagePoolDetailsDao.findDetail(poolId, "pool_type"); + if (poolType == null) { + StoragePoolDetailVO storagePoolDetailVO = new StoragePoolDetailVO(poolId, "pool_type", mspAnswer.getPoolType(), false); + storagePoolDetailsDao.persist(storagePoolDetailVO); + } } primaryStoreDao.update(pool.getId(), poolVO); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 1230fa8fe1a..ffeebc7c5f3 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -16,50 +16,9 @@ // under the License. package com.cloud.hypervisor.vmware.resource; -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URL; -import java.nio.channels.SocketChannel; -import java.rmi.RemoteException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.TimeZone; -import java.util.UUID; - -import javax.naming.ConfigurationException; -import javax.xml.datatype.XMLGregorianCalendar; - import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.storage.command.CopyCommand; -import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.configdrive.ConfigDrive; -import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; -import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; -import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo; -import org.apache.cloudstack.vm.UnmanagedInstanceTO; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.math.NumberUtils; -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; -import org.joda.time.Duration; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; @@ -297,6 +256,7 @@ import com.vmware.vim25.PerfMetricIntSeries; import com.vmware.vim25.PerfMetricSeries; import com.vmware.vim25.PerfQuerySpec; import com.vmware.vim25.RuntimeFaultFaultMsg; +import com.vmware.vim25.StoragePodSummary; import com.vmware.vim25.ToolsUnavailableFaultMsg; import com.vmware.vim25.VAppOvfSectionInfo; import com.vmware.vim25.VAppOvfSectionSpec; @@ -340,6 +300,46 @@ import com.vmware.vim25.VmConfigSpec; import com.vmware.vim25.VmfsDatastoreInfo; import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.StorageSubSystemCommand; +import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo; +import org.apache.cloudstack.vm.UnmanagedInstanceTO; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; +import org.joda.time.Duration; + +import javax.naming.ConfigurationException; +import javax.xml.datatype.XMLGregorianCalendar; +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URL; +import java.nio.channels.SocketChannel; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; import static com.cloud.utils.HumanReadableJson.getHumanReadableBytesJson; import static com.cloud.utils.NumbersUtil.toHumanReadableSize; @@ -4901,7 +4901,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); StorageFilerTO pool = cmd.getPool(); - if (pool.getType() != StoragePoolType.NetworkFilesystem && pool.getType() != StoragePoolType.VMFS && pool.getType() != StoragePoolType.PreSetup) { + if (pool.getType() != StoragePoolType.NetworkFilesystem && pool.getType() != StoragePoolType.VMFS && pool.getType() != StoragePoolType.PreSetup && pool.getType() != StoragePoolType.DatastoreCluster) { throw new Exception("Unsupported storage pool type " + pool.getType()); } @@ -4914,16 +4914,24 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa assert (morDatastore != null); DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDatastore); - HypervisorHostHelper.createBaseFolderInDatastore(dsMo, hyperHost); + HypervisorHostHelper.createBaseFolder(dsMo, hyperHost, pool.getType()); - DatastoreSummary summary = dsMo.getSummary(); - long capacity = summary.getCapacity(); - long available = summary.getFreeSpace(); + long capacity = 0; + long available = 0; + if (pool.getType() == StoragePoolType.DatastoreCluster) { + StoragePodSummary summary = dsMo.getDatastoreClusterSummary(); + capacity = summary.getCapacity(); + available = summary.getFreeSpace(); + } else { + DatastoreSummary summary = dsMo.getDatastoreSummary(); + capacity = summary.getCapacity(); + available = summary.getFreeSpace(); + } Map tInfo = new HashMap<>(); ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, capacity, available, tInfo); - if (cmd.getAdd() && (pool.getType() == StoragePoolType.VMFS || pool.getType() == StoragePoolType.PreSetup)) { + if (cmd.getAdd() && (pool.getType() == StoragePoolType.VMFS || pool.getType() == StoragePoolType.PreSetup) && pool.getType() != StoragePoolType.DatastoreCluster) { answer.setPoolType(dsMo.getDatastoreType()); answer.setLocalDatastoreName(morDatastore.getValue()); } @@ -5305,11 +5313,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (morDs != null) { DatastoreMO datastoreMo = new DatastoreMO(context, morDs); - DatastoreSummary summary = datastoreMo.getSummary(); - assert (summary != null); + long capacity = 0; + long free = 0; + if (cmd.getPooltype() == StoragePoolType.DatastoreCluster) { + StoragePodSummary summary = datastoreMo.getDatastoreClusterSummary(); + capacity = summary.getCapacity(); + free = summary.getFreeSpace(); + } else { + DatastoreSummary summary = datastoreMo.getDatastoreSummary(); + capacity = summary.getCapacity(); + free = summary.getFreeSpace(); + } - long capacity = summary.getCapacity(); - long free = summary.getFreeSpace(); long used = capacity - free; if (s_logger.isDebugEnabled()) { @@ -5317,7 +5332,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa + ", capacity: " + toHumanReadableSize(capacity) + ", free: " + toHumanReadableSize(free) + ", used: " + toHumanReadableSize(used)); } - if (summary.getCapacity() <= 0) { + if (capacity <= 0) { s_logger.warn("Something is wrong with vSphere NFS datastore, rebooting ESX(ESXi) host should help"); } @@ -5839,7 +5854,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa dsMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, poolUuid); } - DatastoreSummary dsSummary = dsMo.getSummary(); + DatastoreSummary dsSummary = dsMo.getDatastoreSummary(); String address = hostMo.getHostName(); StoragePoolInfo pInfo = new StoragePoolInfo(poolUuid, address, dsMo.getMor().getValue(), "", StoragePoolType.VMFS, dsSummary.getCapacity(), dsSummary.getFreeSpace()); @@ -6555,6 +6570,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(context, context.getServiceContent().getCustomFieldsManager()); cfmMo.ensureCustomFieldDef("Datastore", CustomFieldConstants.CLOUD_UUID); + cfmMo.ensureCustomFieldDef("StoragePod", CustomFieldConstants.CLOUD_UUID); + if (_publicTrafficInfo != null && _publicTrafficInfo.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch || _guestTrafficInfo != null && _guestTrafficInfo.getVirtualSwitchType() != VirtualSwitchType.StandardVirtualSwitch) { cfmMo.ensureCustomFieldDef("DistributedVirtualPortgroup", CustomFieldConstants.CLOUD_GC_DVP); 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 9cd9b6e9ea3..22d0a92aea6 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 @@ -2962,7 +2962,7 @@ public class VmwareStorageProcessor implements StorageProcessor { throw new Exception("Unable to create a dummy VM for volume creation"); } - Long volumeSizeToUse = volumeSize < dsMo.getSummary().getFreeSpace() ? volumeSize : dsMo.getSummary().getFreeSpace(); + Long volumeSizeToUse = volumeSize < dsMo.getDatastoreSummary().getFreeSpace() ? volumeSize : dsMo.getDatastoreSummary().getFreeSpace(); vmMo.createDisk(vmdkDatastorePath, getMBsFromBytes(volumeSizeToUse), dsMo.getMor(), vmMo.getScsiDeviceControllerKey()); vmMo.detachDisk(vmdkDatastorePath, false); diff --git a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java index 84b7bfdf9af..955af589c19 100644 --- a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java +++ b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java @@ -18,32 +18,6 @@ */ package org.apache.cloudstack.storage.datastore.lifecycle; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.inject.Inject; - -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters; -import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; - import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.CreateStoragePoolCommand; @@ -78,6 +52,29 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle { private static final Logger s_logger = Logger.getLogger(CloudStackPrimaryDataStoreLifeCycleImpl.class); @@ -256,6 +253,11 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore parameters.setHost(storageHost); parameters.setPort(0); parameters.setPath(hostPath); + } else if (scheme.equalsIgnoreCase("DatastoreCluster")) { + parameters.setType(StoragePoolType.DatastoreCluster); + parameters.setHost(storageHost); + parameters.setPort(0); + parameters.setPath(hostPath); } else if (scheme.equalsIgnoreCase("iscsi")) { String[] tokens = hostPath.split("/"); int lun = NumbersUtil.parseInt(tokens[tokens.length - 1], -1); @@ -360,7 +362,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore if (pool.getPoolType() != StoragePoolType.NetworkFilesystem && pool.getPoolType() != StoragePoolType.Filesystem && pool.getPoolType() != StoragePoolType.IscsiLUN && pool.getPoolType() != StoragePoolType.Iscsi && pool.getPoolType() != StoragePoolType.VMFS && - pool.getPoolType() != StoragePoolType.SharedMountPoint && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.OCFS2 && + pool.getPoolType() != StoragePoolType.SharedMountPoint && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.DatastoreCluster && pool.getPoolType() != StoragePoolType.OCFS2 && pool.getPoolType() != StoragePoolType.RBD && pool.getPoolType() != StoragePoolType.CLVM && pool.getPoolType() != StoragePoolType.SMB && pool.getPoolType() != StoragePoolType.Gluster) { s_logger.warn(" Doesn't support storage pool type " + pool.getPoolType()); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java index fb98dfd4b9d..133a412d750 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java @@ -16,12 +16,10 @@ // under the License. package com.cloud.hypervisor.vmware.mo; -import java.util.ArrayList; -import java.util.List; - +import com.cloud.exception.CloudException; +import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.utils.Pair; import com.vmware.pbm.PbmProfile; -import org.apache.log4j.Logger; - import com.vmware.vim25.DatastoreHostMount; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.FileInfo; @@ -35,11 +33,12 @@ import com.vmware.vim25.ObjectSpec; import com.vmware.vim25.PropertyFilterSpec; import com.vmware.vim25.PropertySpec; import com.vmware.vim25.SelectionSpec; +import com.vmware.vim25.StoragePodSummary; import com.vmware.vim25.TraversalSpec; +import org.apache.log4j.Logger; -import com.cloud.exception.CloudException; -import com.cloud.hypervisor.vmware.util.VmwareContext; -import com.cloud.utils.Pair; +import java.util.ArrayList; +import java.util.List; import static com.cloud.utils.NumbersUtil.toHumanReadableSize; @@ -65,10 +64,14 @@ public class DatastoreMO extends BaseMO { return _name; } - public DatastoreSummary getSummary() throws Exception { + public DatastoreSummary getDatastoreSummary() throws Exception { return (DatastoreSummary)_context.getVimClient().getDynamicProperty(_mor, "summary"); } + public StoragePodSummary getDatastoreClusterSummary() throws Exception { + return (StoragePodSummary)_context.getVimClient().getDynamicProperty(_mor, "summary"); + } + public HostDatastoreBrowserMO getHostDatastoreBrowserMO() throws Exception { return new HostDatastoreBrowserMO(_context, (ManagedObjectReference)_context.getVimClient().getDynamicProperty(_mor, "browser")); } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java index f38f610e145..30798e31e19 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostDatastoreSystemMO.java @@ -16,11 +16,7 @@ // under the License. package com.cloud.hypervisor.vmware.mo; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - +import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.vim25.CustomFieldStringValue; import com.vmware.vim25.DatastoreInfo; import com.vmware.vim25.DynamicProperty; @@ -35,12 +31,18 @@ import com.vmware.vim25.ObjectContent; import com.vmware.vim25.ObjectSpec; import com.vmware.vim25.PropertyFilterSpec; import com.vmware.vim25.PropertySpec; +import com.vmware.vim25.RetrieveOptions; +import com.vmware.vim25.RetrieveResult; +import com.vmware.vim25.SelectionSpec; import com.vmware.vim25.TraversalSpec; import com.vmware.vim25.VmfsDatastoreCreateSpec; import com.vmware.vim25.VmfsDatastoreExpandSpec; import com.vmware.vim25.VmfsDatastoreOption; -import com.cloud.hypervisor.vmware.util.VmwareContext; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; public class HostDatastoreSystemMO extends BaseMO { @@ -53,6 +55,14 @@ public class HostDatastoreSystemMO extends BaseMO { } public ManagedObjectReference findDatastore(String name) throws Exception { + ManagedObjectReference morDatastore = findSpecificDatastore(name); + if (morDatastore == null) { + morDatastore = findDatastoreCluster(name); + } + return morDatastore; + } + + public ManagedObjectReference findSpecificDatastore(String name) throws Exception { // added Apache CloudStack specific name convention, we will use custom field "cloud.uuid" as datastore name as well CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(_context, _context.getServiceContent().getCustomFieldsManager()); int key = cfmMo.getCustomFieldKey("Datastore", CustomFieldConstants.CLOUD_UUID); @@ -79,6 +89,33 @@ public class HostDatastoreSystemMO extends BaseMO { return null; } + public ManagedObjectReference findDatastoreCluster(String name) throws Exception { + // added Apache CloudStack specific name convention, we will use custom field "cloud.uuid" as datastore name as well + CustomFieldsManagerMO cfmMo = new CustomFieldsManagerMO(_context, _context.getServiceContent().getCustomFieldsManager()); + int key = cfmMo.getCustomFieldKey("StoragePod", CustomFieldConstants.CLOUD_UUID); + assert (key != 0); + + List ocs = getDatastoreClusterPropertiesOnHostDatastoreSystem(new String[] {"name", String.format("value[%d]", key)}); + if (ocs != null) { + for (ObjectContent oc : ocs) { + if (oc.getPropSet().get(0).getVal().equals(name)) + return oc.getObj(); + + if (oc.getPropSet().size() > 1) { + DynamicProperty prop = oc.getPropSet().get(1); + if (prop != null && prop.getVal() != null) { + if (prop.getVal() instanceof CustomFieldStringValue) { + String val = ((CustomFieldStringValue)prop.getVal()).getValue(); + if (val.equalsIgnoreCase(name)) + return oc.getObj(); + } + } + } + } + } + return null; + } + public List queryUnresolvedVmfsVolumes() throws Exception { return _context.getService().queryUnresolvedVmfsVolumes(_mor); } @@ -251,4 +288,90 @@ public class HostDatastoreSystemMO extends BaseMO { return _context.getService().retrieveProperties(_context.getPropertyCollector(), pfSpecArr); } + + public List getDatastoreClusterPropertiesOnHostDatastoreSystem(String[] propertyPaths) throws Exception { + ManagedObjectReference retVal = null; + // Create Property Spec + PropertySpec propertySpec = new PropertySpec(); + propertySpec.setAll(Boolean.FALSE); + propertySpec.setType("StoragePod"); + propertySpec.getPathSet().addAll(Arrays.asList(propertyPaths)); + + // Now create Object Spec + ObjectSpec objectSpec = new ObjectSpec(); + objectSpec.setObj(getContext().getRootFolder()); + objectSpec.setSkip(Boolean.TRUE); + objectSpec.getSelectSet().addAll( + Arrays.asList(getStorageTraversalSpec())); + + // Create PropertyFilterSpec using the PropertySpec and ObjectPec + // created above. + PropertyFilterSpec propertyFilterSpec = new PropertyFilterSpec(); + propertyFilterSpec.getPropSet().add(propertySpec); + propertyFilterSpec.getObjectSet().add(objectSpec); + + List listpfs = new ArrayList(); + listpfs.add(propertyFilterSpec); + return retrievePropertiesAllObjects(listpfs); + } + + private SelectionSpec[] getStorageTraversalSpec() { + // create a traversal spec that start from root folder + + SelectionSpec ssFolders = new SelectionSpec(); + ssFolders.setName("visitFolders"); + + TraversalSpec datacenterSpec = new TraversalSpec(); + datacenterSpec.setName("dcTodf"); + datacenterSpec.setType("Datacenter"); + datacenterSpec.setPath("datastoreFolder"); + datacenterSpec.setSkip(Boolean.FALSE); + datacenterSpec.getSelectSet().add(ssFolders); + + TraversalSpec visitFolder = new TraversalSpec(); + visitFolder.setType("Folder"); + visitFolder.setName("visitFolders"); + visitFolder.setPath("childEntity"); + visitFolder.setSkip(Boolean.FALSE); + + List ssSpecList = new ArrayList(); + ssSpecList.add(datacenterSpec); + ssSpecList.add(ssFolders); + + visitFolder.getSelectSet().addAll(ssSpecList); + return (new SelectionSpec[]{visitFolder}); + } + + private List retrievePropertiesAllObjects( + List listpfs) throws Exception { + + RetrieveOptions propObjectRetrieveOpts = new RetrieveOptions(); + + List listobjcontent = new ArrayList(); + + RetrieveResult rslts = + getContext().getService().retrievePropertiesEx(getContext().getServiceContent().getPropertyCollector(), listpfs, + propObjectRetrieveOpts); + if (rslts != null && rslts.getObjects() != null + && !rslts.getObjects().isEmpty()) { + listobjcontent.addAll(rslts.getObjects()); + } + String token = null; + if (rslts != null && rslts.getToken() != null) { + token = rslts.getToken(); + } + while (token != null && !token.isEmpty()) { + rslts = + getContext().getService().continueRetrievePropertiesEx(getContext().getServiceContent().getPropertyCollector(), token); + token = null; + if (rslts != null) { + token = rslts.getToken(); + if (rslts.getObjects() != null && !rslts.getObjects().isEmpty()) { + listobjcontent.addAll(rslts.getObjects()); + } + } + } + return listobjcontent; + } + } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java index 8c02fb444f3..2483ced5cc5 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -28,6 +28,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import com.cloud.storage.Storage; import com.google.gson.Gson; import com.vmware.vim25.AboutInfo; import com.vmware.vim25.AlreadyExistsFaultMsg; @@ -873,12 +874,15 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { } else { morDatastore = _context.getDatastoreMorByPath(poolPath); if (morDatastore == null) { - String msg = "Unable to create VMFS datastore. host: " + poolHostAddress + ", port: " + poolHostPort + ", path: " + poolPath + ", uuid: " + poolUuid; - s_logger.error(msg); + morDatastore = findDatastore(_context.getDatastoreNameFromPath(poolPath)); + if (morDatastore == null) { + String msg = "Unable to create VMFS datastore. host: " + poolHostAddress + ", port: " + poolHostPort + ", path: " + poolPath + ", uuid: " + poolUuid; + s_logger.error(msg); - if (s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - mountDatastore() done(failed)"); - throw new Exception(msg); + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - mountDatastore() done(failed)"); + throw new Exception(msg); + } } dsMo = new DatastoreMO(_context, morDatastore); @@ -887,7 +891,7 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { } if (dsMo != null) { - HypervisorHostHelper.createBaseFolderInDatastore(dsMo, this); + HypervisorHostHelper.createBaseFolder(dsMo, this, "StoragePod".equals(morDatastore.getType()) ? Storage.StoragePoolType.DatastoreCluster: null); } if (s_logger.isTraceEnabled()) diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index f25279bdee3..30ee117fe7b 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -54,6 +54,7 @@ import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.offering.NetworkOffering; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.ActionDelegate; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -172,7 +173,6 @@ public class HypervisorHostHelper { if (morDs == null) morDs = hyperHost.findDatastore(uuidName); - DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs); return morDs; } @@ -2086,7 +2086,19 @@ public class HypervisorHostHelper { return DiskControllerType.getType(controller) == DiskControllerType.ide; } - public static void createBaseFolderInDatastore(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception { + public static void createBaseFolder(DatastoreMO dsMo, VmwareHypervisorHost hyperHost, StoragePoolType poolType) throws Exception { + if (poolType != null && poolType == StoragePoolType.DatastoreCluster) { + List datastoresInCluster = hyperHost.getContext().getVimClient().getDynamicProperty(dsMo.getMor(), "childEntity"); + for (ManagedObjectReference datastore : datastoresInCluster) { + DatastoreMO childDsMo = new DatastoreMO(hyperHost.getContext(), datastore); + createBaseFolderInDatastore(childDsMo, hyperHost); + } + } else { + createBaseFolderInDatastore(dsMo, hyperHost); + } + } + + private static void createBaseFolderInDatastore(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception { String dsPath = String.format("[%s]", dsMo.getName()); String folderPath = String.format("[%s] %s", dsMo.getName(), VSPHERE_DATASTORE_BASE_FOLDER); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java index 33b9644a307..807289f8bdf 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java @@ -321,6 +321,24 @@ public class VmwareContext { return dcMo.findDatastore(tokens[1]); } + // path in format of / + public String getDatastoreNameFromPath(String inventoryPath) throws Exception { + assert (inventoryPath != null); + + String[] tokens; + if (inventoryPath.startsWith("/")) + tokens = inventoryPath.substring(1).split("/"); + else + tokens = inventoryPath.split("/"); + + if (tokens == null || tokens.length != 2) { + s_logger.error("Invalid datastore inventory path. path: " + inventoryPath); + return null; + } + + return tokens[1]; + } + public void waitForTaskProgressDone(ManagedObjectReference morTask) throws Exception { while (true) { TaskInfo tinfo = (TaskInfo)_vimClient.getDynamicProperty(morTask, "info");