Skip to content

Commit 0cf8d60

Browse files
Gupta, SuryaGupta, Surya
authored andcommitted
CSTACKEX-35 Create Async
1 parent 618f957 commit 0cf8d60

File tree

5 files changed

+194
-12
lines changed

5 files changed

+194
-12
lines changed

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

Lines changed: 73 additions & 2 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,15 +41,27 @@
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.StoragePoolDetailsDao;
45+
import org.apache.cloudstack.storage.feign.model.OntapStorage;
46+
import org.apache.cloudstack.storage.provider.StorageProviderFactory;
47+
import org.apache.cloudstack.storage.service.StorageStrategy;
48+
import org.apache.cloudstack.storage.service.model.CloudStackVolume;
49+
import org.apache.cloudstack.storage.service.model.ProtocolType;
50+
import org.apache.cloudstack.storage.utils.Constants;
51+
import org.apache.cloudstack.storage.utils.Utility;
4052
import org.apache.logging.log4j.LogManager;
4153
import org.apache.logging.log4j.Logger;
4254

55+
import javax.inject.Inject;
4356
import java.util.HashMap;
4457
import java.util.Map;
4558

4659
public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
4760

4861
private static final Logger s_logger = (Logger)LogManager.getLogger(OntapPrimaryDatastoreDriver.class);
62+
63+
@Inject private Utility utils;
64+
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
4965
@Override
5066
public Map<String, String> getCapabilities() {
5167
s_logger.trace("OntapPrimaryDatastoreDriver: getCapabilities: Called");
@@ -68,9 +84,64 @@ public DataStoreTO getStoreTO(DataStore store) {
6884
}
6985

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

73-
s_logger.trace("OntapPrimaryDatastoreDriver: createAsync: Store: "+store+", data: "+data);
121+
private String createCloudStackVolumeForTypeVolume(DataStore dataStore, DataObject dataObject) {
122+
Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(dataStore.getId());
123+
String protocol = details.get(Constants.PROTOCOL);
124+
OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD),
125+
details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), ProtocolType.valueOf(protocol),
126+
Boolean.parseBoolean(details.get(Constants.IS_DISAGGREGATED)));
127+
StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage);
128+
boolean isValid = storageStrategy.connect();
129+
if (isValid) {
130+
s_logger.info("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest", details.get(Constants.SVM_NAME));
131+
CloudStackVolume cloudStackVolumeRequest = utils.createCloudStackVolumeRequestByProtocol(dataStore.getId(), details, dataObject);
132+
CloudStackVolume cloudStackVolume = storageStrategy.createCloudStackVolume(cloudStackVolumeRequest);
133+
if (ProtocolType.ISCSI.name().equalsIgnoreCase(protocol) && cloudStackVolume.getLun() != null && cloudStackVolume.getLun().getName() != null) {
134+
return cloudStackVolume.getLun().getName();
135+
} else {
136+
String errMsg = "createCloudStackVolumeForTypeVolume: Volume creation failed. Lun or Lun Path is null for dataObject: " + dataObject;
137+
s_logger.error(errMsg);
138+
throw new CloudRuntimeException(errMsg);
139+
}
140+
} else {
141+
String errMsg = "createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [" + details.get(Constants.SVM_NAME) + "] failed";
142+
s_logger.error(errMsg);
143+
throw new CloudRuntimeException(errMsg);
144+
}
74145
}
75146

