From 86e9092f0cc91d14a363b2432e5bf41e4fb8b7de Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Wed, 1 Nov 2023 14:22:30 -0600 Subject: [PATCH 01/18] StoragePoolType as a class --- .../main/java/com/cloud/storage/Storage.java | 86 +++++++++++++------ .../cloud/agent/transport/RequestTest.java | 4 +- .../src/main/java/com/cloud/host/HostVO.java | 6 +- .../main/java/com/cloud/storage/VolumeVO.java | 9 +- .../storage/datastore/db/StoragePoolVO.java | 15 ++-- .../storage/volume/VolumeServiceTest.java | 5 +- .../kvm/storage/IscsiAdmStorageAdaptor.java | 6 +- .../kvm/storage/KVMStoragePoolManager.java | 25 +++--- .../kvm/storage/LibvirtStorageAdaptor.java | 33 ++++--- .../kvm/storage/ScaleIOStorageAdaptor.java | 6 +- .../kvm/storage/StorageAdaptor.java | 4 + .../kvm/storage/StorageAdaptorInfo.java | 3 - .../cloud/simulator/MockStoragePoolVO.java | 9 +- ...oudStackPrimaryDataStoreLifeCycleImpl.java | 2 +- .../kvm/storage/LinstorStorageAdaptor.java | 6 +- .../kvm/storage/StorPoolStorageAdaptor.java | 6 +- .../com/cloud/storage/StorageManagerImpl.java | 2 +- .../listener/StoragePoolMonitorTest.java | 2 + 18 files changed, 141 insertions(+), 88 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java index 8a2ec1a8905d..b5b6fd9d9da4 100644 --- a/api/src/main/java/com/cloud/storage/Storage.java +++ b/api/src/main/java/com/cloud/storage/Storage.java @@ -17,9 +17,12 @@ package com.cloud.storage; import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public class Storage { public static enum ImageFormat { @@ -135,37 +138,43 @@ public static enum TemplateType { ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */ } - public static enum StoragePoolType { - Filesystem(false, true, true), // local directory - NetworkFilesystem(true, true, true), // NFS - IscsiLUN(true, false, false), // shared LUN, with a clusterfs overlay - Iscsi(true, false, false), // for e.g., ZFS Comstar - ISO(false, false, false), // for iso image - LVM(false, false, false), // XenServer local LVM SR - CLVM(true, false, false), - RBD(true, true, false), // http://libvirt.org/storage.html#StorageBackendRBD - SharedMountPoint(true, false, true), - VMFS(true, true, false), // VMware VMFS storage - PreSetup(true, true, false), // for XenServer, Storage Pool is set up by customers. - EXT(false, true, false), // XenServer local EXT SR - OCFS2(true, false, false), - SMB(true, false, false), - Gluster(true, false, false), - PowerFlex(true, true, true), // Dell EMC PowerFlex/ScaleIO (formerly VxFlexOS) - ManagedNFS(true, false, false), - Linstor(true, true, false), - DatastoreCluster(true, true, false), // for VMware, to abstract pool of clusters - StorPool(true, true, true), - FiberChannel(true, true, false); // Fiber Channel Pool for KVM hypervisors is used to find the volume by WWN value (/dev/disk/by-id/wwn-) - + public static class StoragePoolType { + private static final Map map = new LinkedHashMap<>(); + + public static final StoragePoolType Filesystem = new StoragePoolType("Filesystem", false, true, true); + public static final StoragePoolType NetworkFilesystem = new StoragePoolType("NetworkFilesystem", true, true, true); + public static final StoragePoolType IscsiLUN = new StoragePoolType("IscsiLUN", true, false, false); + public static final StoragePoolType Iscsi = new StoragePoolType("Iscsi", true, false, false); + public static final StoragePoolType ISO = new StoragePoolType("ISO", false, false, false); + public static final StoragePoolType LVM = new StoragePoolType("LVM", false, false, false); + public static final StoragePoolType CLVM = new StoragePoolType("CLVM", true, false, false); + public static final StoragePoolType RBD = new StoragePoolType("RBD", true, true, false); + public static final StoragePoolType SharedMountPoint = new StoragePoolType("SharedMountPoint", true, false, true); + public static final StoragePoolType VMFS = new StoragePoolType("VMFS", true, true, false); + public static final StoragePoolType PreSetup = new StoragePoolType("PreSetup", true, true, false); + public static final StoragePoolType EXT = new StoragePoolType("EXT", false, true, false); + public static final StoragePoolType OCFS2 = new StoragePoolType("OCFS2", true, false, false); + public static final StoragePoolType SMB = new StoragePoolType("SMB", true, false, false); + public static final StoragePoolType Gluster = new StoragePoolType("Gluster", true, false, false); + public static final StoragePoolType PowerFlex = new StoragePoolType("PowerFlex", true, true, true); + public static final StoragePoolType ManagedNFS = new StoragePoolType("ManagedNFS", true, false, false); + public static final StoragePoolType Linstor = new StoragePoolType("Linstor", true, true, false); + public static final StoragePoolType DatastoreCluster = new StoragePoolType("DatastoreCluster", true, true, false); + public static final StoragePoolType StorPool = new StoragePoolType("StorPool", true,true,true); + public static final StoragePoolType FiberChannel = new StoragePoolType("FiberChannel", true,true,false); + + + private final String name; private final boolean shared; private final boolean overprovisioning; private final boolean encryption; - StoragePoolType(boolean shared, boolean overprovisioning, boolean encryption) { + public StoragePoolType(String name, boolean shared, boolean overprovisioning, boolean encryption) { + this.name = name; this.shared = shared; this.overprovisioning = overprovisioning; this.encryption = encryption; + addStoragePoolType(this); } public boolean isShared() { @@ -177,6 +186,35 @@ public boolean supportsOverProvisioning() { } public boolean supportsEncryption() { return encryption; } + + private static void addStoragePoolType(StoragePoolType storagePoolType) { + map.putIfAbsent(storagePoolType.name, storagePoolType); + } + + public static StoragePoolType[] values() { + return map.values().toArray(StoragePoolType[]::new).clone(); + } + + public static StoragePoolType valueOf(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + + StoragePoolType storage = map.get(name); + if (storage == null) { + throw new IllegalArgumentException("StoragePoolType '" + name + "' not found"); + } + return storage; + } + + @Override + public String toString() { + return name; + } + + public String name() { + return name; + } } public static List getNonSharedStoragePoolTypes() { diff --git a/core/src/test/java/com/cloud/agent/transport/RequestTest.java b/core/src/test/java/com/cloud/agent/transport/RequestTest.java index 21766ba038fa..6eada0226fce 100644 --- a/core/src/test/java/com/cloud/agent/transport/RequestTest.java +++ b/core/src/test/java/com/cloud/agent/transport/RequestTest.java @@ -255,7 +255,7 @@ protected void compareRequest(Request req1, Request req2) { public void testGoodCommand() { s_logger.info("Testing good Command"); String content = "[{\"com.cloud.agent.api.GetVolumeStatsCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"]," - + "\"poolType\":\"NetworkFilesystem\",\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; + + "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); sreq.setSequence(1); Command cmds[] = sreq.getCommands(); @@ -266,7 +266,7 @@ public void testGoodCommand() { public void testBadCommand() { s_logger.info("Testing Bad Command"); String content = "[{\"com.cloud.agent.api.SomeJunkCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"]," - + "\"poolType\":\"NetworkFilesystem\",\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; + + "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]"; Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); sreq.setSequence(1); Command cmds[] = sreq.getCommands(); diff --git a/engine/schema/src/main/java/com/cloud/host/HostVO.java b/engine/schema/src/main/java/com/cloud/host/HostVO.java index 697401ad0696..e0f0ce4970c8 100644 --- a/engine/schema/src/main/java/com/cloud/host/HostVO.java +++ b/engine/schema/src/main/java/com/cloud/host/HostVO.java @@ -130,7 +130,7 @@ public class HostVO implements Host { private String resource; @Column(name = "fs_type") - private StoragePoolType fsType; + private String fsType; @Column(name = "available") private boolean available = true; @@ -447,7 +447,7 @@ public HostVO(long id, String name, Type type, String privateIpAddress, String p null); this.parent = parent; this.totalSize = totalSize; - this.fsType = fsType; + this.fsType = fsType == null ? null : fsType.name(); this.uuid = UUID.randomUUID().toString(); } @@ -674,7 +674,7 @@ public void setProxyPort(Integer port) { } public StoragePoolType getFsType() { - return fsType; + return StoragePoolType.valueOf(fsType); } @Override diff --git a/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java b/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java index 0bd71ea6d866..d847eb93e3e3 100644 --- a/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java @@ -114,8 +114,7 @@ public class VolumeVO implements Volume { Type volumeType = Volume.Type.UNKNOWN; @Column(name = "pool_type") - @Enumerated(EnumType.STRING) - StoragePoolType poolType; + String poolType; @Column(name = GenericDao.REMOVED_COLUMN) Date removed; @@ -328,12 +327,10 @@ public long getAccountId() { } public void setPoolType(StoragePoolType poolType) { - this.poolType = poolType; + this.poolType = poolType.name(); } - public StoragePoolType getPoolType() { - return poolType; - } + public StoragePoolType getPoolType() { return StoragePoolType.valueOf(poolType); } @Override public long getDomainId() { diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 926b8a5a01d0..5791cea97894 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -57,8 +57,7 @@ public class StoragePoolVO implements StoragePool { private String uuid = null; @Column(name = "pool_type", updatable = false, nullable = false, length = 32) - @Enumerated(value = EnumType.STRING) - private StoragePoolType poolType; + private String poolType; @Column(name = GenericDao.CREATED_COLUMN) Date created; @@ -141,7 +140,7 @@ public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type this.name = name; id = poolId; this.uuid = uuid; - poolType = type; + poolType = type.name(); this.dataCenterId = dataCenterId; usedBytes = availableBytes; this.capacityBytes = capacityBytes; @@ -153,11 +152,11 @@ public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type } public StoragePoolVO(StoragePoolVO that) { - this(that.id, that.name, that.uuid, that.poolType, that.dataCenterId, that.podId, that.usedBytes, that.capacityBytes, that.hostAddress, that.port, that.path); + this(that.id, that.name, that.uuid, StoragePoolType.valueOf(that.poolType), that.dataCenterId, that.podId, that.usedBytes, that.capacityBytes, that.hostAddress, that.port, that.path); } public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) { - poolType = type; + poolType = type.name(); this.hostAddress = hostAddress; this.port = port; setStatus(StoragePoolStatus.Initial); @@ -177,11 +176,11 @@ public String getUuid() { @Override public StoragePoolType getPoolType() { - return poolType; + return StoragePoolType.valueOf(poolType); } public void setPoolType(StoragePoolType protocol) { - poolType = protocol; + poolType = protocol.name(); } @Override @@ -273,7 +272,7 @@ public void setHostAddress(String host) { @Override public String getPath() { String updatedPath = path; - if (poolType == StoragePoolType.SMB) { + if (poolType.equals(StoragePoolType.SMB.name())) { updatedPath = UriUtils.getUpdateUri(updatedPath, false); if (updatedPath.contains("password") && updatedPath.contains("?")) { updatedPath = updatedPath.substring(0, updatedPath.indexOf('?')); diff --git a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java index ee4b77c269cf..f4c6df7dd40a 100644 --- a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java +++ b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceTest.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.storage.volume; +import com.cloud.storage.Storage; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.snapshot.SnapshotManager; @@ -185,7 +186,9 @@ public void validateDestroySourceVolumeAfterMigrationReturnTrue() throws Executi public void validateDestroySourceVolumeAfterMigrationExpungeSourceVolumeAfterMigrationThrowExceptionReturnFalse() throws ExecutionException, InterruptedException{ VolumeObject volumeObject = new VolumeObject(); - volumeObject.configure(null, new VolumeVO() {}); + VolumeVO vo = new VolumeVO() {}; + vo.setPoolType(Storage.StoragePoolType.Filesystem); + volumeObject.configure(null, vo); List exceptions = new ArrayList<>(Arrays.asList(new InterruptedException(), new ExecutionException() {})); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java index f980cd295bd2..46cca60ac4ed 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java @@ -36,7 +36,6 @@ import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; -@StorageAdaptorInfo(storagePoolType=StoragePoolType.Iscsi) public class IscsiAdmStorageAdaptor implements StorageAdaptor { private static final Logger s_logger = Logger.getLogger(IscsiAdmStorageAdaptor.class); @@ -51,6 +50,11 @@ public KVMStoragePool createStoragePool(String uuid, String host, int port, Stri return storagePool; } + @Override + public StoragePoolType getStoragePoolType() { + return StoragePoolType.Iscsi; + } + @Override public KVMStoragePool getStoragePool(String uuid) { return MapStorageUuidToStoragePool.get(uuid); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java index b1842f38da29..fb5588b4a848 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java @@ -105,20 +105,21 @@ public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) { // add any adaptors that wish to register themselves via annotation Reflections reflections = new Reflections("com.cloud.hypervisor.kvm.storage"); - Set> storageAdaptors = reflections.getSubTypesOf(StorageAdaptor.class); - for (Class storageAdaptor : storageAdaptors) { - StorageAdaptorInfo info = storageAdaptor.getAnnotation(StorageAdaptorInfo.class); - if (info != null && info.storagePoolType() != null) { - if (this._storageMapper.containsKey(info.storagePoolType().toString())) { - s_logger.warn(String.format("Duplicate StorageAdaptor type %s, not loading %s", info.storagePoolType().toString(), storageAdaptor.getName())); - } else { - try { - s_logger.info(String.format("adding storage adaptor for %s", storageAdaptor.getName())); - this._storageMapper.put(info.storagePoolType().toString(), storageAdaptor.getDeclaredConstructor().newInstance()); - } catch (Exception ex) { - throw new CloudRuntimeException(ex.toString()); + Set> storageAdaptorClasses = reflections.getSubTypesOf(StorageAdaptor.class); + for (Class storageAdaptorClass : storageAdaptorClasses) { + try { + StorageAdaptor adaptor = storageAdaptorClass.getDeclaredConstructor().newInstance(); + StoragePoolType storagePoolType = adaptor.getStoragePoolType(); + if (storagePoolType != null) { + if (this._storageMapper.containsKey(storagePoolType.toString())) { + s_logger.warn(String.format("Duplicate StorageAdaptor type %s, not loading %s", storagePoolType, storageAdaptorClass.getName())); + } else { + s_logger.info(String.format("adding storage adaptor for %s", storageAdaptorClass.getName())); + this._storageMapper.put(storagePoolType.toString(), adaptor); } } + } catch (Exception ex) { + throw new CloudRuntimeException(ex.toString()); } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index bdaa419c6983..d257a6a3310a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -775,23 +775,22 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, s_logger.info("Attempting to create volume " + name + " (" + pool.getType().toString() + ") in pool " + pool.getUuid() + " with size " + toHumanReadableSize(size)); - switch (pool.getType()) { - case RBD: - return createPhysicalDiskByLibVirt(name, pool, PhysicalDiskFormat.RAW, provisioningType, size); - case NetworkFilesystem: - case Filesystem: - switch (format) { - case QCOW2: - case RAW: - return createPhysicalDiskByQemuImg(name, pool, format, provisioningType, size, passphrase); - case DIR: - case TAR: - return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size); - default: - throw new CloudRuntimeException("Unexpected disk format is specified."); - } - default: - return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size); + StoragePoolType poolType = pool.getType(); + if (poolType.equals(StoragePoolType.RBD)) { + return createPhysicalDiskByLibVirt(name, pool, PhysicalDiskFormat.RAW, provisioningType, size); + } else if (poolType.equals(StoragePoolType.NetworkFilesystem) || poolType.equals(StoragePoolType.Filesystem)) { + switch (format) { + case QCOW2: + case RAW: + return createPhysicalDiskByQemuImg(name, pool, format, provisioningType, size, passphrase); + case DIR: + case TAR: + return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size); + default: + throw new CloudRuntimeException("Unexpected disk format is specified."); + } + } else { + return createPhysicalDiskByLibVirt(name, pool, format, provisioningType, size); } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java index b85be041e488..86ca20aa19f0 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java @@ -48,7 +48,6 @@ import com.cloud.utils.script.Script; import org.apache.commons.lang3.StringUtils; -@StorageAdaptorInfo(storagePoolType= Storage.StoragePoolType.PowerFlex) public class ScaleIOStorageAdaptor implements StorageAdaptor { private static final Logger LOGGER = Logger.getLogger(ScaleIOStorageAdaptor.class); private static final Map MapStorageUuidToStoragePool = new HashMap<>(); @@ -70,6 +69,11 @@ public KVMStoragePool getStoragePool(String uuid) { return pool; } + @Override + public Storage.StoragePoolType getStoragePoolType() { + return Storage.StoragePoolType.PowerFlex; + } + @Override public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) { return getStoragePool(uuid); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java index ecf8691c6edc..3c359410f8dd 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java @@ -26,6 +26,10 @@ public interface StorageAdaptor { + default StoragePoolType getStoragePoolType() { + return null; + } + public KVMStoragePool getStoragePool(String uuid); // Get the storage pool from libvirt, but control if libvirt should refresh the pool (can take a long time) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptorInfo.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptorInfo.java index fce976535f65..8d4b0c60a860 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptorInfo.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptorInfo.java @@ -22,10 +22,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import com.cloud.storage.Storage.StoragePoolType; - @Retention(RetentionPolicy.RUNTIME) @Target({ TYPE }) public @interface StorageAdaptorInfo { - StoragePoolType storagePoolType(); } diff --git a/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java b/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java index 46cd0e47a7b6..6383c0a12060 100644 --- a/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java +++ b/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java @@ -18,8 +18,6 @@ import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @@ -50,8 +48,7 @@ public class MockStoragePoolVO implements InternalIdentity { private String hostGuid; @Column(name = "pool_type") - @Enumerated(value = EnumType.STRING) - private StoragePoolType poolType; + private String poolType; public MockStoragePoolVO() { @@ -71,11 +68,11 @@ public long getId() { } public StoragePoolType getPoolType() { - return this.poolType; + return StoragePoolType.valueOf(this.poolType); } public void setStorageType(StoragePoolType poolType) { - this.poolType = poolType; + this.poolType = poolType.name(); } public String getUuid() { 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 685565d73b03..bad57068a731 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 @@ -263,7 +263,7 @@ public DataStore initialize(Map dsInfos) { parameters.setPort(port); parameters.setPath(hostPath); } else { - StoragePoolType type = Enum.valueOf(StoragePoolType.class, scheme); + StoragePoolType type = StoragePoolType.valueOf(scheme); if (type != null) { parameters.setType(type); diff --git a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java index 917b7c0ed0cb..deee5fb6c413 100644 --- a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java +++ b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java @@ -54,7 +54,6 @@ import com.linbit.linstor.api.model.StoragePool; import com.linbit.linstor.api.model.VolumeDefinition; -@StorageAdaptorInfo(storagePoolType=Storage.StoragePoolType.Linstor) public class LinstorStorageAdaptor implements StorageAdaptor { private static final Logger s_logger = Logger.getLogger(LinstorStorageAdaptor.class); private static final Map MapStorageUuidToStoragePool = new HashMap<>(); @@ -66,6 +65,11 @@ private DevelopersApi getLinstorAPI(KVMStoragePool pool) { return new DevelopersApi(client); } + @Override + public Storage.StoragePoolType getStoragePoolType() { + return Storage.StoragePoolType.Linstor; + } + private static String getLinstorRscName(String name) { return LinstorUtil.RSC_PREFIX + name; } diff --git a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java index 273f088d77f9..d8f77ac88c63 100644 --- a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java +++ b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java @@ -39,7 +39,6 @@ import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; -@StorageAdaptorInfo(storagePoolType=StoragePoolType.StorPool) public class StorPoolStorageAdaptor implements StorageAdaptor { public static void SP_LOG(String fmt, Object... args) { try (PrintWriter spLogFile = new PrintWriter(new BufferedWriter(new FileWriter("/var/log/cloudstack/agent/storpool-agent.log", true)))) { @@ -65,6 +64,11 @@ public KVMStoragePool createStoragePool(String uuid, String host, int port, Stri return storagePool; } + @Override + public StoragePoolType getStoragePoolType() { + return StoragePoolType.StorPool; + } + @Override public KVMStoragePool getStoragePool(String uuid) { SP_LOG("StorPoolStorageAdaptor.getStoragePool: uuid=%s", uuid); diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index 04889d0b2a83..198762ae5a8f 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -2474,7 +2474,7 @@ public List listByStoragePool(long storagePoolId) { @DB public StoragePoolVO findLocalStorageOnHost(long hostId) { SearchCriteria sc = LocalStorageSearch.create(); - sc.setParameters("type", new Object[] {StoragePoolType.Filesystem, StoragePoolType.LVM}); + sc.setParameters("type", StoragePoolType.Filesystem.toString(), StoragePoolType.LVM.toString()); sc.setJoinParameters("poolHost", "hostId", hostId); List storagePools = _storagePoolDao.search(sc, null); if (!storagePools.isEmpty()) { diff --git a/server/src/test/java/com/cloud/storage/listener/StoragePoolMonitorTest.java b/server/src/test/java/com/cloud/storage/listener/StoragePoolMonitorTest.java index fa6b71d0cb22..3be6e02d04b1 100644 --- a/server/src/test/java/com/cloud/storage/listener/StoragePoolMonitorTest.java +++ b/server/src/test/java/com/cloud/storage/listener/StoragePoolMonitorTest.java @@ -21,6 +21,7 @@ import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage; import com.cloud.storage.StorageManagerImpl; import com.cloud.storage.StoragePoolStatus; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -53,6 +54,7 @@ public void setUp() throws Exception { pool.setScope(ScopeType.CLUSTER); pool.setStatus(StoragePoolStatus.Up); pool.setId(123L); + pool.setPoolType(Storage.StoragePoolType.Filesystem); cmd = new StartupRoutingCommand(); cmd.setHypervisorType(Hypervisor.HypervisorType.KVM); } From 154c736030f5033d31fad6a003bdfd227482d515 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Wed, 1 Nov 2023 16:53:58 -0600 Subject: [PATCH 02/18] Fix agent side StoragePoolType enum to class --- .../kvm/storage/KVMStoragePoolManager.java | 28 ++++++++++++++----- .../kvm/storage/LibvirtStorageAdaptor.java | 6 ++++ .../kvm/storage/ManagedNfsStorageAdaptor.java | 3 ++ .../kvm/storage/ScaleIOStorageAdaptor.java | 6 ++-- .../kvm/storage/StorageAdaptor.java | 4 +-- .../kvm/storage/ScaleIOStoragePoolTest.java | 6 +--- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java index fb5588b4a848..6598b08f879a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.hypervisor.kvm.storage; +import java.lang.reflect.Constructor; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; @@ -98,17 +99,30 @@ private void addStoragePool(String uuid, StoragePoolInformation pool) { public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) { this._haMonitor = monitor; this._storageMapper.put("libvirt", new LibvirtStorageAdaptor(storagelayer)); - // add other storage adaptors here - // this._storageMapper.put("newadaptor", new NewStorageAdaptor(storagelayer)); - this._storageMapper.put(StoragePoolType.ManagedNFS.toString(), new ManagedNfsStorageAdaptor(storagelayer)); - this._storageMapper.put(StoragePoolType.PowerFlex.toString(), new ScaleIOStorageAdaptor(storagelayer)); + // add other storage adaptors manually here - // add any adaptors that wish to register themselves via annotation + // add any adaptors that wish to register themselves via call to adaptor.getStoragePoolType() Reflections reflections = new Reflections("com.cloud.hypervisor.kvm.storage"); Set> storageAdaptorClasses = reflections.getSubTypesOf(StorageAdaptor.class); for (Class storageAdaptorClass : storageAdaptorClasses) { + s_logger.debug("Checking pool type for adaptor " + storageAdaptorClass.getName()); + if (storageAdaptorClass.isAssignableFrom(LibvirtStorageAdaptor.class)) { + s_logger.debug("Skipping re-registration of LibvirtStorageAdaptor"); + continue; + } try { - StorageAdaptor adaptor = storageAdaptorClass.getDeclaredConstructor().newInstance(); + Constructor storageLayerConstructor = Arrays.stream(storageAdaptorClass.getConstructors()) + .filter(c -> c.getParameterCount() == 1) + .filter(c -> c.getParameterTypes()[0].isAssignableFrom(StorageLayer.class)) + .findFirst().orElse(null); + StorageAdaptor adaptor; + + if (storageLayerConstructor == null) { + adaptor = storageAdaptorClass.getDeclaredConstructor().newInstance(); + } else { + adaptor = (StorageAdaptor) storageLayerConstructor.newInstance(storagelayer); + } + StoragePoolType storagePoolType = adaptor.getStoragePoolType(); if (storagePoolType != null) { if (this._storageMapper.containsKey(storagePoolType.toString())) { @@ -119,7 +133,7 @@ public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) { } } } catch (Exception ex) { - throw new CloudRuntimeException(ex.toString()); + throw new CloudRuntimeException("Failed to set up storage adaptors", ex); } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index d257a6a3310a..83a5c06cb5b7 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -459,6 +459,12 @@ public LibvirtStorageVolumeDef getStorageVolumeDef(Connect conn, StorageVol vol) return parser.parseStorageVolumeXML(volDefXML); } + @Override + public StoragePoolType getStoragePoolType() { + // This is mapped manually in KVMStoragePoolManager + return null; + } + @Override public KVMStoragePool getStoragePool(String uuid) { return this.getStoragePool(uuid, false); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java index b23dd9a17904..62029fa1e340 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java @@ -65,6 +65,9 @@ public KVMStoragePool createStoragePool(String uuid, String host, int port, Stri return storagePool; } + @Override + public StoragePoolType getStoragePoolType() { return StoragePoolType.ManagedNFS; } + @Override public KVMStoragePool getStoragePool(String uuid) { return getStoragePool(uuid, false); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java index 86ca20aa19f0..2cd68753e014 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java @@ -41,7 +41,6 @@ import org.libvirt.LibvirtException; import com.cloud.storage.Storage; -import com.cloud.storage.StorageLayer; import com.cloud.storage.StorageManager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.OutputInterpreter; @@ -52,10 +51,9 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor { private static final Logger LOGGER = Logger.getLogger(ScaleIOStorageAdaptor.class); private static final Map MapStorageUuidToStoragePool = new HashMap<>(); private static final int DEFAULT_DISK_WAIT_TIME_IN_SECS = 60; - private StorageLayer storageLayer; - public ScaleIOStorageAdaptor(StorageLayer storagelayer) { - storageLayer = storagelayer; + public ScaleIOStorageAdaptor() { + } @Override diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java index 3c359410f8dd..8db672ad7f7e 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java @@ -26,9 +26,7 @@ public interface StorageAdaptor { - default StoragePoolType getStoragePoolType() { - return null; - } + StoragePoolType getStoragePoolType(); public KVMStoragePool getStoragePool(String uuid); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java index 492bc275a3f3..bfc48da5a74c 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java @@ -44,7 +44,6 @@ import org.mockito.junit.MockitoJUnitRunner; import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.StorageLayer; import com.cloud.utils.script.Script; @RunWith(MockitoJUnitRunner.class) @@ -54,9 +53,6 @@ public class ScaleIOStoragePoolTest { StorageAdaptor adapter; - @Mock - StorageLayer storageLayer; - @Before public void setUp() throws Exception { final String uuid = "345fc603-2d7e-47d2-b719-a0110b3732e6"; @@ -65,7 +61,7 @@ public void setUp() throws Exception { Map details = new HashMap(); details.put(ScaleIOGatewayClient.STORAGE_POOL_SYSTEM_ID, systemId); - adapter = spy(new ScaleIOStorageAdaptor(storageLayer)); + adapter = spy(new ScaleIOStorageAdaptor()); pool = new ScaleIOStoragePool(uuid, "192.168.1.19", 443, "a519be2f00000000", type, details, adapter); } From 2da13ee86971bba7b08aa310b6c015fb01e66d12 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Thu, 2 Nov 2023 10:21:01 -0600 Subject: [PATCH 03/18] Handle StoragePoolType for StoragePoolJoinVO --- .../main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java index 5eb04d2e00d5..03f7ceb0633b 100644 --- a/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java @@ -64,8 +64,7 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I private StoragePoolStatus status; @Column(name = "pool_type") - @Enumerated(value = EnumType.STRING) - private StoragePoolType poolType; + private String poolType; @Column(name = GenericDao.CREATED_COLUMN) private Date created; @@ -183,7 +182,7 @@ public StoragePoolStatus getStatus() { } public StoragePoolType getPoolType() { - return poolType; + return StoragePoolType.valueOf(poolType); } public Date getCreated() { From 38017646f9c4f0cb716cd690b00de615419659f3 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Fri, 10 Nov 2023 10:03:53 -0800 Subject: [PATCH 04/18] Since StoragePoolType is a class, it cannot be converted by @Enumerated annotation. Implemented conveter class and logic to utilize @Convert annotation. --- .../main/java/com/cloud/storage/VolumeVO.java | 3 + .../cloud/util/StoragePoolTypeConverter.java | 24 ++ .../com/cloud/utils/db/GenericDaoBase.java | 306 ++++++++++-------- .../com/cloud/api/query/vo/UserVmJoinVO.java | 33 +- 4 files changed, 218 insertions(+), 148 deletions(-) create mode 100644 engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java diff --git a/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java b/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java index d847eb93e3e3..ed9d1c5a83cf 100644 --- a/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java @@ -20,6 +20,7 @@ import java.util.UUID; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -32,6 +33,7 @@ import javax.persistence.TemporalType; import javax.persistence.Transient; +import com.cloud.util.StoragePoolTypeConverter; import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; import com.cloud.storage.Storage.ProvisioningType; @@ -114,6 +116,7 @@ public class VolumeVO implements Volume { Type volumeType = Volume.Type.UNKNOWN; @Column(name = "pool_type") + @Convert(converter = StoragePoolTypeConverter.class) String poolType; @Column(name = GenericDao.REMOVED_COLUMN) diff --git a/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java b/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java new file mode 100644 index 000000000000..4f1e777606ba --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java @@ -0,0 +1,24 @@ +package com.cloud.util; + +import com.cloud.storage.Storage.StoragePoolType; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * Converts {@link StoragePoolType} to and from {@link String} using {@link StoragePoolType#name()}. + * + * @author mprokopchuk + */ +@Converter +public class StoragePoolTypeConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(StoragePoolType attribute) { + return attribute != null ? attribute.name() : null; + } + + @Override + public StoragePoolType convertToEntityAttribute(String dbData) { + return dbData != null ? StoragePoolType.valueOf(dbData) : null; + } +} diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java index 6bf36df09414..90781dcd91d6 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java @@ -16,6 +16,42 @@ // under the License. package com.cloud.utils.db; +import com.cloud.utils.DateUtil; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ComponentLifecycle; +import com.cloud.utils.component.ComponentLifecycleBase; +import com.cloud.utils.component.ComponentMethodInterceptable; +import com.cloud.utils.crypt.DBEncryptionUtil; +import com.cloud.utils.db.SearchCriteria.SelectType; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.NoOp; +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Element; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.log4j.Logger; + +import javax.naming.ConfigurationException; +import javax.persistence.AttributeConverter; +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.EmbeddedId; +import javax.persistence.EntityExistsException; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Table; +import javax.persistence.TableGenerator; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; @@ -42,79 +78,42 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import javax.naming.ConfigurationException; -import javax.persistence.AttributeOverride; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.EntityExistsException; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Table; -import javax.persistence.TableGenerator; - -import org.apache.log4j.Logger; - -import com.cloud.utils.DateUtil; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.Ternary; -import com.cloud.utils.component.ComponentLifecycle; -import com.cloud.utils.component.ComponentLifecycleBase; -import com.cloud.utils.component.ComponentMethodInterceptable; -import com.cloud.utils.crypt.DBEncryptionUtil; -import com.cloud.utils.db.SearchCriteria.SelectType; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.Ip; -import com.cloud.utils.net.NetUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.NoOp; -import net.sf.ehcache.Cache; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.Element; - /** - * GenericDaoBase is a simple way to implement DAOs. It DOES NOT - * support the full EJB3 spec. It borrows some of the annotations from - * the EJB3 spec to produce a set of SQLs so developers don't have to - * copy and paste the same code over and over again. Of course, - * GenericDaoBase is completely at the mercy of the annotations you add - * to your entity bean. If GenericDaoBase does not fit your needs, then - * don't extend from it. - * - * GenericDaoBase attempts to achieve the following: - * 1. If you use _allFieldsStr in your SQL statement and use to() to convert - * the result to the entity bean, you don't ever have to worry about - * missing fields because its automatically taken from the entity bean's - * annotations. - * 2. You don't have to rewrite the same insert and select query strings - * in all of your DAOs. - * 3. You don't have to match the '?' (you know what I'm talking about) to - * the fields in the insert statement as that's taken care of for you. - * - * GenericDaoBase looks at the following annotations: - * 1. Table - just name - * 2. Column - just name - * 3. GeneratedValue - any field with this annotation is not inserted. - * 4. SequenceGenerator - sequence generator - * 5. Id - * 6. SecondaryTable - * - * Sometime later, I might look into injecting the SQLs as needed but right - * now we have to construct them at construction time. The good thing is that - * the DAOs are suppose to be one per jvm so the time is all during the - * initial load. - * + * GenericDaoBase is a simple way to implement DAOs. It DOES NOT + * support the full EJB3 spec. It borrows some of the annotations from + * the EJB3 spec to produce a set of SQLs so developers don't have to + * copy and paste the same code over and over again. Of course, + * GenericDaoBase is completely at the mercy of the annotations you add + * to your entity bean. If GenericDaoBase does not fit your needs, then + * don't extend from it. + *

+ * GenericDaoBase attempts to achieve the following: + * 1. If you use _allFieldsStr in your SQL statement and use to() to convert + * the result to the entity bean, you don't ever have to worry about + * missing fields because its automatically taken from the entity bean's + * annotations. + * 2. You don't have to rewrite the same insert and select query strings + * in all of your DAOs. + * 3. You don't have to match the '?' (you know what I'm talking about) to + * the fields in the insert statement as that's taken care of for you. + *

+ * GenericDaoBase looks at the following annotations: + * 1. Table - just name + * 2. Column - just name + * 3. GeneratedValue - any field with this annotation is not inserted. + * 4. SequenceGenerator - sequence generator + * 5. Id + * 6. SecondaryTable + *

+ * Sometime later, I might look into injecting the SQLs as needed but right + * now we have to construct them at construction time. The good thing is that + * the DAOs are suppose to be one per jvm so the time is all during the + * initial load. **/ @DB public abstract class GenericDaoBase extends ComponentLifecycleBase implements GenericDao, ComponentMethodInterceptable { @@ -123,6 +122,7 @@ public abstract class GenericDaoBase extends Compone protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT"); protected final static Map, GenericDao> s_daoMaps = new ConcurrentHashMap, GenericDao>(71); + private final ConversionSupport _conversionSupport; protected Class _entityBeanType; protected String _table; @@ -170,7 +170,7 @@ public abstract class GenericDaoBase extends Compone public static GenericDao getDao(Class entityType) { @SuppressWarnings("unchecked") - GenericDao dao = (GenericDao)s_daoMaps.get(entityType); + GenericDao dao = (GenericDao) s_daoMaps.get(entityType); assert dao != null : "Unable to find DAO for " + entityType + ". Are you sure you waited for the DAO to be initialized before asking for it?"; return dao; } @@ -189,8 +189,8 @@ public Map getAllAttributes() { @SuppressWarnings("unchecked") public T createSearchEntity(MethodInterceptor interceptor) { - T entity = (T)_searchEnhancer.create(); - final Factory factory = (Factory)entity; + T entity = (T) _searchEnhancer.create(); + final Factory factory = (Factory) entity; factory.setCallback(0, interceptor); return entity; } @@ -200,11 +200,11 @@ protected GenericDaoBase() { super(); Type t = getClass().getGenericSuperclass(); if (t instanceof ParameterizedType) { - _entityBeanType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; - } else if (((Class)t).getGenericSuperclass() instanceof ParameterizedType) { - _entityBeanType = (Class)((ParameterizedType)((Class)t).getGenericSuperclass()).getActualTypeArguments()[0]; + _entityBeanType = (Class) ((ParameterizedType) t).getActualTypeArguments()[0]; + } else if (((Class) t).getGenericSuperclass() instanceof ParameterizedType) { + _entityBeanType = (Class) ((ParameterizedType) ((Class) t).getGenericSuperclass()).getActualTypeArguments()[0]; } else { - _entityBeanType = (Class)((ParameterizedType)((Class)((Class)t).getGenericSuperclass()).getGenericSuperclass()).getActualTypeArguments()[0]; + _entityBeanType = (Class) ((ParameterizedType) ((Class) ((Class) t).getGenericSuperclass()).getGenericSuperclass()).getActualTypeArguments()[0]; } s_daoMaps.put(_entityBeanType, this); @@ -220,7 +220,7 @@ protected GenericDaoBase() { final SqlGenerator generator = new SqlGenerator(_entityBeanType); _partialSelectSql = generator.buildSelectSql(false); _count = generator.buildCountSql(); - _distinctIdSql= generator.buildDistinctIdSql(); + _distinctIdSql = generator.buildDistinctIdSql(); _partialQueryCacheSelectSql = generator.buildSelectSql(true); _embeddedFields = generator.getEmbeddedFields(); _insertSqls = generator.buildInsertSqls(); @@ -252,13 +252,13 @@ protected GenericDaoBase() { _tgs.put(tg.name(), tg); } - Callback[] callbacks = new Callback[] {NoOp.INSTANCE, new UpdateBuilder(this)}; + Callback[] callbacks = new Callback[]{NoOp.INSTANCE, new UpdateBuilder(this)}; _enhancer = new Enhancer(); _enhancer.setSuperclass(_entityBeanType); _enhancer.setCallbackFilter(s_callbackFilter); _enhancer.setCallbacks(callbacks); - _factory = (Factory)_enhancer.create(); + _factory = (Factory) _enhancer.create(); _searchEnhancer = new Enhancer(); _searchEnhancer.setSuperclass(_entityBeanType); @@ -281,12 +281,12 @@ protected GenericDaoBase() { s_logger.trace("Collection SQLs"); for (Attribute attr : _ecAttributes) { - EcInfo info = (EcInfo)attr.attache; + EcInfo info = (EcInfo) attr.attache; s_logger.trace(info.insertSql); s_logger.trace(info.selectSql); } } - + _conversionSupport = new ConversionSupport(); setRunLevel(ComponentLifecycle.RUN_LEVEL_SYSTEM); } @@ -294,7 +294,7 @@ protected GenericDaoBase() { @DB() @SuppressWarnings("unchecked") public T createForUpdate(final ID id) { - final T entity = (T)_factory.newInstance(new Callback[] {NoOp.INSTANCE, new UpdateBuilder(this)}); + final T entity = (T) _factory.newInstance(new Callback[]{NoOp.INSTANCE, new UpdateBuilder(this)}); if (id != null) { try { _idField.set(entity, id); @@ -434,7 +434,7 @@ public List customSearchIncludingRemoved(SearchCriteria sc, final Filt throw new CloudRuntimeException("Call to customSearchIncludingRemoved with null search Criteria"); } if (sc.isSelectAll()) { - return (List)searchIncludingRemoved((SearchCriteria)sc, filter, null, false); + return (List) searchIncludingRemoved((SearchCriteria) sc, filter, null, false); } String clause = sc.getWhereClause(); if (clause != null && clause.length() == 0) { @@ -484,7 +484,7 @@ public List customSearchIncludingRemoved(SearchCriteria sc, final Filt List fields = sc.getSelectFields(); while (rs.next()) { if (st == SelectType.Entity) { - results.add((M)toEntityBean(rs, false)); + results.add((M) toEntityBean(rs, false)); } else if (st == SelectType.Fields || st == SelectType.Result) { M m = sc.getResultType().newInstance(); for (int j = 1; j <= fields.size(); j++) { @@ -549,7 +549,7 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr final Enumerated enumerated = field.getAnnotation(Enumerated.class); final EnumType enumType = (enumerated == null) ? EnumType.STRING : enumerated.value(); - final Enum[] enums = (Enum[])field.getType().getEnumConstants(); + final Enum[] enums = (Enum[]) field.getType().getEnumConstants(); for (final Enum e : enums) { if ((enumType == EnumType.STRING && e.name().equalsIgnoreCase(rs.getString(index))) || (enumType == EnumType.ORDINAL && e.ordinal() == rs.getInt(index))) { @@ -650,7 +650,7 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr } else if (type == byte[].class) { field.set(entity, rs.getBytes(index)); } else { - field.set(entity, rs.getObject(index)); + field.set(entity, _conversionSupport.convertToEntityAttribute(field, rs.getObject(index))); } } catch (final IllegalAccessException e) { throw new CloudRuntimeException("Yikes! ", e); @@ -660,12 +660,9 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr /** * Get a value from a result set. * - * @param type - * the expected type of the result - * @param rs - * the result set - * @param index - * the index of the column + * @param type the expected type of the result + * @param rs the result set + * @param index the index of the column * @return the result in the requested type * @throws SQLException */ @@ -676,7 +673,7 @@ protected static M getObject(Class type, ResultSet rs, int index) throws byte[] bytes = rs.getBytes(index); if (bytes != null) { try { - return (M)new String(bytes, "UTF-8"); + return (M) new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new CloudRuntimeException("UnsupportedEncodingException exception while converting UTF-8 data"); } @@ -704,7 +701,7 @@ protected static M getObject(Class type, ResultSet rs, int index) throws if (data == null) { return null; } else { - return (M)DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index)); + return (M) DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index)); } } else if (type == short.class) { return (M) (Short) rs.getShort(index); @@ -753,12 +750,12 @@ protected static M getObject(Class type, ResultSet rs, int index) throws } else { final Calendar cal = Calendar.getInstance(); cal.setTime(DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index))); - return (M)cal; + return (M) cal; } } else if (type == byte[].class) { - return (M)rs.getBytes(index); + return (M) rs.getBytes(index); } else { - return (M)rs.getObject(index); + return (M) rs.getObject(index); } } @@ -850,6 +847,7 @@ public int update(UpdateBuilder ub, final SearchCriteria sc, Integer rows) { /** * If the SQLException.getSQLState is of 23000 (Integrity Constraint Violation), and the Error Code is 1062 (Duplicate Entry), throws EntityExistsException. + * * @throws EntityExistsException */ protected static void handleEntityExistsException(SQLException e) throws EntityExistsException { @@ -958,7 +956,7 @@ public T findById(final ID id) { if (element == null) { result = lockRow(id, null); } else { - result = (T)element.getObjectValue(); + result = (T) element.getObjectValue(); } } else { result = lockRow(id, null); @@ -991,7 +989,7 @@ public T findByIdIncludingRemoved(final ID id) { if (element == null) { result = findById(id, true, null); } else { - result = (T)element.getObjectValue(); + result = (T) element.getObjectValue(); } } else { result = findById(id, true, null); @@ -1378,6 +1376,7 @@ public Pair, Integer> searchAndCount(SearchCriteria sc, final Filter /** * Validates if the count of records is higher or equal to the result set's size.

* Count cannot be less than the result set, however, it can be higher due to pagination (see CLOUDSTACK-10320). + * * @return Count if it is higher or equal to the result set's size, otherwise the result set's size. */ protected int checkCountOfRecordsAgainstTheResultSetSize(int count, int resultSetSize) { @@ -1386,7 +1385,7 @@ protected int checkCountOfRecordsAgainstTheResultSetSize(int count, int resultSe } String stackTrace = ExceptionUtils.getStackTrace(new CloudRuntimeException(String.format("The query to count all the records of [%s] resulted in a value smaller than" - + " the result set's size [count of records: %s, result set's size: %s]. Using the result set's size instead.", _entityBeanType, + + " the result set's size [count of records: %s, result set's size: %s]. Using the result set's size instead.", _entityBeanType, count, resultSetSize))); s_logger.warn(stackTrace); @@ -1455,7 +1454,7 @@ public T persist(final T entity) { if (_idField != null) { ID id; try { - id = (ID)_idField.get(entity); + id = (ID) _idField.get(entity); } catch (IllegalAccessException e) { throw new CloudRuntimeException("How can it be illegal access...come on", e); } @@ -1486,7 +1485,7 @@ public T persist(final T entity) { final ResultSet rs = pstmt.getGeneratedKeys(); if (id == null) { if (rs != null && rs.next()) { - id = (ID)rs.getObject(1); + id = (ID) rs.getObject(1); } try { if (_idField != null) { @@ -1497,7 +1496,7 @@ public T persist(final T entity) { _idField.set(entity, id); } } else { - id = (ID)_idField.get(entity); + id = (ID) _idField.get(entity); } } } catch (final IllegalAccessException e) { @@ -1537,12 +1536,12 @@ protected void insertElementCollection(T entity, Attribute idAttribute, ID id, M Attribute attr = entry.getKey(); Object obj = entry.getValue(); - EcInfo ec = (EcInfo)attr.attache; + EcInfo ec = (EcInfo) attr.attache; Enumeration en = null; if (ec.rawClass == null) { - en = Collections.enumeration(Arrays.asList((Object[])obj)); + en = Collections.enumeration(Arrays.asList((Object[]) obj)); } else { - en = Collections.enumeration((Collection)obj); + en = Collections.enumeration((Collection) obj); } PreparedStatement pstmt = txn.prepareAutoCloseStatement(ec.clearSql); prepareAttribute(1, pstmt, idAttribute, id); @@ -1551,7 +1550,7 @@ protected void insertElementCollection(T entity, Attribute idAttribute, ID id, M while (en.hasMoreElements()) { pstmt = txn.prepareAutoCloseStatement(ec.insertSql); if (ec.targetClass == Date.class) { - pstmt.setString(1, DateUtil.getDateDisplayString(s_gmtTimeZone, (Date)en.nextElement())); + pstmt.setString(1, DateUtil.getDateDisplayString(s_gmtTimeZone, (Date) en.nextElement())); } else { pstmt.setObject(1, en.nextElement()); } @@ -1596,7 +1595,8 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina } } if (attr.field.getType() == String.class) { - final String str = (String)value; + // convert value to DB column type if needed + final String str = _conversionSupport.convertToDatabaseColumn(attr.field, value); if (str == null) { pstmt.setString(j, null); return; @@ -1631,7 +1631,7 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina } } } else if (attr.field.getType() == Date.class) { - final Date date = (Date)value; + final Date date = (Date) value; if (date == null || date.equals(DATE_TO_NULL)) { pstmt.setObject(j, null); return; @@ -1644,7 +1644,7 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, date)); } } else if (attr.field.getType() == Calendar.class) { - final Calendar cal = (Calendar)value; + final Calendar cal = (Calendar) value; if (cal == null) { pstmt.setObject(j, null); return; @@ -1665,15 +1665,15 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina if (value == null) { pstmt.setObject(j, null); } else { - pstmt.setInt(j, ((Enum)value).ordinal()); + pstmt.setInt(j, ((Enum) value).ordinal()); } } } else if (attr.field.getType() == URI.class) { pstmt.setString(j, value == null ? null : value.toString()); } else if (attr.field.getType() == URL.class) { - pstmt.setURL(j, (URL)value); + pstmt.setURL(j, (URL) value); } else if (attr.field.getType() == byte[].class) { - pstmt.setBytes(j, (byte[])value); + pstmt.setBytes(j, (byte[]) value); } else if (attr.field.getType() == Ip.class) { final Enumerated enumerated = attr.field.getAnnotation(Enumerated.class); final EnumType type = (enumerated == null) ? EnumType.ORDINAL : enumerated.value(); @@ -1683,7 +1683,7 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina if (value == null) { pstmt.setObject(j, null); } else { - pstmt.setLong(j, (value instanceof Ip) ? ((Ip)value).longValue() : NetUtils.ip2Long((String)value)); + pstmt.setLong(j, (value instanceof Ip) ? ((Ip) value).longValue() : NetUtils.ip2Long((String) value)); } } } else { @@ -1711,7 +1711,7 @@ protected int prepareAttributes(final PreparedStatement pstmt, final Object enti @SuppressWarnings("unchecked") @DB() protected T toEntityBean(final ResultSet result, final boolean cache) throws SQLException { - final T entity = (T)_factory.newInstance(new Callback[] {NoOp.INSTANCE, new UpdateBuilder(this)}); + final T entity = (T) _factory.newInstance(new Callback[]{NoOp.INSTANCE, new UpdateBuilder(this)}); toEntityBean(result, entity); @@ -1762,13 +1762,11 @@ protected void toEntityBean(final ResultSet result, final T entity) throws SQLEx @DB() @SuppressWarnings("unchecked") protected void loadCollection(T entity, Attribute attr) { - EcInfo ec = (EcInfo)attr.attache; + EcInfo ec = (EcInfo) attr.attache; TransactionLegacy txn = TransactionLegacy.currentTxn(); - try(PreparedStatement pstmt = txn.prepareStatement(ec.selectSql);) - { + try (PreparedStatement pstmt = txn.prepareStatement(ec.selectSql);) { pstmt.setObject(1, _idField.get(entity)); - try(ResultSet rs = pstmt.executeQuery();) - { + try (ResultSet rs = pstmt.executeQuery();) { ArrayList lst = new ArrayList(); if (ec.targetClass == Integer.class) { while (rs.next()) { @@ -1818,16 +1816,15 @@ protected void loadCollection(T entity, Attribute attr) { throw new CloudRuntimeException("Never should happen", e); } } - } - catch (SQLException e) { - throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); + } catch (SQLException e) { + throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); } } catch (SQLException e) { - throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); + throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); } catch (IllegalArgumentException e) { - throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); + throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); } catch (IllegalAccessException e) { - throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); + throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); } } @@ -1939,13 +1936,13 @@ public int remove(SearchCriteria sc) { @DB() protected void createCache(final Map params) { - final String value = (String)params.get("cache.size"); + final String value = (String) params.get("cache.size"); if (value != null) { final CacheManager cm = CacheManager.create(); final int maxElements = NumbersUtil.parseInt(value, 0); - final int live = NumbersUtil.parseInt((String)params.get("cache.time.to.live"), 300); - final int idle = NumbersUtil.parseInt((String)params.get("cache.time.to.idle"), 300); + final int live = NumbersUtil.parseInt((String) params.get("cache.time.to.live"), 300); + final int idle = NumbersUtil.parseInt((String) params.get("cache.time.to.idle"), 300); _cache = new Cache(getName(), maxElements, false, live == -1, live == -1 ? Integer.MAX_VALUE : live, idle); cm.addCache(_cache); s_logger.info("Cache created: " + _cache.toString()); @@ -1959,11 +1956,11 @@ protected void createCache(final Map params) { public boolean configure(final String name, final Map params) throws ConfigurationException { _name = name; - final String value = (String)params.get("lock.timeout"); + final String value = (String) params.get("lock.timeout"); _timeoutSeconds = NumbersUtil.parseInt(value, 300); createCache(params); - final boolean load = Boolean.parseBoolean((String)params.get("cache.preload")); + final boolean load = Boolean.parseBoolean((String) params.get("cache.preload")); if (load) { listAll(); } @@ -1973,9 +1970,9 @@ public boolean configure(final String name, final Map params) th @DB() public static UpdateBuilder getUpdateBuilder(final T entityObject) { - final Factory factory = (Factory)entityObject; + final Factory factory = (Factory) entityObject; assert (factory != null); - return (UpdateBuilder)factory.getCallback(1); + return (UpdateBuilder) factory.getCallback(1); } @Override @@ -2221,4 +2218,49 @@ protected StringBuilder createDistinctSelect(SearchCriteria sc, final boolean return sql; } + + /** + * Support conversion between DB and Entity values. + * Detects whether field is annotated with {@link Convert} annotation and use converter instance from the annotation. + */ + static class ConversionSupport { + /** + * Contains cache of {@link AttributeConverter} instances. + */ + private static final Map, AttributeConverter> s_converterCacheMap = new ConcurrentHashMap<>(); + + /** + * Checks whether field annotated with {@link Convert} annotation and tries to convert source value with converter. + * + * @param field Entity field + * @param value DB value + * @return converted value if field is annotated with {@link Convert} or original value otherwise + */ + private T convertToEntityAttribute(Field field, Object value) { + return (T) getConverter(field).map(converter -> converter.convertToEntityAttribute(value)).orElse(value); + } + + /** + * Checks whether field annotated with {@link Convert} annotation and tries to convert source value with converter. + * + * @param field Entity field + * @param value Entity value + * @return converted value if field is annotated with {@link Convert} or original value otherwise + */ + private T convertToDatabaseColumn(Field field, Object value) { + return (T) getConverter(field).map(converter -> converter.convertToDatabaseColumn(value)).orElse(value); + } + + private Optional> getConverter(Field field) { + return Optional.of(field).map(f -> f.getAnnotation(Convert.class)).map(Convert::converter).filter(AttributeConverter.class::isAssignableFrom).map(converterType -> { + return (AttributeConverter) s_converterCacheMap.computeIfAbsent(converterType, ct -> { + try { + return (AttributeConverter) ct.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new CloudRuntimeException("Unable to create converter for the class " + converterType, e); + } + }); + }); + } + } } diff --git a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java index a465e8990e72..074fc49d44c1 100644 --- a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java @@ -16,19 +16,7 @@ // under the License. package com.cloud.api.query.vo; -import java.net.URI; -import java.util.Date; -import java.util.Map; - -import javax.persistence.AttributeOverride; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Transient; - +import com.cloud.util.StoragePoolTypeConverter; import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network.GuestType; @@ -42,9 +30,22 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import java.net.URI; +import java.util.Date; +import java.util.Map; + @Entity @Table(name = "user_vm_view") -@AttributeOverride( name="id", column = @Column(name = "id", updatable = false, nullable = false) ) +@AttributeOverride(name = "id", column = @Column(name = "id", updatable = false, nullable = false)) public class UserVmJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @@ -113,7 +114,7 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro @Column(name = GenericDao.REMOVED_COLUMN) private Date removed; - @Column(name="update_time") + @Column(name = "update_time") private Date lastUpdated; @Column(name = "instance_name", updatable = true, nullable = false) @@ -256,7 +257,7 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro private String poolUuid; @Column(name = "pool_type", updatable = false, nullable = false, length = 32) - @Enumerated(value = EnumType.STRING) + @Convert(converter = StoragePoolTypeConverter.class) private StoragePoolType poolType; @Column(name = "volume_id") From ea9a7c800014e5cfa7ec64b6d0660d5ff62cd21e Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Mon, 6 Nov 2023 10:13:56 -0800 Subject: [PATCH 05/18] Fix UserVMJoinVO for StoragePoolType --- .../com/cloud/api/query/vo/UserVmJoinVO.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java index 074fc49d44c1..53d1d8e6786c 100644 --- a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java @@ -16,7 +16,19 @@ // under the License. package com.cloud.api.query.vo; -import com.cloud.util.StoragePoolTypeConverter; +import java.net.URI; +import java.util.Date; +import java.util.Map; + +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; + import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network.GuestType; @@ -30,22 +42,9 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import javax.persistence.AttributeOverride; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Transient; -import java.net.URI; -import java.util.Date; -import java.util.Map; - @Entity @Table(name = "user_vm_view") -@AttributeOverride(name = "id", column = @Column(name = "id", updatable = false, nullable = false)) +@AttributeOverride( name="id", column = @Column(name = "id", updatable = false, nullable = false) ) public class UserVmJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @@ -114,7 +113,7 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro @Column(name = GenericDao.REMOVED_COLUMN) private Date removed; - @Column(name = "update_time") + @Column(name="update_time") private Date lastUpdated; @Column(name = "instance_name", updatable = true, nullable = false) From 5c631108afe85a98c1fbe20524bd0c3ed7d2ca56 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Fri, 10 Nov 2023 13:04:35 -0800 Subject: [PATCH 06/18] fixed missing imports --- server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java index 53d1d8e6786c..dbad73a39bbc 100644 --- a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java @@ -22,6 +22,7 @@ import javax.persistence.AttributeOverride; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -38,6 +39,7 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume; import com.cloud.user.Account; +import com.cloud.util.StoragePoolTypeConverter; import com.cloud.utils.db.GenericDao; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; From c0b421b23d6a256251ef0c6648097a963add1e72 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Fri, 17 Nov 2023 19:26:16 -0800 Subject: [PATCH 07/18] Since StoragePoolType is a class, it cannot be converted by @Enumerated annotation. Implemented conveter class and logic to utilize @Convert annotation. --- .../src/main/java/com/cloud/host/HostVO.java | 9 +- .../main/java/com/cloud/storage/VolumeVO.java | 6 +- .../storage/datastore/db/StoragePoolVO.java | 17 +- .../com/cloud/utils/db/GenericDaoBase.java | 267 ++++++++++-------- .../cloud/simulator/MockStoragePoolVO.java | 9 +- .../simulator/dao/MockStoragePoolDaoImpl.java | 2 +- .../cloud/api/query/vo/StoragePoolJoinVO.java | 7 +- .../com/cloud/storage/StorageManagerImpl.java | 2 +- 8 files changed, 174 insertions(+), 145 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/host/HostVO.java b/engine/schema/src/main/java/com/cloud/host/HostVO.java index e0f0ce4970c8..b7cac8ff8cbc 100644 --- a/engine/schema/src/main/java/com/cloud/host/HostVO.java +++ b/engine/schema/src/main/java/com/cloud/host/HostVO.java @@ -23,6 +23,7 @@ import java.util.UUID; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.Entity; @@ -44,6 +45,7 @@ import com.cloud.offering.ServiceOffering; import com.cloud.resource.ResourceState; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.util.StoragePoolTypeConverter; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; import java.util.Arrays; @@ -130,7 +132,8 @@ public class HostVO implements Host { private String resource; @Column(name = "fs_type") - private String fsType; + @Convert(converter = StoragePoolTypeConverter.class) + private StoragePoolType fsType; @Column(name = "available") private boolean available = true; @@ -447,7 +450,7 @@ public HostVO(long id, String name, Type type, String privateIpAddress, String p null); this.parent = parent; this.totalSize = totalSize; - this.fsType = fsType == null ? null : fsType.name(); + this.fsType = fsType; this.uuid = UUID.randomUUID().toString(); } @@ -674,7 +677,7 @@ public void setProxyPort(Integer port) { } public StoragePoolType getFsType() { - return StoragePoolType.valueOf(fsType); + return fsType; } @Override diff --git a/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java b/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java index ed9d1c5a83cf..d8dfbb6f0762 100644 --- a/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/VolumeVO.java @@ -117,7 +117,7 @@ public class VolumeVO implements Volume { @Column(name = "pool_type") @Convert(converter = StoragePoolTypeConverter.class) - String poolType; + StoragePoolType poolType; @Column(name = GenericDao.REMOVED_COLUMN) Date removed; @@ -330,10 +330,10 @@ public long getAccountId() { } public void setPoolType(StoragePoolType poolType) { - this.poolType = poolType.name(); + this.poolType = poolType; } - public StoragePoolType getPoolType() { return StoragePoolType.valueOf(poolType); } + public StoragePoolType getPoolType() { return poolType; } @Override public long getDomainId() { diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 5791cea97894..9b357dfee4ce 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -21,11 +21,13 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; +import com.cloud.util.StoragePoolTypeConverter; import com.cloud.utils.UriUtils; import com.cloud.utils.db.Encrypt; import com.cloud.utils.db.GenericDao; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -57,7 +59,8 @@ public class StoragePoolVO implements StoragePool { private String uuid = null; @Column(name = "pool_type", updatable = false, nullable = false, length = 32) - private String poolType; + @Convert(converter = StoragePoolTypeConverter.class) + private StoragePoolType poolType; @Column(name = GenericDao.CREATED_COLUMN) Date created; @@ -140,7 +143,7 @@ public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type this.name = name; id = poolId; this.uuid = uuid; - poolType = type.name(); + poolType = type; this.dataCenterId = dataCenterId; usedBytes = availableBytes; this.capacityBytes = capacityBytes; @@ -152,11 +155,11 @@ public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type } public StoragePoolVO(StoragePoolVO that) { - this(that.id, that.name, that.uuid, StoragePoolType.valueOf(that.poolType), that.dataCenterId, that.podId, that.usedBytes, that.capacityBytes, that.hostAddress, that.port, that.path); + this(that.id, that.name, that.uuid, that.poolType, that.dataCenterId, that.podId, that.usedBytes, that.capacityBytes, that.hostAddress, that.port, that.path); } public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) { - poolType = type.name(); + poolType = type; this.hostAddress = hostAddress; this.port = port; setStatus(StoragePoolStatus.Initial); @@ -176,11 +179,11 @@ public String getUuid() { @Override public StoragePoolType getPoolType() { - return StoragePoolType.valueOf(poolType); + return poolType; } - public void setPoolType(StoragePoolType protocol) { - poolType = protocol.name(); + public void setPoolType(StoragePoolType poolType) { + this.poolType = poolType; } @Override diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java index 90781dcd91d6..cc34d7e05ca4 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java @@ -16,42 +16,6 @@ // under the License. package com.cloud.utils.db; -import com.cloud.utils.DateUtil; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.Ternary; -import com.cloud.utils.component.ComponentLifecycle; -import com.cloud.utils.component.ComponentLifecycleBase; -import com.cloud.utils.component.ComponentMethodInterceptable; -import com.cloud.utils.crypt.DBEncryptionUtil; -import com.cloud.utils.db.SearchCriteria.SelectType; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.Ip; -import com.cloud.utils.net.NetUtils; -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.NoOp; -import net.sf.ehcache.Cache; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.Element; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.log4j.Logger; - -import javax.naming.ConfigurationException; -import javax.persistence.AttributeConverter; -import javax.persistence.AttributeOverride; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.EmbeddedId; -import javax.persistence.EntityExistsException; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Table; -import javax.persistence.TableGenerator; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; @@ -83,37 +47,77 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import javax.naming.ConfigurationException; +import javax.persistence.AttributeConverter; +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.EmbeddedId; +import javax.persistence.EntityExistsException; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Table; +import javax.persistence.TableGenerator; + +import org.apache.log4j.Logger; + +import com.cloud.utils.DateUtil; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ComponentLifecycle; +import com.cloud.utils.component.ComponentLifecycleBase; +import com.cloud.utils.component.ComponentMethodInterceptable; +import com.cloud.utils.crypt.DBEncryptionUtil; +import com.cloud.utils.db.SearchCriteria.SelectType; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.NoOp; +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Element; + /** - * GenericDaoBase is a simple way to implement DAOs. It DOES NOT - * support the full EJB3 spec. It borrows some of the annotations from - * the EJB3 spec to produce a set of SQLs so developers don't have to - * copy and paste the same code over and over again. Of course, - * GenericDaoBase is completely at the mercy of the annotations you add - * to your entity bean. If GenericDaoBase does not fit your needs, then - * don't extend from it. - *

- * GenericDaoBase attempts to achieve the following: - * 1. If you use _allFieldsStr in your SQL statement and use to() to convert - * the result to the entity bean, you don't ever have to worry about - * missing fields because its automatically taken from the entity bean's - * annotations. - * 2. You don't have to rewrite the same insert and select query strings - * in all of your DAOs. - * 3. You don't have to match the '?' (you know what I'm talking about) to - * the fields in the insert statement as that's taken care of for you. - *

- * GenericDaoBase looks at the following annotations: - * 1. Table - just name - * 2. Column - just name - * 3. GeneratedValue - any field with this annotation is not inserted. - * 4. SequenceGenerator - sequence generator - * 5. Id - * 6. SecondaryTable - *

- * Sometime later, I might look into injecting the SQLs as needed but right - * now we have to construct them at construction time. The good thing is that - * the DAOs are suppose to be one per jvm so the time is all during the - * initial load. + * GenericDaoBase is a simple way to implement DAOs. It DOES NOT + * support the full EJB3 spec. It borrows some of the annotations from + * the EJB3 spec to produce a set of SQLs so developers don't have to + * copy and paste the same code over and over again. Of course, + * GenericDaoBase is completely at the mercy of the annotations you add + * to your entity bean. If GenericDaoBase does not fit your needs, then + * don't extend from it. + * + * GenericDaoBase attempts to achieve the following: + * 1. If you use _allFieldsStr in your SQL statement and use to() to convert + * the result to the entity bean, you don't ever have to worry about + * missing fields because its automatically taken from the entity bean's + * annotations. + * 2. You don't have to rewrite the same insert and select query strings + * in all of your DAOs. + * 3. You don't have to match the '?' (you know what I'm talking about) to + * the fields in the insert statement as that's taken care of for you. + * + * GenericDaoBase looks at the following annotations: + * 1. Table - just name + * 2. Column - just name + * 3. GeneratedValue - any field with this annotation is not inserted. + * 4. SequenceGenerator - sequence generator + * 5. Id + * 6. SecondaryTable + * + * Sometime later, I might look into injecting the SQLs as needed but right + * now we have to construct them at construction time. The good thing is that + * the DAOs are suppose to be one per jvm so the time is all during the + * initial load. + * **/ @DB public abstract class GenericDaoBase extends ComponentLifecycleBase implements GenericDao, ComponentMethodInterceptable { @@ -170,7 +174,7 @@ public abstract class GenericDaoBase extends Compone public static GenericDao getDao(Class entityType) { @SuppressWarnings("unchecked") - GenericDao dao = (GenericDao) s_daoMaps.get(entityType); + GenericDao dao = (GenericDao)s_daoMaps.get(entityType); assert dao != null : "Unable to find DAO for " + entityType + ". Are you sure you waited for the DAO to be initialized before asking for it?"; return dao; } @@ -189,8 +193,8 @@ public Map getAllAttributes() { @SuppressWarnings("unchecked") public T createSearchEntity(MethodInterceptor interceptor) { - T entity = (T) _searchEnhancer.create(); - final Factory factory = (Factory) entity; + T entity = (T)_searchEnhancer.create(); + final Factory factory = (Factory)entity; factory.setCallback(0, interceptor); return entity; } @@ -200,11 +204,11 @@ protected GenericDaoBase() { super(); Type t = getClass().getGenericSuperclass(); if (t instanceof ParameterizedType) { - _entityBeanType = (Class) ((ParameterizedType) t).getActualTypeArguments()[0]; - } else if (((Class) t).getGenericSuperclass() instanceof ParameterizedType) { - _entityBeanType = (Class) ((ParameterizedType) ((Class) t).getGenericSuperclass()).getActualTypeArguments()[0]; + _entityBeanType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; + } else if (((Class)t).getGenericSuperclass() instanceof ParameterizedType) { + _entityBeanType = (Class)((ParameterizedType)((Class)t).getGenericSuperclass()).getActualTypeArguments()[0]; } else { - _entityBeanType = (Class) ((ParameterizedType) ((Class) ((Class) t).getGenericSuperclass()).getGenericSuperclass()).getActualTypeArguments()[0]; + _entityBeanType = (Class)((ParameterizedType)((Class)((Class)t).getGenericSuperclass()).getGenericSuperclass()).getActualTypeArguments()[0]; } s_daoMaps.put(_entityBeanType, this); @@ -220,7 +224,7 @@ protected GenericDaoBase() { final SqlGenerator generator = new SqlGenerator(_entityBeanType); _partialSelectSql = generator.buildSelectSql(false); _count = generator.buildCountSql(); - _distinctIdSql = generator.buildDistinctIdSql(); + _distinctIdSql= generator.buildDistinctIdSql(); _partialQueryCacheSelectSql = generator.buildSelectSql(true); _embeddedFields = generator.getEmbeddedFields(); _insertSqls = generator.buildInsertSqls(); @@ -252,13 +256,13 @@ protected GenericDaoBase() { _tgs.put(tg.name(), tg); } - Callback[] callbacks = new Callback[]{NoOp.INSTANCE, new UpdateBuilder(this)}; + Callback[] callbacks = new Callback[] {NoOp.INSTANCE, new UpdateBuilder(this)}; _enhancer = new Enhancer(); _enhancer.setSuperclass(_entityBeanType); _enhancer.setCallbackFilter(s_callbackFilter); _enhancer.setCallbacks(callbacks); - _factory = (Factory) _enhancer.create(); + _factory = (Factory)_enhancer.create(); _searchEnhancer = new Enhancer(); _searchEnhancer.setSuperclass(_entityBeanType); @@ -281,11 +285,12 @@ protected GenericDaoBase() { s_logger.trace("Collection SQLs"); for (Attribute attr : _ecAttributes) { - EcInfo info = (EcInfo) attr.attache; + EcInfo info = (EcInfo)attr.attache; s_logger.trace(info.insertSql); s_logger.trace(info.selectSql); } } + _conversionSupport = new ConversionSupport(); setRunLevel(ComponentLifecycle.RUN_LEVEL_SYSTEM); } @@ -294,7 +299,7 @@ protected GenericDaoBase() { @DB() @SuppressWarnings("unchecked") public T createForUpdate(final ID id) { - final T entity = (T) _factory.newInstance(new Callback[]{NoOp.INSTANCE, new UpdateBuilder(this)}); + final T entity = (T)_factory.newInstance(new Callback[] {NoOp.INSTANCE, new UpdateBuilder(this)}); if (id != null) { try { _idField.set(entity, id); @@ -434,7 +439,7 @@ public List customSearchIncludingRemoved(SearchCriteria sc, final Filt throw new CloudRuntimeException("Call to customSearchIncludingRemoved with null search Criteria"); } if (sc.isSelectAll()) { - return (List) searchIncludingRemoved((SearchCriteria) sc, filter, null, false); + return (List)searchIncludingRemoved((SearchCriteria)sc, filter, null, false); } String clause = sc.getWhereClause(); if (clause != null && clause.length() == 0) { @@ -484,7 +489,7 @@ public List customSearchIncludingRemoved(SearchCriteria sc, final Filt List fields = sc.getSelectFields(); while (rs.next()) { if (st == SelectType.Entity) { - results.add((M) toEntityBean(rs, false)); + results.add((M)toEntityBean(rs, false)); } else if (st == SelectType.Fields || st == SelectType.Result) { M m = sc.getResultType().newInstance(); for (int j = 1; j <= fields.size(); j++) { @@ -549,7 +554,7 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr final Enumerated enumerated = field.getAnnotation(Enumerated.class); final EnumType enumType = (enumerated == null) ? EnumType.STRING : enumerated.value(); - final Enum[] enums = (Enum[]) field.getType().getEnumConstants(); + final Enum[] enums = (Enum[])field.getType().getEnumConstants(); for (final Enum e : enums) { if ((enumType == EnumType.STRING && e.name().equalsIgnoreCase(rs.getString(index))) || (enumType == EnumType.ORDINAL && e.ordinal() == rs.getInt(index))) { @@ -660,9 +665,12 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr /** * Get a value from a result set. * - * @param type the expected type of the result - * @param rs the result set - * @param index the index of the column + * @param type + * the expected type of the result + * @param rs + * the result set + * @param index + * the index of the column * @return the result in the requested type * @throws SQLException */ @@ -673,7 +681,7 @@ protected static M getObject(Class type, ResultSet rs, int index) throws byte[] bytes = rs.getBytes(index); if (bytes != null) { try { - return (M) new String(bytes, "UTF-8"); + return (M)new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new CloudRuntimeException("UnsupportedEncodingException exception while converting UTF-8 data"); } @@ -701,7 +709,7 @@ protected static M getObject(Class type, ResultSet rs, int index) throws if (data == null) { return null; } else { - return (M) DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index)); + return (M)DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index)); } } else if (type == short.class) { return (M) (Short) rs.getShort(index); @@ -750,12 +758,12 @@ protected static M getObject(Class type, ResultSet rs, int index) throws } else { final Calendar cal = Calendar.getInstance(); cal.setTime(DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index))); - return (M) cal; + return (M)cal; } } else if (type == byte[].class) { - return (M) rs.getBytes(index); + return (M)rs.getBytes(index); } else { - return (M) rs.getObject(index); + return (M)rs.getObject(index); } } @@ -847,7 +855,6 @@ public int update(UpdateBuilder ub, final SearchCriteria sc, Integer rows) { /** * If the SQLException.getSQLState is of 23000 (Integrity Constraint Violation), and the Error Code is 1062 (Duplicate Entry), throws EntityExistsException. - * * @throws EntityExistsException */ protected static void handleEntityExistsException(SQLException e) throws EntityExistsException { @@ -956,7 +963,7 @@ public T findById(final ID id) { if (element == null) { result = lockRow(id, null); } else { - result = (T) element.getObjectValue(); + result = (T)element.getObjectValue(); } } else { result = lockRow(id, null); @@ -989,7 +996,7 @@ public T findByIdIncludingRemoved(final ID id) { if (element == null) { result = findById(id, true, null); } else { - result = (T) element.getObjectValue(); + result = (T)element.getObjectValue(); } } else { result = findById(id, true, null); @@ -1376,7 +1383,6 @@ public Pair, Integer> searchAndCount(SearchCriteria sc, final Filter /** * Validates if the count of records is higher or equal to the result set's size.

* Count cannot be less than the result set, however, it can be higher due to pagination (see CLOUDSTACK-10320). - * * @return Count if it is higher or equal to the result set's size, otherwise the result set's size. */ protected int checkCountOfRecordsAgainstTheResultSetSize(int count, int resultSetSize) { @@ -1454,7 +1460,7 @@ public T persist(final T entity) { if (_idField != null) { ID id; try { - id = (ID) _idField.get(entity); + id = (ID)_idField.get(entity); } catch (IllegalAccessException e) { throw new CloudRuntimeException("How can it be illegal access...come on", e); } @@ -1485,7 +1491,7 @@ public T persist(final T entity) { final ResultSet rs = pstmt.getGeneratedKeys(); if (id == null) { if (rs != null && rs.next()) { - id = (ID) rs.getObject(1); + id = (ID)rs.getObject(1); } try { if (_idField != null) { @@ -1496,7 +1502,7 @@ public T persist(final T entity) { _idField.set(entity, id); } } else { - id = (ID) _idField.get(entity); + id = (ID)_idField.get(entity); } } } catch (final IllegalAccessException e) { @@ -1536,12 +1542,12 @@ protected void insertElementCollection(T entity, Attribute idAttribute, ID id, M Attribute attr = entry.getKey(); Object obj = entry.getValue(); - EcInfo ec = (EcInfo) attr.attache; + EcInfo ec = (EcInfo)attr.attache; Enumeration en = null; if (ec.rawClass == null) { - en = Collections.enumeration(Arrays.asList((Object[]) obj)); + en = Collections.enumeration(Arrays.asList((Object[])obj)); } else { - en = Collections.enumeration((Collection) obj); + en = Collections.enumeration((Collection)obj); } PreparedStatement pstmt = txn.prepareAutoCloseStatement(ec.clearSql); prepareAttribute(1, pstmt, idAttribute, id); @@ -1550,7 +1556,7 @@ protected void insertElementCollection(T entity, Attribute idAttribute, ID id, M while (en.hasMoreElements()) { pstmt = txn.prepareAutoCloseStatement(ec.insertSql); if (ec.targetClass == Date.class) { - pstmt.setString(1, DateUtil.getDateDisplayString(s_gmtTimeZone, (Date) en.nextElement())); + pstmt.setString(1, DateUtil.getDateDisplayString(s_gmtTimeZone, (Date)en.nextElement())); } else { pstmt.setObject(1, en.nextElement()); } @@ -1594,9 +1600,16 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina return; } } - if (attr.field.getType() == String.class) { - // convert value to DB column type if needed - final String str = _conversionSupport.convertToDatabaseColumn(attr.field, value); + if(attr.field.getDeclaredAnnotation(Convert.class) != null) { + try { + Object val = _conversionSupport.convertToDatabaseColumn(attr.field, value); + pstmt.setObject(j, val); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } else if (attr.field.getType() == String.class) { + final String str = (String)value; if (str == null) { pstmt.setString(j, null); return; @@ -1631,7 +1644,7 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina } } } else if (attr.field.getType() == Date.class) { - final Date date = (Date) value; + final Date date = (Date)value; if (date == null || date.equals(DATE_TO_NULL)) { pstmt.setObject(j, null); return; @@ -1644,7 +1657,7 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, date)); } } else if (attr.field.getType() == Calendar.class) { - final Calendar cal = (Calendar) value; + final Calendar cal = (Calendar)value; if (cal == null) { pstmt.setObject(j, null); return; @@ -1665,15 +1678,15 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina if (value == null) { pstmt.setObject(j, null); } else { - pstmt.setInt(j, ((Enum) value).ordinal()); + pstmt.setInt(j, ((Enum)value).ordinal()); } } } else if (attr.field.getType() == URI.class) { pstmt.setString(j, value == null ? null : value.toString()); } else if (attr.field.getType() == URL.class) { - pstmt.setURL(j, (URL) value); + pstmt.setURL(j, (URL)value); } else if (attr.field.getType() == byte[].class) { - pstmt.setBytes(j, (byte[]) value); + pstmt.setBytes(j, (byte[])value); } else if (attr.field.getType() == Ip.class) { final Enumerated enumerated = attr.field.getAnnotation(Enumerated.class); final EnumType type = (enumerated == null) ? EnumType.ORDINAL : enumerated.value(); @@ -1683,7 +1696,7 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina if (value == null) { pstmt.setObject(j, null); } else { - pstmt.setLong(j, (value instanceof Ip) ? ((Ip) value).longValue() : NetUtils.ip2Long((String) value)); + pstmt.setLong(j, (value instanceof Ip) ? ((Ip)value).longValue() : NetUtils.ip2Long((String)value)); } } } else { @@ -1711,7 +1724,7 @@ protected int prepareAttributes(final PreparedStatement pstmt, final Object enti @SuppressWarnings("unchecked") @DB() protected T toEntityBean(final ResultSet result, final boolean cache) throws SQLException { - final T entity = (T) _factory.newInstance(new Callback[]{NoOp.INSTANCE, new UpdateBuilder(this)}); + final T entity = (T)_factory.newInstance(new Callback[] {NoOp.INSTANCE, new UpdateBuilder(this)}); toEntityBean(result, entity); @@ -1762,11 +1775,13 @@ protected void toEntityBean(final ResultSet result, final T entity) throws SQLEx @DB() @SuppressWarnings("unchecked") protected void loadCollection(T entity, Attribute attr) { - EcInfo ec = (EcInfo) attr.attache; + EcInfo ec = (EcInfo)attr.attache; TransactionLegacy txn = TransactionLegacy.currentTxn(); - try (PreparedStatement pstmt = txn.prepareStatement(ec.selectSql);) { + try(PreparedStatement pstmt = txn.prepareStatement(ec.selectSql);) + { pstmt.setObject(1, _idField.get(entity)); - try (ResultSet rs = pstmt.executeQuery();) { + try(ResultSet rs = pstmt.executeQuery();) + { ArrayList lst = new ArrayList(); if (ec.targetClass == Integer.class) { while (rs.next()) { @@ -1816,15 +1831,16 @@ protected void loadCollection(T entity, Attribute attr) { throw new CloudRuntimeException("Never should happen", e); } } - } catch (SQLException e) { - throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); + } + catch (SQLException e) { + throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); } } catch (SQLException e) { - throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); + throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); } catch (IllegalArgumentException e) { - throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); + throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); } catch (IllegalAccessException e) { - throw new CloudRuntimeException("loadCollection: Exception : " + e.getMessage(), e); + throw new CloudRuntimeException("loadCollection: Exception : " +e.getMessage(), e); } } @@ -1936,13 +1952,13 @@ public int remove(SearchCriteria sc) { @DB() protected void createCache(final Map params) { - final String value = (String) params.get("cache.size"); + final String value = (String)params.get("cache.size"); if (value != null) { final CacheManager cm = CacheManager.create(); final int maxElements = NumbersUtil.parseInt(value, 0); - final int live = NumbersUtil.parseInt((String) params.get("cache.time.to.live"), 300); - final int idle = NumbersUtil.parseInt((String) params.get("cache.time.to.idle"), 300); + final int live = NumbersUtil.parseInt((String)params.get("cache.time.to.live"), 300); + final int idle = NumbersUtil.parseInt((String)params.get("cache.time.to.idle"), 300); _cache = new Cache(getName(), maxElements, false, live == -1, live == -1 ? Integer.MAX_VALUE : live, idle); cm.addCache(_cache); s_logger.info("Cache created: " + _cache.toString()); @@ -1956,11 +1972,11 @@ protected void createCache(final Map params) { public boolean configure(final String name, final Map params) throws ConfigurationException { _name = name; - final String value = (String) params.get("lock.timeout"); + final String value = (String)params.get("lock.timeout"); _timeoutSeconds = NumbersUtil.parseInt(value, 300); createCache(params); - final boolean load = Boolean.parseBoolean((String) params.get("cache.preload")); + final boolean load = Boolean.parseBoolean((String)params.get("cache.preload")); if (load) { listAll(); } @@ -1970,9 +1986,9 @@ public boolean configure(final String name, final Map params) th @DB() public static UpdateBuilder getUpdateBuilder(final T entityObject) { - final Factory factory = (Factory) entityObject; + final Factory factory = (Factory)entityObject; assert (factory != null); - return (UpdateBuilder) factory.getCallback(1); + return (UpdateBuilder)factory.getCallback(1); } @Override @@ -2263,4 +2279,5 @@ private Optional> getConverter(Field field) { }); } } + } diff --git a/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java b/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java index 6383c0a12060..385ed3273ac1 100644 --- a/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java +++ b/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/MockStoragePoolVO.java @@ -17,12 +17,14 @@ package com.cloud.simulator; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; +import com.cloud.util.StoragePoolTypeConverter; import org.apache.cloudstack.api.InternalIdentity; import com.cloud.storage.Storage.StoragePoolType; @@ -48,7 +50,8 @@ public class MockStoragePoolVO implements InternalIdentity { private String hostGuid; @Column(name = "pool_type") - private String poolType; + @Convert(converter = StoragePoolTypeConverter.class) + private StoragePoolType poolType; public MockStoragePoolVO() { @@ -68,11 +71,11 @@ public long getId() { } public StoragePoolType getPoolType() { - return StoragePoolType.valueOf(this.poolType); + return this.poolType; } public void setStorageType(StoragePoolType poolType) { - this.poolType = poolType.name(); + this.poolType = poolType; } public String getUuid() { diff --git a/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java b/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java index ea9bcc4063cb..c656b84289d2 100644 --- a/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java +++ b/plugins/hypervisors/simulator/src/main/java/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java @@ -52,7 +52,7 @@ public MockStoragePoolDaoImpl() { public MockStoragePoolVO findByHost(String hostUuid) { SearchCriteria sc = hostguidSearch.create(); sc.setParameters("hostguid", hostUuid); - sc.setParameters("type", StoragePoolType.Filesystem.toString()); + sc.setParameters("type", StoragePoolType.Filesystem); return findOneBy(sc); } diff --git a/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java index 03f7ceb0633b..85e904be9736 100644 --- a/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/StoragePoolJoinVO.java @@ -19,12 +19,14 @@ import java.util.Date; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; +import com.cloud.util.StoragePoolTypeConverter; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -64,7 +66,8 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I private StoragePoolStatus status; @Column(name = "pool_type") - private String poolType; + @Convert(converter = StoragePoolTypeConverter.class) + private StoragePoolType poolType; @Column(name = GenericDao.CREATED_COLUMN) private Date created; @@ -182,7 +185,7 @@ public StoragePoolStatus getStatus() { } public StoragePoolType getPoolType() { - return StoragePoolType.valueOf(poolType); + return poolType; } public Date getCreated() { diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index 198762ae5a8f..dc4f2903f16f 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -2474,7 +2474,7 @@ public List listByStoragePool(long storagePoolId) { @DB public StoragePoolVO findLocalStorageOnHost(long hostId) { SearchCriteria sc = LocalStorageSearch.create(); - sc.setParameters("type", StoragePoolType.Filesystem.toString(), StoragePoolType.LVM.toString()); + sc.setParameters("type", StoragePoolType.Filesystem, StoragePoolType.LVM); sc.setJoinParameters("poolHost", "hostId", hostId); List storagePools = _storagePoolDao.search(sc, null); if (!storagePools.isEmpty()) { From 38108b492ac5a6de8b40795adc9985a1271e8586 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 29 Nov 2023 09:29:26 -0800 Subject: [PATCH 08/18] Fixed equals for the enum. --- .../apache/cloudstack/storage/datastore/db/StoragePoolVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 9b357dfee4ce..27179a8467ed 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -275,7 +275,7 @@ public void setHostAddress(String host) { @Override public String getPath() { String updatedPath = path; - if (poolType.equals(StoragePoolType.SMB.name())) { + if (poolType.equals(StoragePoolType.SMB)) { updatedPath = UriUtils.getUpdateUri(updatedPath, false); if (updatedPath.contains("password") && updatedPath.contains("?")) { updatedPath = updatedPath.substring(0, updatedPath.indexOf('?')); From 4c40bdcf7266e8dd4f19832d78fce970e3730b73 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 29 Nov 2023 09:56:46 -0800 Subject: [PATCH 09/18] removed not needed try/catch for prepareAttribute --- .../src/main/java/com/cloud/utils/db/GenericDaoBase.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java index cc34d7e05ca4..3e711a5058a2 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java @@ -1601,13 +1601,8 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina } } if(attr.field.getDeclaredAnnotation(Convert.class) != null) { - try { - Object val = _conversionSupport.convertToDatabaseColumn(attr.field, value); - pstmt.setObject(j, val); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + Object val = _conversionSupport.convertToDatabaseColumn(attr.field, value); + pstmt.setObject(j, val); } else if (attr.field.getType() == String.class) { final String str = (String)value; if (str == null) { From d33197c74838fd5379877c9055840c26470fc183 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 29 Nov 2023 10:06:58 -0800 Subject: [PATCH 10/18] Added license to the file. --- .../com/cloud/util/StoragePoolTypeConverter.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java b/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java index 4f1e777606ba..ab4148ec8341 100644 --- a/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java +++ b/engine/schema/src/main/java/com/cloud/util/StoragePoolTypeConverter.java @@ -1,3 +1,19 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. package com.cloud.util; import com.cloud.storage.Storage.StoragePoolType; From 9f252f9bdb125a0dc1ed1b3a18c27d132bf1c8f9 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 6 Dec 2023 09:59:06 -0800 Subject: [PATCH 11/18] Implemented "supportsPhysicalDiskCopy" for storage adaptor. Co-authored-by: mprokopchuk --- .../hypervisor/kvm/storage/KVMStoragePoolManager.java | 7 +++++++ .../cloud/hypervisor/kvm/storage/KVMStorageProcessor.java | 2 +- .../com/cloud/hypervisor/kvm/storage/StorageAdaptor.java | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java index 6598b08f879a..918eb9b6b6b7 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java @@ -142,6 +142,13 @@ public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) { } } + /** + * Returns true if physical disk copy functionality supported. + */ + public boolean supportsPhysicalDiskCopy(StoragePoolType type) { + return getStorageAdaptor(type).supportsPhysicalDiskCopy(type); + } + public boolean connectPhysicalDisk(StoragePoolType type, String poolUuid, String volPath, Map details) { StorageAdaptor adaptor = getStorageAdaptor(type); KVMStoragePool pool = adaptor.getStoragePool(poolUuid); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 1be4a8b61851..f958a1b181d4 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -403,7 +403,7 @@ public Answer cloneVolumeFromBaseTemplate(final CopyCommand cmd) { if (primaryPool.getType() == StoragePoolType.CLVM) { templatePath = ((NfsTO)imageStore).getUrl() + File.separator + templatePath; vol = templateToPrimaryDownload(templatePath, primaryPool, volume.getUuid(), volume.getSize(), cmd.getWaitInMillSeconds()); - } if (primaryPool.getType() == StoragePoolType.PowerFlex) { + } if (storagePoolMgr.supportsPhysicalDiskCopy(primaryPool.getType())) { Map details = primaryStore.getDetails(); String path = details != null ? details.get("managedStoreTarget") : null; diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java index 8db672ad7f7e..34bf08f4496a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java @@ -93,4 +93,11 @@ KVMPhysicalDisk createDiskFromTemplateBacking(KVMPhysicalDisk template, * @param timeout */ KVMPhysicalDisk createTemplateFromDirectDownloadFile(String templateFilePath, String destTemplatePath, KVMStoragePool destPool, Storage.ImageFormat format, int timeout); + + /** + * Returns true if storage adaptor supports physical disk copy functionality. + */ + default boolean supportsPhysicalDiskCopy(StoragePoolType type) { + return StoragePoolType.PowerFlex == type; + } } From 17e9cff2bd489fec493ed26fa69279990382ff90 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Tue, 12 Dec 2023 09:15:47 -0700 Subject: [PATCH 12/18] Add javadoc to StoragePoolType class --- .../main/java/com/cloud/storage/Storage.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java index b5b6fd9d9da4..61d0cc64d3d6 100644 --- a/api/src/main/java/com/cloud/storage/Storage.java +++ b/api/src/main/java/com/cloud/storage/Storage.java @@ -138,6 +138,17 @@ public static enum TemplateType { ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */ } + /** + * StoragePoolTypes carry some details about the format and capabilities of a storage pool. While not necessarily a + * 1:1 with PrimaryDataStoreDriver (and for KVM agent, KVMStoragePool and StorageAdaptor) implementations, it is + * often used to decide which storage plugin or storage command to call, so it may be necessary for new storage + * plugins to add a StoragePoolType. This can be done by adding it below, or by creating a new public static final + * instance of StoragePoolType in the plugin itself, which registers it with the map. + * + * Note that if the StoragePoolType is for KVM and defined in plugin code rather than below, care must be taken to + * ensure this is available on the agent side as well. This is best done by defining the StoragePoolType in a common + * package available on both management server and agent plugin jars. + */ public static class StoragePoolType { private static final Map map = new LinkedHashMap<>(); @@ -169,6 +180,13 @@ public static class StoragePoolType { private final boolean overprovisioning; private final boolean encryption; + /** + * Define a new StoragePoolType, and register it into the map of pool types known to the management server. + * @param name Simple unique name of the StoragePoolType. + * @param shared Storage pool is shared/accessible to multiple hypervisors + * @param overprovisioning Storage pool supports overprovisioning + * @param encryption Storage pool supports encrypted volumes + */ public StoragePoolType(String name, boolean shared, boolean overprovisioning, boolean encryption) { this.name = name; this.shared = shared; From 9af44328524399edc3f6da00b675c6ca6c706abe Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Fri, 15 Dec 2023 16:13:17 -0700 Subject: [PATCH 13/18] Add unit test for StoragePoolType comparisons --- api/src/test/java/com/cloud/storage/StorageTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/src/test/java/com/cloud/storage/StorageTest.java b/api/src/test/java/com/cloud/storage/StorageTest.java index 951ee9fe76a1..5f40db46dea3 100644 --- a/api/src/test/java/com/cloud/storage/StorageTest.java +++ b/api/src/test/java/com/cloud/storage/StorageTest.java @@ -74,4 +74,13 @@ public void supportsOverprovisioningStoragePool() { Assert.assertTrue(StoragePoolType.DatastoreCluster.supportsOverProvisioning()); Assert.assertTrue(StoragePoolType.Linstor.supportsOverProvisioning()); } + + @Test + public void equalityTest() { + StoragePoolType t1 = StoragePoolType.NetworkFilesystem; + StoragePoolType t2 = StoragePoolType.NetworkFilesystem; + Assert.assertTrue(t1 == StoragePoolType.NetworkFilesystem); + Assert.assertTrue(t1.equals(StoragePoolType.NetworkFilesystem)); + Assert.assertFalse(t1.equals(StoragePoolType.EXT)); + } } From edecd06b2ec6065c70168bd6801646c3f00a7ff1 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 10 Jan 2024 15:09:13 -0800 Subject: [PATCH 14/18] StoragePoolType "==" and ".equals()" fix. --- .../main/java/com/cloud/storage/Storage.java | 14 +++++ .../transport/StoragePoolTypeAdaptor.java | 53 +++++++++++++++++++ .../java/com/cloud/serializer/GsonHelper.java | 3 ++ 3 files changed, 70 insertions(+) create mode 100644 core/src/main/java/com/cloud/agent/transport/StoragePoolTypeAdaptor.java diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java index 61d0cc64d3d6..c97a87262f6e 100644 --- a/api/src/main/java/com/cloud/storage/Storage.java +++ b/api/src/main/java/com/cloud/storage/Storage.java @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; public class Storage { public static enum ImageFormat { @@ -233,6 +234,19 @@ public String toString() { public String name() { return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StoragePoolType that = (StoragePoolType) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } } public static List getNonSharedStoragePoolTypes() { diff --git a/core/src/main/java/com/cloud/agent/transport/StoragePoolTypeAdaptor.java b/core/src/main/java/com/cloud/agent/transport/StoragePoolTypeAdaptor.java new file mode 100644 index 000000000000..635f6d06cf57 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/transport/StoragePoolTypeAdaptor.java @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.transport; + +import com.cloud.storage.Storage.StoragePoolType; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +/** + * {@link StoragePoolType} acts as extendable set of singleton objects and should return same result when used "==" + * or {@link Object#equals(Object)}. + * To support that, need to return existing object for a given name instead of creating new. + */ +public class StoragePoolTypeAdaptor implements JsonDeserializer, JsonSerializer { + @Override + public StoragePoolType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (json instanceof JsonPrimitive && ((JsonPrimitive) json).isString()) { + return StoragePoolType.valueOf(json.getAsString()); + } + return null; + } + + @Override + public JsonElement serialize(StoragePoolType src, Type typeOfSrc, JsonSerializationContext context) { + String name = src.name(); + if (name == null) { + return new JsonNull(); + } + return new JsonPrimitive(name); + } +} diff --git a/core/src/main/java/com/cloud/serializer/GsonHelper.java b/core/src/main/java/com/cloud/serializer/GsonHelper.java index 7ac85d393178..c3653e5089c0 100644 --- a/core/src/main/java/com/cloud/serializer/GsonHelper.java +++ b/core/src/main/java/com/cloud/serializer/GsonHelper.java @@ -37,6 +37,8 @@ import com.cloud.agent.transport.LoggingExclusionStrategy; import com.cloud.agent.transport.Request.NwGroupsCommandTypeAdaptor; import com.cloud.agent.transport.Request.PortConfigListTypeAdaptor; +import com.cloud.agent.transport.StoragePoolTypeAdaptor; +import com.cloud.storage.Storage; import com.cloud.utils.Pair; public class GsonHelper { @@ -69,6 +71,7 @@ static Gson setDefaultGsonConfig(GsonBuilder builder) { }.getType(), new PortConfigListTypeAdaptor()); builder.registerTypeAdapter(new TypeToken>() { }.getType(), new NwGroupsCommandTypeAdaptor()); + builder.registerTypeAdapter(Storage.StoragePoolType.class, new StoragePoolTypeAdaptor()); Gson gson = builder.create(); dsAdaptor.initGson(gson); dtAdaptor.initGson(gson); From 03c7b609af61fc3aff219ee5507b81e090e2974c Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 22 Jan 2024 13:04:02 +0530 Subject: [PATCH 15/18] Fix StoragePoolType for FiberChannelAdapter --- .../cloud/hypervisor/kvm/storage/FiberChannelAdapter.java | 6 +++++- .../hypervisor/kvm/storage/ScaleIOStoragePoolTest.java | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/FiberChannelAdapter.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/FiberChannelAdapter.java index be7cb727ad77..83636b9a9c31 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/FiberChannelAdapter.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/FiberChannelAdapter.java @@ -19,12 +19,16 @@ import com.cloud.storage.Storage; import com.cloud.utils.exception.CloudRuntimeException; -@StorageAdaptorInfo(storagePoolType=Storage.StoragePoolType.FiberChannel) public class FiberChannelAdapter extends MultipathSCSIAdapterBase { public FiberChannelAdapter() { LOGGER.info("Loaded FiberChannelAdapter for StorageLayer"); } + @Override + public Storage.StoragePoolType getStoragePoolType() { + return Storage.StoragePoolType.FiberChannel; + } + @Override public KVMStoragePool getStoragePool(String uuid) { KVMStoragePool pool = MapStorageUuidToStoragePool.get(uuid); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java index bfc48da5a74c..7989f9e6a69e 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java @@ -37,7 +37,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; From 97ec85f2cb298a82bcbbbbfb3690d5687289d2a3 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Tue, 23 Jan 2024 13:10:57 +0530 Subject: [PATCH 16/18] Fix for abstract storage adaptor set up issue --- .../hypervisor/kvm/storage/KVMStoragePoolManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java index 918eb9b6b6b7..679407e2f58c 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java @@ -17,6 +17,7 @@ package com.cloud.hypervisor.kvm.storage; import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; @@ -106,6 +107,10 @@ public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) { Set> storageAdaptorClasses = reflections.getSubTypesOf(StorageAdaptor.class); for (Class storageAdaptorClass : storageAdaptorClasses) { s_logger.debug("Checking pool type for adaptor " + storageAdaptorClass.getName()); + if (Modifier.isAbstract(storageAdaptorClass.getModifiers()) || storageAdaptorClass.isInterface()) { + s_logger.debug("Skipping registration of abstract class / interface " + storageAdaptorClass.getName()); + continue; + } if (storageAdaptorClass.isAssignableFrom(LibvirtStorageAdaptor.class)) { s_logger.debug("Skipping re-registration of LibvirtStorageAdaptor"); continue; @@ -128,7 +133,7 @@ public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) { if (this._storageMapper.containsKey(storagePoolType.toString())) { s_logger.warn(String.format("Duplicate StorageAdaptor type %s, not loading %s", storagePoolType, storageAdaptorClass.getName())); } else { - s_logger.info(String.format("adding storage adaptor for %s", storageAdaptorClass.getName())); + s_logger.info(String.format("Adding storage adaptor for %s", storageAdaptorClass.getName())); this._storageMapper.put(storagePoolType.toString(), adaptor); } } From f178724748af14e19a9a6eba9660fb87a5b96495 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Wed, 24 Jan 2024 14:50:53 +0530 Subject: [PATCH 17/18] review comments --- .../db/src/main/java/com/cloud/utils/db/GenericDaoBase.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java index 3e711a5058a2..b46b82f50b06 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java @@ -654,8 +654,11 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr } } else if (type == byte[].class) { field.set(entity, rs.getBytes(index)); + } else if (field.getDeclaredAnnotation(Convert.class) != null) { + Object val = _conversionSupport.convertToEntityAttribute(field, rs.getObject(index)); + field.set(entity, val); } else { - field.set(entity, _conversionSupport.convertToEntityAttribute(field, rs.getObject(index))); + field.set(entity, rs.getObject(index)); } } catch (final IllegalAccessException e) { throw new CloudRuntimeException("Yikes! ", e); From 47d455b6f83a572996181e94deb39e69f328cbb3 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 29 Jan 2024 17:24:18 +0530 Subject: [PATCH 18/18] Pass StoragePoolType object for poolType dao attribute --- .../main/java/com/cloud/storage/Storage.java | 17 ++++++-- .../entity/api/db/EngineHostVO.java | 3 ++ .../datastore/db/PrimaryDataStoreDao.java | 3 +- .../datastore/db/PrimaryDataStoreDaoImpl.java | 3 +- .../api/query/dao/StoragePoolJoinDaoImpl.java | 42 ++++++++++--------- .../com/cloud/storage/StorageManagerImpl.java | 4 +- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java index c97a87262f6e..2ef424adcb0a 100644 --- a/api/src/main/java/com/cloud/storage/Storage.java +++ b/api/src/main/java/com/cloud/storage/Storage.java @@ -16,15 +16,15 @@ // under the License. package com.cloud.storage; -import org.apache.commons.lang.NotImplementedException; -import org.apache.commons.lang3.StringUtils; - import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang3.StringUtils; + public class Storage { public static enum ImageFormat { QCOW2(true, true, false, "qcow2"), @@ -181,6 +181,17 @@ public static class StoragePoolType { private final boolean overprovisioning; private final boolean encryption; + /** + * New StoragePoolType, set the name to check with it in Dao (Note: Do not register it into the map of pool types). + * @param name name of the StoragePoolType. + */ + public StoragePoolType(String name) { + this.name = name; + this.shared = false; + this.overprovisioning = false; + this.encryption = false; + } + /** * Define a new StoragePoolType, and register it into the map of pool types known to the management server. * @param name Simple unique name of the StoragePoolType. diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java index 846b4157786d..5315bca4b9ab 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java @@ -22,6 +22,7 @@ import java.util.UUID; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.Entity; @@ -45,6 +46,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceState; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.util.StoragePoolTypeConverter; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.StateMachine; @@ -126,6 +128,7 @@ public class EngineHostVO implements EngineHost, Identity { private String resource; @Column(name = "fs_type") + @Convert(converter = StoragePoolTypeConverter.class) private StoragePoolType fsType; @Column(name = "available") diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index 8f77b4ba63e9..cfd12862c83a 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -21,6 +21,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage; import com.cloud.storage.StoragePoolStatus; import com.cloud.utils.db.GenericDao; @@ -130,7 +131,7 @@ public interface PrimaryDataStoreDao extends GenericDao { Integer countAll(); - List findPoolsByStorageType(String storageType); + List findPoolsByStorageType(Storage.StoragePoolType storageType); List listStoragePoolsWithActiveVolumesByOfferingId(long offeringid); } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index af7dbdc02259..bcd2d27ad634 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -31,6 +31,7 @@ import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolTagVO; @@ -619,7 +620,7 @@ public List findPoolsInClusters(List clusterIds) { } @Override - public List findPoolsByStorageType(String storageType) { + public List findPoolsByStorageType(Storage.StoragePoolType storageType) { SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("poolType", storageType); return listBy(sc); diff --git a/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java index e75e86108c70..c587eb40f189 100644 --- a/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java @@ -16,6 +16,27 @@ // under the License. package com.cloud.api.query.dao; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.annotation.AnnotationService; +import org.apache.cloudstack.annotation.dao.AnnotationDao; +import org.apache.cloudstack.api.response.StoragePoolResponse; +import org.apache.cloudstack.context.CallContext; +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.PrimaryDataStoreDriver; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +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.cloudstack.utils.jsinterpreter.TagAsRuleHelper; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.StoragePoolJoinVO; import com.cloud.capacity.CapacityManager; @@ -33,25 +54,6 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import org.apache.cloudstack.annotation.AnnotationService; -import org.apache.cloudstack.annotation.dao.AnnotationDao; -import org.apache.cloudstack.api.response.StoragePoolResponse; -import org.apache.cloudstack.context.CallContext; -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.PrimaryDataStoreDriver; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -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.cloudstack.utils.jsinterpreter.TagAsRuleHelper; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; @Component public class StoragePoolJoinDaoImpl extends GenericDaoBase implements StoragePoolJoinDao { @@ -337,7 +339,7 @@ private SearchCriteria createStoragePoolSearchCriteria(Long s if (keyword != null) { SearchCriteria ssc = createSearchCriteria(); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); - ssc.addOr("poolType", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + ssc.addOr("poolType", SearchCriteria.Op.LIKE, new Storage.StoragePoolType("%" + keyword + "%")); sc.addAnd("name", SearchCriteria.Op.SC, ssc); } diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index dc4f2903f16f..8bcb2ac3956c 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -2133,7 +2133,7 @@ public void syncDatastoreClusterStoragePool(long datastoreClusterPoolId, List nfsStoragePools = _storagePoolDao.findPoolsByStorageType(StoragePoolType.NetworkFilesystem.toString()); + List nfsStoragePools = _storagePoolDao.findPoolsByStorageType(StoragePoolType.NetworkFilesystem); for (StoragePoolVO storagePool : nfsStoragePools) { String storagePoolUUID = storagePool.getUuid(); if (childStoragePoolInfo.getName().equalsIgnoreCase(storagePoolUUID.replaceAll("-", ""))) { @@ -2193,7 +2193,7 @@ public void validateChildDatastoresToBeAddedInUpState(StoragePoolVO datastoreClu StoragePoolInfo childStoragePoolInfo = childDataStoreAnswer.getPoolInfo(); StoragePoolVO dataStoreVO = _storagePoolDao.findPoolByUUID(childStoragePoolInfo.getUuid()); if (dataStoreVO == null && childDataStoreAnswer.getPoolType().equalsIgnoreCase("NFS")) { - List nfsStoragePools = _storagePoolDao.findPoolsByStorageType(StoragePoolType.NetworkFilesystem.toString()); + List nfsStoragePools = _storagePoolDao.findPoolsByStorageType(StoragePoolType.NetworkFilesystem); for (StoragePoolVO storagePool : nfsStoragePools) { String storagePoolUUID = storagePool.getUuid(); if (childStoragePoolInfo.getName().equalsIgnoreCase(storagePoolUUID.replaceAll("-", ""))) {