Skip to content

Commit 2b7f3ea

Browse files
Gupta, SuryaGupta, Surya
authored andcommitted
CSTACKEX-35 CreateAsync workflow for ISCSI
1 parent 25353c2 commit 2b7f3ea

File tree

10 files changed

+249
-86
lines changed

10 files changed

+249
-86
lines changed

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@
1818
*/
1919
package org.apache.cloudstack.storage.driver;
2020

21+
import com.cloud.agent.api.Answer;
22+
import com.cloud.agent.api.to.DataObjectType;
2123
import com.cloud.agent.api.to.DataStoreTO;
2224
import com.cloud.agent.api.to.DataTO;
25+
import com.cloud.exception.InvalidParameterValueException;
2326
import com.cloud.host.Host;
2427
import com.cloud.storage.Storage;
2528
import com.cloud.storage.StoragePool;
2629
import com.cloud.storage.Volume;
2730
import com.cloud.utils.Pair;
31+
import com.cloud.utils.exception.CloudRuntimeException;
2832
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
2933
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
3034
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
@@ -37,18 +41,35 @@
3741
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
3842
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
3943
import org.apache.cloudstack.storage.command.CommandResult;
44+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
45+
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
46+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
47+
import org.apache.cloudstack.storage.feign.model.Lun;
48+
import org.apache.cloudstack.storage.provider.StorageProviderFactory;
49+
import org.apache.cloudstack.storage.service.SANStrategy;
50+
import org.apache.cloudstack.storage.service.StorageStrategy;
51+
import org.apache.cloudstack.storage.feign.model.OntapStorage;
52+
import org.apache.cloudstack.storage.utils.Constants;
4053
import org.apache.logging.log4j.LogManager;
4154
import org.apache.logging.log4j.Logger;
4255

56+
import javax.inject.Inject;
57+
import java.util.Arrays;
4358
import java.util.HashMap;
59+
import java.util.List;
4460
import java.util.Map;
4561

4662
public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
4763