76147
@Override

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public abstract class StorageStrategy {
6464
@Inject
6565
private JobFeignClient jobFeignClient;
6666

67-
private final OntapStorage storage;
67+
protected final OntapStorage storage;
6868

6969
/**
7070
* Presents aggregate object for the unified storage, not eligible for disaggregated

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

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,61 @@
1919

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

22+
import com.cloud.utils.exception.CloudRuntimeException;
23+
import org.apache.cloudstack.storage.feign.client.SANFeignClient;
24+
import org.apache.cloudstack.storage.feign.model.Lun;
25+
import org.apache.cloudstack.storage.feign.model.LunSpace;
2226
import org.apache.cloudstack.storage.feign.model.OntapStorage;
27+
import org.apache.cloudstack.storage.feign.model.Svm;
28+
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
2329
import org.apache.cloudstack.storage.service.model.AccessGroup;
2430
import org.apache.cloudstack.storage.service.model.CloudStackVolume;
31+
import org.apache.cloudstack.storage.utils.Constants;
32+
import org.apache.cloudstack.storage.utils.Utility;
33+
import org.apache.logging.log4j.LogManager;
34+
import org.apache.logging.log4j.Logger;
2535

36+
import javax.inject.Inject;
37+
import java.net.URI;
2638
import java.util.Map;
2739

28-
public class UnifiedSANStrategy extends SANStrategy{
40+
public class UnifiedSANStrategy extends SANStrategy {
41+
42+
private static final Logger s_logger = (Logger) LogManager.getLogger(UnifiedSANStrategy.class);
43+
@Inject private Utility utils;
44+
@Inject private SANFeignClient sanFeignClient;
2945
public UnifiedSANStrategy(OntapStorage ontapStorage) {
3046
super(ontapStorage);
3147
}
3248

3349
@Override
3450
public CloudStackVolume createCloudStackVolume(CloudStackVolume cloudstackVolume) {
35-
//TODO
36-
return null;
51+
s_logger.info("createCloudStackVolume : Creating Lun with cloudstackVolume request {} ", cloudstackVolume);
52+
if (cloudstackVolume == null || cloudstackVolume.getLun() == null) {
53+
s_logger.error("createCloudStackVolume: LUN creation failed. Invalid cloudstackVolume request: {}", cloudstackVolume);
54+
throw new CloudRuntimeException("createCloudStackVolume : Failed to create Lun, invalid cloudstackVolume request");
55+
}
56+
try {
57+
// Get AuthHeader
58+
String authHeader = utils.generateAuthHeader(storage.getUsername(), storage.getPassword());
59+
// Create URI for lun creation
60+
URI url = utils.generateURI(Constants.CREATE_LUN);
61+
OntapResponse<Lun> createdLun = sanFeignClient.createLun(url, authHeader, true, cloudstackVolume.getLun());
62+
if (createdLun == null || createdLun.getRecords() == null || createdLun.getRecords().size() == 0) {
63+
s_logger.error("createCloudStackVolume: LUN creation failed for Lun {}", cloudstackVolume.getLun().getName());
64+
throw new CloudRuntimeException("Failed to create Lun: " + cloudstackVolume.getLun().getName());
65+
}
66+
Lun lun = createdLun.getRecords().get(0);
67+
s_logger.debug("createCloudStackVolume: LUN created successfully. Lun: {}", lun);
68+
s_logger.info("createCloudStackVolume: LUN created successfully. LunName: {}", lun.getName());
69+
70+
CloudStackVolume createdCloudStackVolume = new CloudStackVolume();
71+
createdCloudStackVolume.setLun(lun);
72+
return createdCloudStackVolume;
73+
} catch (Exception e) {
74+
s_logger.error("Exception occurred while creating LUN: {}. Exception: {}", cloudstackVolume.getLun().getName(), e.getMessage());
75+
throw new CloudRuntimeException("Failed to create Lun: " + e.getMessage());
76+
}
3777
}
3878

3979
@Override

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/Constants.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,16 @@ public class Constants {
4040
public static final int JOB_MAX_RETRIES = 100;
4141
public static final int CREATE_VOLUME_CHECK_SLEEP_TIME = 2000;
4242

43+
public static final String PATH_SEPARATOR = "/";
44+
45+
public static final String VOLUME_PATH_PREFIX = "/vol/";
46+
47+
public static final String KVM = "KVM";
48+
4349
public static final String HTTPS = "https://";
4450
public static final String GET_SVMs = "/api/svm/svms";
4551
public static final String CREATE_VOLUME = "/api/storage/volumes";
4652
public static final String GET_JOB_BY_UUID = "/api/cluster/jobs";
53+
public static final String CREATE_LUN = "/api/storage/luns";
54+
4755
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/Utility.java

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,96 @@
2020
package org.apache.cloudstack.storage.utils;
2121

2222
import com.cloud.utils.StringUtils;
23+
import com.cloud.utils.exception.CloudRuntimeException;
24+
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
25+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
26+
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
27+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
28+
import org.apache.cloudstack.storage.driver.OntapPrimaryDatastoreDriver;
29+
import org.apache.cloudstack.storage.feign.model.Lun;
30+
import org.apache.cloudstack.storage.feign.model.LunSpace;
2331
import org.apache.cloudstack.storage.feign.model.OntapStorage;
32+
import org.apache.cloudstack.storage.feign.model.Svm;
33+
import org.apache.cloudstack.storage.provider.StorageProviderFactory;
34+
import org.apache.cloudstack.storage.service.StorageStrategy;
35+
import org.apache.cloudstack.storage.service.model.CloudStackVolume;
36+
import org.apache.cloudstack.storage.service.model.ProtocolType;
37+
import org.apache.logging.log4j.LogManager;
38+
import org.apache.logging.log4j.Logger;
2439
import org.springframework.stereotype.Component;
2540
import org.springframework.util.Base64Utils;
2641

2742
import javax.inject.Inject;
2843
import java.net.URI;
44+
import java.util.Map;
2945

3046
@Component
3147
public class Utility {
32-
@Inject
33-
OntapStorage ontapStorage;
48+
49+
private static final Logger s_logger = (Logger) LogManager.getLogger(Utility.class);
50+
@Inject private OntapStorage ontapStorage;
51+
@Inject private PrimaryDataStoreDao storagePoolDao;
52+
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
3453

3554
private static final String BASIC = "Basic";
3655
private static final String AUTH_HEADER_COLON = ":";
56+
3757
/**
3858
* Method generates authentication headers using storage backend credentials passed as normal string
39-
* @param username -->> username of the storage backend
40-
* @param password -->> normal decoded password of the storage backend
59+
*
60+
* @param username -->> username of the storage backend
61+
* @param password -->> normal decoded password of the storage backend
4162
* @return
4263
*/
43-
public String generateAuthHeader(String username, String password) {
64+
public String generateAuthHeader (String username, String password) {
4465
byte[] encodedBytes = Base64Utils.encode((username + AUTH_HEADER_COLON + password).getBytes());
4566
return BASIC + StringUtils.SPACE + new String(encodedBytes);
4667
}
4768

48-
public URI generateURI(String path) {
69+
public URI generateURI (String path) {
4970
String uriString = Constants.HTTPS + ontapStorage.getManagementLIF() + path;
5071
return URI.create(uriString);
5172
}
73+
74+
public CloudStackVolume createCloudStackVolumeRequestByProtocol(Long storagePoolId, Map<String, String> details, DataObject dataObject) {
75+
StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
76+
if(storagePool == null) {
77+
throw new CloudRuntimeException("createCloudStackVolume : Storage Pool not found for id: " + storagePoolId);
78+
}
79+
CloudStackVolume cloudStackVolumeRequest = null;
80+
81+
String protocol = details.get(Constants.PROTOCOL);
82+
if (ProtocolType.ISCSI.name().equalsIgnoreCase(protocol)) {
83+
cloudStackVolumeRequest = new CloudStackVolume();
84+
Lun lunRequest = new Lun();
85+
Svm svm = new Svm();
86+
svm.setName(details.get(Constants.SVM_NAME));
87+
lunRequest.setSvm(svm);
88+
89+
LunSpace lunSpace = new LunSpace();
90+
lunSpace.setSize(dataObject.getSize());
91+
lunRequest.setSpace(lunSpace);
92+
93+
String lunFullName = Constants.VOLUME_PATH_PREFIX + storagePool.getName() + Constants.PATH_SEPARATOR + dataObject.getName();
94+
lunRequest.setName(lunFullName);
95+
96+
String hypervisorType = storagePool.getHypervisor().name();
97+
String osType = null;
98+
switch (hypervisorType) {
99+
case Constants.KVM:
100+
osType = Lun.OsTypeEnum.LINUX.getValue();
101+
break;
102+
default:
103+
String errMsg = "createCloudStackVolume : Unsupported hypervisor type " + hypervisorType + " for ONTAP storage";
104+
s_logger.error(errMsg);
105+
throw new CloudRuntimeException(errMsg);
106+
}
107+
lunRequest.setOsType(Lun.OsTypeEnum.valueOf(osType));
108+
109+
cloudStackVolumeRequest.setLun(lunRequest);
110+
return cloudStackVolumeRequest;
111+
} else {
112+
throw new CloudRuntimeException("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol);
113+
}
114+
}
52115
}

0 commit comments

Comments
 (0)