Skip to content

Commit 8ea9fc9

Browse files
sureshanapartiMarcus Sorensenmprokopchuk
authored
StoragePoolType as class (#8544)
* StoragePoolType as a class * Fix agent side StoragePoolType enum to class * Handle StoragePoolType for StoragePoolJoinVO * Since StoragePoolType is a class, it cannot be converted by @Enumerated annotation. Implemented conveter class and logic to utilize @convert annotation. * Fix UserVMJoinVO for StoragePoolType * fixed missing imports * Since StoragePoolType is a class, it cannot be converted by @Enumerated annotation. Implemented conveter class and logic to utilize @convert annotation. * Fixed equals for the enum. * removed not needed try/catch for prepareAttribute * Added license to the file. * Implemented "supportsPhysicalDiskCopy" for storage adaptor. Co-authored-by: mprokopchuk <mprokopchuk@apple.com> * Add javadoc to StoragePoolType class * Add unit test for StoragePoolType comparisons * StoragePoolType "==" and ".equals()" fix. * Fix StoragePoolType for FiberChannelAdapter * Fix for abstract storage adaptor set up issue * review comments * Pass StoragePoolType object for poolType dao attribute --------- Co-authored-by: Marcus Sorensen <mls@apple.com> Co-authored-by: mprokopchuk <mprokopchuk@apple.com> Co-authored-by: mprokopchuk <mprokopchuk@gmail.com>
1 parent d353fcc commit 8ea9fc9

File tree

34 files changed

+441
-123
lines changed

34 files changed

+441
-123
lines changed

api/src/main/java/com/cloud/storage/Storage.java

Lines changed: 107 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
// under the License.
1717
package com.cloud.storage;
1818

19-
import org.apache.commons.lang.NotImplementedException;
20-
2119
import java.util.ArrayList;
20+
import java.util.LinkedHashMap;
2221
import java.util.List;
22+
import java.util.Map;
23+
import java.util.Objects;
24+
25+
import org.apache.commons.lang.NotImplementedException;
26+
import org.apache.commons.lang3.StringUtils;
2327

2428
public class Storage {
2529
public static enum ImageFormat {
@@ -135,37 +139,72 @@ public static enum TemplateType {
135139
ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */
136140
}
137141

138-
public static enum StoragePoolType {
139-
Filesystem(false, true, true), // local directory
140-
NetworkFilesystem(true, true, true), // NFS
141-
IscsiLUN(true, false, false), // shared LUN, with a clusterfs overlay
142-
Iscsi(true, false, false), // for e.g., ZFS Comstar
143-
ISO(false, false, false), // for iso image
144-
LVM(false, false, false), // XenServer local LVM SR
145-
CLVM(true, false, false),
146-
RBD(true, true, false), // http://libvirt.org/storage.html#StorageBackendRBD
147-
SharedMountPoint(true, false, true),
148-
VMFS(true, true, false), // VMware VMFS storage
149-
PreSetup(true, true, false), // for XenServer, Storage Pool is set up by customers.
150-
EXT(false, true, false), // XenServer local EXT SR
151-
OCFS2(true, false, false),
152-
SMB(true, false, false),
153-
Gluster(true, false, false),
154-
PowerFlex(true, true, true), // Dell EMC PowerFlex/ScaleIO (formerly VxFlexOS)
155-
ManagedNFS(true, false, false),
156-
Linstor(true, true, false),
157-
DatastoreCluster(true, true, false), // for VMware, to abstract pool of clusters
158-
StorPool(true, true, true),
159-
FiberChannel(true, true, false); // Fiber Channel Pool for KVM hypervisors is used to find the volume by WWN value (/dev/disk/by-id/wwn-<wwnvalue>)
160-
142+
/**
143+
* StoragePoolTypes carry some details about the format and capabilities of a storage pool. While not necessarily a
144+
* 1:1 with PrimaryDataStoreDriver (and for KVM agent, KVMStoragePool and StorageAdaptor) implementations, it is
145+
* often used to decide which storage plugin or storage command to call, so it may be necessary for new storage
146+
* plugins to add a StoragePoolType. This can be done by adding it below, or by creating a new public static final
147+
* instance of StoragePoolType in the plugin itself, which registers it with the map.
148+
*
149+
* Note that if the StoragePoolType is for KVM and defined in plugin code rather than below, care must be taken to
150+
* ensure this is available on the agent side as well. This is best done by defining the StoragePoolType in a common
151+
* package available on both management server and agent plugin jars.
152+
*/
153+
public static class StoragePoolType {
154+
private static final Map<String, StoragePoolType> map = new LinkedHashMap<>();
155+
156+
public static final StoragePoolType Filesystem = new StoragePoolType("Filesystem", false, true, true);
157+
public static final StoragePoolType NetworkFilesystem = new StoragePoolType("NetworkFilesystem", true, true, true);
158+
public static final StoragePoolType IscsiLUN = new StoragePoolType("IscsiLUN", true, false, false);
159+
public static final StoragePoolType Iscsi = new StoragePoolType("Iscsi", true, false, false);
160+
public static final StoragePoolType ISO = new StoragePoolType("ISO", false, false, false);
161+
public static final StoragePoolType LVM = new StoragePoolType("LVM", false, false, false);
162+
public static final StoragePoolType CLVM = new StoragePoolType("CLVM", true, false, false);
163+
public static final StoragePoolType RBD = new StoragePoolType("RBD", true, true, false);
164+
public static final StoragePoolType SharedMountPoint = new StoragePoolType("SharedMountPoint", true, false, true);
165+
public static final StoragePoolType VMFS = new StoragePoolType("VMFS", true, true, false);
166+
public static final StoragePoolType PreSetup = new StoragePoolType("PreSetup", true, true, false);
167+
public static final StoragePoolType EXT = new StoragePoolType("EXT", false, true, false);
168+
public static final StoragePoolType OCFS2 = new StoragePoolType("OCFS2", true, false, false);
169+
public static final StoragePoolType SMB = new StoragePoolType("SMB", true, false, false);
170+
public static final StoragePoolType Gluster = new StoragePoolType("Gluster", true, false, false);
171+
public static final StoragePoolType PowerFlex = new StoragePoolType("PowerFlex", true, true, true);
172+
public static final StoragePoolType ManagedNFS = new StoragePoolType("ManagedNFS", true, false, false);
173+
public static final StoragePoolType Linstor = new StoragePoolType("Linstor", true, true, false);
174+
public static final StoragePoolType DatastoreCluster = new StoragePoolType("DatastoreCluster", true, true, false);
175+
public static final StoragePoolType StorPool = new StoragePoolType("StorPool", true,true,true);
176+
public static final StoragePoolType FiberChannel = new StoragePoolType("FiberChannel", true,true,false);
177+
178+
179+
private final String name;
161180
private final boolean shared;
162181
private final boolean overprovisioning;
163182
private final boolean encryption;
164183

165-
StoragePoolType(boolean shared, boolean overprovisioning, boolean encryption) {
184+
/**
185+
* New StoragePoolType, set the name to check with it in Dao (Note: Do not register it into the map of pool types).
186+
* @param name name of the StoragePoolType.
187+
*/
188+
public StoragePoolType(String name) {
189+
this.name = name;
190+
this.shared = false;
191+
this.overprovisioning = false;
192+
this.encryption = false;
193+
}
194+
195+
/**
196+
* Define a new StoragePoolType, and register it into the map of pool types known to the management server.
197+
* @param name Simple unique name of the StoragePoolType.
198+
* @param shared Storage pool is shared/accessible to multiple hypervisors
199+
* @param overprovisioning Storage pool supports overprovisioning
200+
* @param encryption Storage pool supports encrypted volumes
201+
*/
202+
public StoragePoolType(String name, boolean shared, boolean overprovisioning, boolean encryption) {
203+
this.name = name;
166204
this.shared = shared;
167205
this.overprovisioning = overprovisioning;
168206
this.encryption = encryption;
207+
addStoragePoolType(this);
169208
}
170209

171210
public boolean isShared() {
@@ -177,6 +216,48 @@ public boolean supportsOverProvisioning() {
177216
}
178217

179218
public boolean supportsEncryption() { return encryption; }
219+
220+
private static void addStoragePoolType(StoragePoolType storagePoolType) {
221+
map.putIfAbsent(storagePoolType.name, storagePoolType);
222+
}
223+
224+
public static StoragePoolType[] values() {
225+
return map.values().toArray(StoragePoolType[]::new).clone();
226+
}
227+
228+
public static StoragePoolType valueOf(String name) {
229+
if (StringUtils.isBlank(name)) {
230+
return null;
231+
}
232+
233+
StoragePoolType storage = map.get(name);
234+
if (storage == null) {
235+
throw new IllegalArgumentException("StoragePoolType '" + name + "' not found");
236+
}
237+
return storage;
238+
}
239+
240+
@Override
241+
public String toString() {
242+
return name;
243+
}
244+
245+
public String name() {
246+
return name;
247+
}
248+
249+
@Override
250+
public boolean equals(Object o) {
251+
if (this == o) return true;
252+
if (o == null || getClass() != o.getClass()) return false;
253+
StoragePoolType that = (StoragePoolType) o;
254+
return Objects.equals(name, that.name);
255+
}
256+
257+
@Override
258+
public int hashCode() {
259+
return Objects.hash(name);
260+
}
180261
}
181262

182263
public static List<StoragePoolType> getNonSharedStoragePoolTypes() {

api/src/test/java/com/cloud/storage/StorageTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,13 @@ public void supportsOverprovisioningStoragePool() {
7474
Assert.assertTrue(StoragePoolType.DatastoreCluster.supportsOverProvisioning());
7575
Assert.assertTrue(StoragePoolType.Linstor.supportsOverProvisioning());
7676
}
77+
78+
@Test
79+
public void equalityTest() {
80+
StoragePoolType t1 = StoragePoolType.NetworkFilesystem;
81+
StoragePoolType t2 = StoragePoolType.NetworkFilesystem;
82+
Assert.assertTrue(t1 == StoragePoolType.NetworkFilesystem);
83+
Assert.assertTrue(t1.equals(StoragePoolType.NetworkFilesystem));
84+
Assert.assertFalse(t1.equals(StoragePoolType.EXT));
85+
}
7786
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.agent.transport;
18+
19+
import com.cloud.storage.Storage.StoragePoolType;
20+
import com.google.gson.JsonDeserializationContext;
21+
import com.google.gson.JsonDeserializer;
22+
import com.google.gson.JsonElement;
23+
import com.google.gson.JsonNull;
24+
import com.google.gson.JsonParseException;
25+
import com.google.gson.JsonPrimitive;
26+
import com.google.gson.JsonSerializationContext;
27+
import com.google.gson.JsonSerializer;
28+
29+
import java.lang.reflect.Type;
30+
31+
/**
32+
* {@link StoragePoolType} acts as extendable set of singleton objects and should return same result when used "=="
33+
* or {@link Object#equals(Object)}.
34+
* To support that, need to return existing object for a given name instead of creating new.
35+
*/
36+
public class StoragePoolTypeAdaptor implements JsonDeserializer<StoragePoolType>, JsonSerializer<StoragePoolType> {
37+
@Override
38+
public StoragePoolType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
39+
if (json instanceof JsonPrimitive && ((JsonPrimitive) json).isString()) {
40+
return StoragePoolType.valueOf(json.getAsString());
41+
}
42+
return null;
43+
}
44+
45+
@Override
46+
public JsonElement serialize(StoragePoolType src, Type typeOfSrc, JsonSerializationContext context) {
47+
String name = src.name();
48+
if (name == null) {
49+
return new JsonNull();
50+
}
51+
return new JsonPrimitive(name);
52+
}
53+
}

core/src/main/java/com/cloud/serializer/GsonHelper.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import com.cloud.agent.transport.LoggingExclusionStrategy;
3838
import com.cloud.agent.transport.Request.NwGroupsCommandTypeAdaptor;
3939
import com.cloud.agent.transport.Request.PortConfigListTypeAdaptor;
40+
import com.cloud.agent.transport.StoragePoolTypeAdaptor;
41+
import com.cloud.storage.Storage;
4042
import com.cloud.utils.Pair;
4143

4244
public class GsonHelper {
@@ -69,6 +71,7 @@ static Gson setDefaultGsonConfig(GsonBuilder builder) {
6971
}.getType(), new PortConfigListTypeAdaptor());
7072
builder.registerTypeAdapter(new TypeToken<Pair<Long, Long>>() {
7173
}.getType(), new NwGroupsCommandTypeAdaptor());
74+
builder.registerTypeAdapter(Storage.StoragePoolType.class, new StoragePoolTypeAdaptor());
7275
Gson gson = builder.create();
7376
dsAdaptor.initGson(gson);
7477
dtAdaptor.initGson(gson);

core/src/test/java/com/cloud/agent/transport/RequestTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ protected void compareRequest(Request req1, Request req2) {
255255
public void testGoodCommand() {
256256
s_logger.info("Testing good Command");
257257
String content = "[{\"com.cloud.agent.api.GetVolumeStatsCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"],"
258-
+ "\"poolType\":\"NetworkFilesystem\",\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]";
258+
+ "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]";
259259
Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content);
260260
sreq.setSequence(1);
261261
Command cmds[] = sreq.getCommands();
@@ -266,7 +266,7 @@ public void testGoodCommand() {
266266
public void testBadCommand() {
267267
s_logger.info("Testing Bad Command");
268268
String content = "[{\"com.cloud.agent.api.SomeJunkCommand\":{\"volumeUuids\":[\"dcc860ac-4a20-498f-9cb3-bab4d57aa676\"],"
269-
+ "\"poolType\":\"NetworkFilesystem\",\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]";
269+
+ "\"poolType\":{\"name\":\"NetworkFilesystem\"},\"poolUuid\":\"e007c270-2b1b-3ce9-ae92-a98b94eef7eb\",\"contextMap\":{},\"wait\":5}}]";
270270
Request sreq = new Request(Version.v2, 1L, 2L, 3L, 1L, (short)1, content);
271271
sreq.setSequence(1);
272272
Command cmds[] = sreq.getCommands();

engine/orchestration/src/main/java/org/apache/cloudstack/engine/datacenter/entity/api/db/EngineHostVO.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.UUID;
2323

2424
import javax.persistence.Column;
25+
import javax.persistence.Convert;
2526
import javax.persistence.DiscriminatorColumn;
2627
import javax.persistence.DiscriminatorType;
2728
import javax.persistence.Entity;
@@ -45,6 +46,7 @@
4546
import com.cloud.hypervisor.Hypervisor.HypervisorType;
4647
import com.cloud.resource.ResourceState;
4748
import com.cloud.storage.Storage.StoragePoolType;
49+
import com.cloud.util.StoragePoolTypeConverter;
4850
import com.cloud.utils.NumbersUtil;
4951
import com.cloud.utils.db.GenericDao;
5052
import com.cloud.utils.db.StateMachine;
@@ -126,6 +128,7 @@ public class EngineHostVO implements EngineHost, Identity {
126128
private String resource;
127129

128130
@Column(name = "fs_type")
131+
@Convert(converter = StoragePoolTypeConverter.class)
129132
private StoragePoolType fsType;
130133

131134
@Column(name = "available")

engine/schema/src/main/java/com/cloud/host/HostVO.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.UUID;
2424

2525
import javax.persistence.Column;
26+
import javax.persistence.Convert;
2627
import javax.persistence.DiscriminatorColumn;
2728
import javax.persistence.DiscriminatorType;
2829
import javax.persistence.Entity;
@@ -44,6 +45,7 @@
4445
import com.cloud.offering.ServiceOffering;
4546
import com.cloud.resource.ResourceState;
4647
import com.cloud.storage.Storage.StoragePoolType;
48+
import com.cloud.util.StoragePoolTypeConverter;
4749
import com.cloud.utils.NumbersUtil;
4850
import com.cloud.utils.db.GenericDao;
4951
import java.util.Arrays;
@@ -130,6 +132,7 @@ public class HostVO implements Host {
130132
private String resource;
131133

132134
@Column(name = "fs_type")
135+
@Convert(converter = StoragePoolTypeConverter.class)
133136
private StoragePoolType fsType;
134137

135138
@Column(name = "available")

engine/schema/src/main/java/com/cloud/storage/VolumeVO.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.UUID;
2121

2222
import javax.persistence.Column;
23+
import javax.persistence.Convert;
2324
import javax.persistence.Entity;
2425
import javax.persistence.EnumType;
2526
import javax.persistence.Enumerated;
@@ -32,6 +33,7 @@
3233
import javax.persistence.TemporalType;
3334
import javax.persistence.Transient;
3435

36+
import com.cloud.util.StoragePoolTypeConverter;
3537
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
3638

3739
import com.cloud.storage.Storage.ProvisioningType;
@@ -114,7 +116,7 @@ public class VolumeVO implements Volume {
114116
Type volumeType = Volume.Type.UNKNOWN;
115117

116118
@Column(name = "pool_type")
117-
@Enumerated(EnumType.STRING)
119+
@Convert(converter = StoragePoolTypeConverter.class)
118120
StoragePoolType poolType;
119121

120122
@Column(name = GenericDao.REMOVED_COLUMN)
@@ -331,9 +333,7 @@ public void setPoolType(StoragePoolType poolType) {
331333
this.poolType = poolType;
332334
}
333335

334-
public StoragePoolType getPoolType() {
335-
return poolType;
336-
}
336+
public StoragePoolType getPoolType() { return poolType; }
337337

338338
@Override
339339
public long getDomainId() {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.util;
18+
19+
import com.cloud.storage.Storage.StoragePoolType;
20+
21+
import javax.persistence.AttributeConverter;
22+
import javax.persistence.Converter;
23+
24+
/**
25+
* Converts {@link StoragePoolType} to and from {@link String} using {@link StoragePoolType#name()}.
26+
*
27+
* @author mprokopchuk
28+
*/
29+
@Converter
30+
public class StoragePoolTypeConverter implements AttributeConverter<StoragePoolType, String> {
31+
@Override
32+
public String convertToDatabaseColumn(StoragePoolType attribute) {
33+
return attribute != null ? attribute.name() : null;
34+
}
35+
36+
@Override
37+
public StoragePoolType convertToEntityAttribute(String dbData) {
38+
return dbData != null ? StoragePoolType.valueOf(dbData) : null;
39+
}
40+
}

0 commit comments

Comments
 (0)