48-
private static final Logger s_logger = (Logger)LogManager.getLogger(OntapPrimaryDatastoreDriver.class);
64+
private static final Logger logger = (Logger)LogManager.getLogger(OntapPrimaryDatastoreDriver.class);
65+
66+
@Inject
67+
private StoragePoolDetailsDao storagePoolDetailsDao;
68+
@Inject private PrimaryDataStoreDao storagePoolDao;
69+
4970
@Override
5071
public Map<String, String> getCapabilities() {
51-
s_logger.trace("OntapPrimaryDatastoreDriver: getCapabilities: Called");
72+
logger.trace("OntapPrimaryDatastoreDriver: getCapabilities: Called");
5273
Map<String, String> mapCapabilities = new HashMap<>();
5374

5475
mapCapabilities.put(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString(), Boolean.TRUE.toString());
@@ -68,9 +89,74 @@ public DataStoreTO getStoreTO(DataStore store) {
6889
}
6990

7091
@Override
71-
public void createAsync(DataStore store, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
92+
public void createAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CreateCmdResult> callback) {
93+
CreateCmdResult createCmdResult = null;
94+
String path = null;
95+
String errMsg = null;
96+
if (dataStore == null) {
97+
throw new InvalidParameterValueException("createAsync: dataStore should not be null");
98+
}
99+
if (dataObject == null) {
100+
throw new InvalidParameterValueException("createAsync: dataObject should not be null");
101+
}
102+
if (callback == null) {
103+
throw new InvalidParameterValueException("createAsync: callback should not be null");
104+
}
105+
106+
try {
107+
logger.info("createAsync: Volume creation starting for data store [{}] and data object [{}] of type [{}]",
108+
dataStore, dataObject, dataObject.getType());
109+
if (dataObject.getType() == DataObjectType.VOLUME) {
110+
path = createCloudStackVolume(dataStore.getId(), dataObject);
111+
createCmdResult = new CreateCmdResult(path, new Answer(null, true, null));
112+
} else {
113+
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
114+
logger.error(errMsg);
115+
throw new CloudRuntimeException(errMsg);
116+
}
117+
} catch (Exception e) {
118+
errMsg = e.getMessage();
119+
logger.error("createAsync: Volume creation failed for dataObject [{}]: {}", dataObject, errMsg);
120+
createCmdResult = new CreateCmdResult(null, new Answer(null, false, errMsg));
121+
createCmdResult.setResult(e.toString());
122+
} finally {
123+
callback.complete(createCmdResult);
124+
}
125+
}
72126

73-
s_logger.trace("OntapPrimaryDatastoreDriver: createAsync: Store: "+store+", data: "+data);
127+
private String createCloudStackVolume(long storagePoolId, DataObject dataObject) {
128+
String path = null;
129+
StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
130+
if(storagePool == null) {
131+
throw new CloudRuntimeException("createCloudStackVolume : Storage Pool not found for id: " + storagePoolId);
132+
}
133+
List<String> keyList = Arrays.asList(Constants.USERNAME, Constants.PROTOCOL, Constants.IS_DISAGGREGATED, Constants.PASSWORD, Constants.MANAGEMENT_LIF,
134+
Constants.SVM_NAME, Constants.NAME);
135+
Map<String, String> storagePoolDetailMap = storagePoolDetailsDao.listDetailsKeyPairs(storagePoolId, keyList);
136+
OntapStorage ontapStorage = new OntapStorage(storagePoolDetailMap.get(Constants.USERNAME), storagePoolDetailMap.get(Constants.PASSWORD),
137+
storagePoolDetailMap.get(Constants.MANAGEMENT_LIF), storagePoolDetailMap.get(Constants.SVM_NAME), Constants.ProtocolType.valueOf(storagePoolDetailMap.get(Constants.PROTOCOL)),
138+
Boolean.parseBoolean(storagePoolDetailMap.get(Constants.IS_DISAGGREGATED)));
139+
StorageStrategy storageStrategy = StorageProviderFactory.createStrategy(ontapStorage);
140+
boolean isValid = storageStrategy.connect();
141+
if (isValid) {
142+
String svmName = ontapStorage.getSvmName();
143+
String lunOrFileName = dataObject.getName();
144+
Long size = dataObject.getSize();
145+
String volName = storagePool.getName();
146+
147+
// Create LUN based on protocol
148+
if (ontapStorage.getProtocol().equals(Constants.ISCSI)) {
149+
SANStrategy sanStrategy = StorageProviderFactory.getSANStrategy(ontapStorage);
150+
Lun lun = sanStrategy.createLUN(svmName, volName, lunOrFileName, size , Lun.OsTypeEnum.LINUX.getValue());
151+
if(lun.getName() == null || lun.getName().isEmpty()) {
152+
throw new CloudRuntimeException("createCloudStackVolume : LUN Name is invalid");
153+
}
154+
path = lun.getName();
155+
}
156+
} else {
157+
throw new CloudRuntimeException("createCloudStackVolume : ONTAP details validation failed, cannot connect to ONTAP cluster");
158+
}
159+
return path;
74160
}
75161

76162
@Override
@@ -105,6 +191,15 @@ public ChapInfo getChapInfo(DataObject dataObject) {
105191

106192
@Override
107193
public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) {
194+
if (dataStore == null) {
195+
throw new CloudRuntimeException("grantAccess: dataStore should not be null");
196+
}
197+
if (dataObject == null) {
198+
throw new CloudRuntimeException("grantAccess: dataObject should not be null");
199+
}
200+
if (host == null) {
201+
throw new CloudRuntimeException("grantAccess: host should not be null");
202+
}
108203
return true;
109204
}
110205

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/SvmFeignClient.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626
import org.springframework.web.bind.annotation.RequestHeader;
2727
import org.springframework.web.bind.annotation.RequestMapping;
2828
import org.springframework.web.bind.annotation.RequestMethod;
29-
import org.springframework.web.bind.annotation.RequestParam;
3029

3130
import java.net.URI;
32-
import java.util.Map;
3331

3432
@FeignClient(name = "SvmClient", url = "https://{clusterIP}/api/svm/svms", configuration = FeignConfiguration.class)
3533
public interface SvmFeignClient {

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/OntapStorage.java

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,67 +22,67 @@
2222
import org.apache.cloudstack.storage.utils.Constants.ProtocolType;
2323

2424
public class OntapStorage {
25-
public static String _username;
26-
public static String _password;
27-
public static String _managementLIF;
28-
public static String _svmName;
29-
public static ProtocolType _protocolType;
30-
public static Boolean _isDisaggregated;
25+
public static String username;
26+
public static String password;
27+
public static String managementLIF;
28+
public static String svmName;
29+
public static ProtocolType protocolType;
30+
public static Boolean isDisaggregated;
3131

3232
public OntapStorage(String username, String password, String managementLIF, String svmName, ProtocolType protocolType, Boolean isDisaggregated) {
33-
_username = username;
34-
_password = password;
35-
_managementLIF = managementLIF;
36-
_svmName = svmName;
37-
_protocolType = protocolType;
38-
_isDisaggregated = isDisaggregated;
33+
this.username = username;
34+
this.password = password;
35+
this.managementLIF = managementLIF;
36+
this.svmName = svmName;
37+
this.protocolType = protocolType;
38+
this.isDisaggregated = isDisaggregated;
3939
}
4040

4141
public String getUsername() {
42-
return _username;
42+
return username;
4343
}
4444

4545
public void setUsername(String username) {
46-
_username = username;
46+
username = username;
4747
}
4848

4949
public String getPassword() {
50-
return _password;
50+
return password;
5151
}
5252

5353
public void setPassword(String password) {
54-
_password = password;
54+
password = password;
5555
}
5656

5757
public String getManagementLIF() {
58-
return _managementLIF;
58+
return managementLIF;
5959
}
6060

6161
public void setManagementLIF(String managementLIF) {
62-
_managementLIF = managementLIF;
62+
managementLIF = managementLIF;
6363
}
6464

6565
public String getSvmName() {
66-
return _svmName;
66+
return svmName;
6767
}
6868

6969
public void setSvmName(String svmName) {
70-
_svmName = svmName;
70+
svmName = svmName;
7171
}
7272

7373
public ProtocolType getProtocol() {
74-
return _protocolType;
74+
return protocolType;
7575
}
7676

7777
public void setProtocol(ProtocolType protocolType) {
78-
_protocolType = protocolType;
78+
protocolType = protocolType;
7979
}
8080

8181
public Boolean getIsDisaggregated() {
82-
return _isDisaggregated;
82+
return isDisaggregated;
8383
}
8484

8585
public void setIsDisaggregated(Boolean isDisaggregated) {
86-
_isDisaggregated = isDisaggregated;
86+
isDisaggregated = isDisaggregated;
8787
}
8888
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public DataStore initialize(Map<String, Object> dsInfos) {
141141
OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD),
142142
details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), protocol,
143143
Boolean.parseBoolean(details.get(Constants.IS_DISAGGREGATED)));
144-
StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage);
144+
StorageStrategy storageStrategy = StorageProviderFactory.createStrategy(ontapStorage);
145145
boolean isValid = storageStrategy.connect();
146146
if (isValid) {
147147
// String volumeName = storagePoolName + "_vol"; //TODO: Figure out a better naming convention

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/provider/StorageProviderFactory.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,42 +24,45 @@
2424
import org.apache.cloudstack.storage.service.StorageStrategy;
2525
import org.apache.cloudstack.storage.service.UnifiedNASStrategy;
2626
import org.apache.cloudstack.storage.service.UnifiedSANStrategy;
27-
import org.apache.cloudstack.storage.utils.Constants;
27+
import org.apache.cloudstack.storage.service.SANStrategy;
28+
import org.apache.cloudstack.storage.service.NASStrategy;
2829
import org.apache.cloudstack.storage.utils.Constants.ProtocolType;
2930
import org.apache.logging.log4j.LogManager;
3031
import org.apache.logging.log4j.Logger;
3132
import org.springframework.stereotype.Component;
3233

3334
@Component
3435
public class StorageProviderFactory {
35-
private final StorageStrategy storageStrategy;
3636
private static final Logger s_logger = (Logger) LogManager.getLogger(StorageProviderFactory.class);
3737

38-
private StorageProviderFactory(OntapStorage ontapStorage) {
38+
private StorageProviderFactory() {}
39+
40+
public static StorageStrategy createStrategy(OntapStorage ontapStorage) {
3941
ProtocolType protocol = ontapStorage.getProtocol();
40-
s_logger.info("Initializing StorageProviderFactory with protocol: " + protocol);
42+
s_logger.info("Initializing StorageProviderFactory with protocol: {}", protocol);
4143
switch (protocol) {
4244
case NFS:
4345
if(!ontapStorage.getIsDisaggregated()) {
44-
this.storageStrategy = new UnifiedNASStrategy(ontapStorage);
46+
return new UnifiedNASStrategy(ontapStorage);
4547
} else {
4648
throw new CloudRuntimeException("Unsupported configuration: Disaggregated ONTAP is not supported.");
4749
}
48-
break;
4950
case ISCSI:
5051
if (!ontapStorage.getIsDisaggregated()) {
51-
this.storageStrategy = new UnifiedSANStrategy(ontapStorage);
52+
return new UnifiedSANStrategy(ontapStorage);
5253
} else {
5354
throw new CloudRuntimeException("Unsupported configuration: Disaggregated ONTAP is not supported.");
5455
}
55-
break;
5656
default:
57-
this.storageStrategy = null;
58-
throw new CloudRuntimeException("Unsupported protocol: " + protocol);
57+
throw new CloudRuntimeException("Unsupported configuration: " + protocol);
5958
}
6059
}
6160

62-
public static StorageStrategy getStrategy(OntapStorage ontapStorage) {
63-
return new StorageProviderFactory(ontapStorage).storageStrategy;
61+
public static SANStrategy getSANStrategy(OntapStorage ontapStorage) {
62+
return (SANStrategy) createStrategy(ontapStorage);
63+
}
64+
65+
public static NASStrategy getNASStrategy(OntapStorage ontapStorage) {
66+
return (NASStrategy) createStrategy(ontapStorage);
6467
}
65-
}
68+
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/SANStrategy.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@
1919

2020
package org.apache.cloudstack.storage.service;
2121

22+
import org.apache.cloudstack.storage.feign.model.Lun;
2223
import org.apache.cloudstack.storage.feign.model.OntapStorage;
2324

2425
public abstract class SANStrategy extends StorageStrategy {
2526
public SANStrategy(OntapStorage ontapStorage) {
2627
super(ontapStorage);
2728
}
2829

29-
public abstract String createLUN(String svmName, String volumeName, String lunName, long sizeBytes, String osType);
30+
public abstract Lun createLUN(String svmName, String volumeName, String lunName, long sizeBytes, String osType);
3031
public abstract String createIgroup(String svmName, String igroupName, String[] initiators);
3132
public abstract String mapLUNToIgroup(String lunName, String igroupName);
3233
public abstract String enableISCSI(String svmUuid);
33-
}
34+
}

0 commit comments

Comments
 (0)