Skip to content

Commit 75e3a31

Browse files
Srivastava, PiyushSrivastava, Piyush
authored andcommitted
vm instance creation test1
1 parent e8062fd commit 75e3a31

File tree

4 files changed

+197
-32
lines changed

4 files changed

+197
-32
lines changed

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

Lines changed: 158 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.cloud.storage.Storage;
2828
import com.cloud.storage.StoragePool;
2929
import com.cloud.storage.Volume;
30+
import com.cloud.storage.VolumeVO;
3031
import com.cloud.utils.Pair;
3132
import com.cloud.utils.exception.CloudRuntimeException;
3233
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
@@ -64,13 +65,14 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
6465

6566
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
6667
@Inject private PrimaryDataStoreDao storagePoolDao;
68+
@Inject private com.cloud.storage.dao.VolumeDao volumeDao;
6769
@Override
6870
public Map<String, String> getCapabilities() {
6971
s_logger.trace("OntapPrimaryDatastoreDriver: getCapabilities: Called");
7072
Map<String, String> mapCapabilities = new HashMap<>();
71-
72-
mapCapabilities.put(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString(), Boolean.TRUE.toString());
73-
mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString(), Boolean.TRUE.toString());
73+
// RAW managed initial implementation: snapshot features not yet supported
74+
mapCapabilities.put(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString(), Boolean.FALSE.toString());
75+
mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString(), Boolean.FALSE.toString());
7476

7577
return mapCapabilities;
7678
}
@@ -116,36 +118,176 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
116118
createCmdResult = new CreateCmdResult(null, new Answer(null, false, errMsg));
117119
createCmdResult.setResult(e.toString());
118120
} finally {
119-
s_logger.info("Volume creation successfully completed");
121+
if (createCmdResult != null && createCmdResult.isSuccess()) {
122+
s_logger.info("createAsync: Volume metadata created successfully. Path: {}", path);
123+
}
120124
callback.complete(createCmdResult);
121125
}
122126
}
123127

128+
/**
129+
* Creates CloudStack volume based on storage protocol type (NFS or iSCSI).
130+
*
131+
* For Managed NFS (Option 2 Implementation):
132+
* - Returns only UUID without creating qcow2 file
133+
* - KVM hypervisor creates qcow2 file automatically during VM deployment
134+
* - ONTAP volume provides the backing NFS storage
135+
*
136+
* For iSCSI/Block Storage:
137+
* - Creates LUN via ONTAP REST API
138+
* - Returns LUN path for direct attachment
139+
*/
124140
private String createCloudStackVolumeForTypeVolume(DataStore dataStore, DataObject dataObject) {
125141
StoragePoolVO storagePool = storagePoolDao.findById(dataStore.getId());
126142
if(storagePool == null) {
127-
s_logger.error("createCloudStackVolume : Storage Pool not found for id: " + dataStore.getId());
128-
throw new CloudRuntimeException("createCloudStackVolume : Storage Pool not found for id: " + dataStore.getId());
143+
s_logger.error("createCloudStackVolumeForTypeVolume: Storage Pool not found for id: {}", dataStore.getId());
144+
throw new CloudRuntimeException("createCloudStackVolumeForTypeVolume: Storage Pool not found for id: " + dataStore.getId());
129145
}
146+
130147
Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(dataStore.getId());
148+
String protocol = details.get(Constants.PROTOCOL);
149+
150+
if (ProtocolType.NFS.name().equalsIgnoreCase(protocol)) {
151+
return createManagedNfsVolume(dataStore, dataObject, storagePool);
152+
} else if (ProtocolType.ISCSI.name().equalsIgnoreCase(protocol)) {
153+
return createManagedBlockVolume(dataStore, dataObject, storagePool, details);
154+
} else {
155+
String errMsg = String.format("createCloudStackVolumeForTypeVolume: Unsupported protocol [%s]", protocol);
156+
s_logger.error(errMsg);
157+
throw new CloudRuntimeException(errMsg);
158+
}
159+
}
160+
161+
/**
162+
* Creates Managed NFS Volume with ONTAP backing storage.
163+
*
164+
* Architecture: 1 CloudStack Storage Pool = 1 ONTAP Volume (shared by all volumes)
165+
*
166+
* Flow:
167+
* 1. createAsync() stores volume metadata and NFS mount point
168+
* 2. Volume attach triggers ManagedNfsStorageAdaptor.connectPhysicalDisk()
169+
* 3. KVM mounts: nfs://nfsServer/junctionPath to /mnt/volumeUuid
170+
* 4. Libvirt creates qcow2 file via storageVolCreateXML()
171+
* 5. File created at: /vol/ontap_volume/volumeUuid (on ONTAP)
172+
*
173+
* Key Details:
174+
* - All volumes in same pool share the same ONTAP volume NFS export
175+
* - Each volume gets separate libvirt mount point: /mnt/<volumeUuid>
176+
* - All qcow2 files stored in same ONTAP volume: /vol/<pool_volume_name>/
177+
* - volume._iScsiName stores the NFS junction path (pool.path)
178+
*
179+
* @param dataStore CloudStack data store (storage pool)
180+
* @param dataObject Volume data object
181+
* @param storagePool Storage pool VO
182+
* @return Volume UUID (used as filename for qcow2 file)
183+
*/
184+
private String createManagedNfsVolume(DataStore dataStore, DataObject dataObject, StoragePoolVO storagePool) {
185+
VolumeInfo volumeInfo = (VolumeInfo) dataObject;
186+
VolumeVO volume = volumeDao.findById(volumeInfo.getId());
187+
String volumeUuid = volumeInfo.getUuid();
188+
189+
// Get the NFS junction path from storage pool
190+
// This is the path that was set during pool creation (e.g., "/my_pool_volume")
191+
String junctionPath = storagePool.getPath();
192+
193+
// Update volume metadata in CloudStack database
194+
volume.setPoolType(Storage.StoragePoolType.ManagedNFS);
195+
volume.setPoolId(dataStore.getId());
196+
volume.setPath(volumeUuid); // Filename for qcow2 file
197+
198+
// CRITICAL: Store junction path in _iScsiName field
199+
// CloudStack will use this in AttachCommand as DiskTO.MOUNT_POINT
200+
// ManagedNfsStorageAdaptor will mount: nfs://hostAddress/junctionPath to /mnt/volumeUuid
201+
volume.set_iScsiName(junctionPath);
202+
203+
volumeDao.update(volume.getId(), volume);
204+
205+
s_logger.info("ONTAP Managed NFS Volume Created: uuid={}, path={}, junctionPath={}, format=QCOW2, " +
206+
"pool={}, size={}GB. Libvirt will create qcow2 file at mount time.",
207+
volumeUuid, volumeUuid, junctionPath, storagePool.getName(),
208+
volumeInfo.getSize() / (1024 * 1024 * 1024));
209+
210+
// Optional: Prepare ONTAP volume for optimal qcow2 storage (future enhancement)
211+
// prepareOntapVolumeForQcow2Storage(dataStore, volumeInfo);
212+
213+
return volumeUuid;
214+
}
215+
216+
/**
217+
* Creates iSCSI/Block volume by calling ONTAP REST API to create a LUN.
218+
*
219+
* For block storage (iSCSI), the storage provider must create the LUN
220+
* before CloudStack can use it. This is different from NFS where the
221+
* hypervisor creates the file.
222+
*
223+
* @param dataStore CloudStack data store
224+
* @param dataObject Volume data object
225+
* @param storagePool Storage pool VO
226+
* @param details Storage pool details containing ONTAP connection info
227+
* @return LUN path/name for iSCSI attachment
228+
*/
229+
private String createManagedBlockVolume(DataStore dataStore, DataObject dataObject,
230+
StoragePoolVO storagePool, Map<String, String> details) {
131231
StorageStrategy storageStrategy = getStrategyByStoragePoolDetails(details);
132-
s_logger.info("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest", details.get(Constants.SVM_NAME));
232+
233+
s_logger.info("createManagedBlockVolume: Creating iSCSI LUN on ONTAP SVM [{}]", details.get(Constants.SVM_NAME));
234+
133235
CloudStackVolume cloudStackVolumeRequest = Utility.createCloudStackVolumeRequestByProtocol(storagePool, details, (VolumeInfo) dataObject);
236+
134237
CloudStackVolume cloudStackVolume = storageStrategy.createCloudStackVolume(cloudStackVolumeRequest);
135-
if (ProtocolType.ISCSI.name().equalsIgnoreCase(details.get(Constants.PROTOCOL)) && cloudStackVolume.getLun() != null && cloudStackVolume.getLun().getName() != null) {
136-
return cloudStackVolume.getLun().getName();
137-
} else if (ProtocolType.NFS.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) {
138-
return cloudStackVolume.getFile().getName();
238+
239+
if (cloudStackVolume.getLun() != null && cloudStackVolume.getLun().getName() != null) {
240+
String lunPath = cloudStackVolume.getLun().getName();
241+
s_logger.info("createManagedBlockVolume: iSCSI LUN created successfully: {}", lunPath);
242+
return lunPath;
139243
} else {
140-
String errMsg = "createCloudStackVolumeForTypeVolume: Volume creation failed. Lun or Lun Path is null for dataObject: " + dataObject;
244+
String errMsg = String.format("createManagedBlockVolume: LUN creation failed for volume [%s]. " +
245+
"LUN or LUN path is null.", dataObject.getUuid());
141246
s_logger.error(errMsg);
142247
throw new CloudRuntimeException(errMsg);
143248
}
144249
}
145250

251+
/**
252+
* Optional: Prepares ONTAP volume for optimal qcow2 file storage.
253+
*
254+
* Future enhancements can include:
255+
* - Enable compression for qcow2 files
256+
* - Set QoS policies
257+
* - Enable deduplication
258+
* - Configure snapshot policies
259+
*
260+
* This is a placeholder for ONTAP-specific optimizations.
261+
*/
262+
private void prepareOntapVolumeForQcow2Storage(DataStore dataStore, VolumeInfo volumeInfo) {
263+
// TODO: Implement ONTAP volume optimizations
264+
// Examples:
265+
// - storageStrategy.enableCompression(volumePath)
266+
// - storageStrategy.setQosPolicy(volumePath, iops)
267+
// - storageStrategy.enableDeduplication(volumePath)
268+
s_logger.debug("prepareOntapVolumeForQcow2Storage: Placeholder for future ONTAP optimizations");
269+
}
270+
146271
@Override
147272
public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
148-
273+
CommandResult commandResult = new CommandResult();
274+
try {
275+
if (store == null || data == null) {
276+
throw new CloudRuntimeException("deleteAsync: store or data is null");
277+
}
278+
if (data.getType() == DataObjectType.VOLUME) {
279+
StoragePoolVO storagePool = storagePoolDao.findById(store.getId());
280+
Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(store.getId());
281+
if (ProtocolType.NFS.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) {
282+
// ManagedNFS qcow2 backing file deletion handled by KVM host/libvirt; nothing to do via ONTAP REST.
283+
s_logger.info("deleteAsync: ManagedNFS volume {} no-op ONTAP deletion", data.getId());
284+
}
285+
}
286+
} catch (Exception e) {
287+
commandResult.setResult(e.getMessage());
288+
} finally {
289+
callback.complete(commandResult);
290+
}
149291
}
150292

151293
@Override
@@ -219,7 +361,7 @@ public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, Qual
219361

220362
@Override
221363
public boolean canProvideStorageStats() {
222-
return true;
364+
return false;
223365
}
224366

225367
@Override
@@ -229,7 +371,7 @@ public Pair<Long, Long> getStorageStats(StoragePool storagePool) {
229371

230372
@Override
231373
public boolean canProvideVolumeStats() {
232-
return true;
374+
return false; // Not yet implemented for RAW managed NFS
233375
}
234376

235377
@Override
@@ -291,4 +433,4 @@ private StorageStrategy getStrategyByStoragePoolDetails(Map<String, String> deta
291433
throw new CloudRuntimeException("getStrategyByStoragePoolDetails: Connection to Ontap SVM [" + details.get(Constants.SVM_NAME) + "] failed");
292434
}
293435
}
294-
}
436+
}

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
@@ -192,7 +192,7 @@ public DataStore initialize(Map<String, Object> dsInfos) {
192192
ProtocolType protocol = ProtocolType.valueOf(details.get(Constants.PROTOCOL));
193193
switch (protocol) {
194194
case NFS:
195-
parameters.setType(Storage.StoragePoolType.NetworkFilesystem);
195+
parameters.setType(Storage.StoragePoolType.ManagedNFS);
196196
// Path should be just the NFS export path (junction path), NOT host:path
197197
// CloudStack will construct the full mount path as: hostAddress + ":" + path
198198
path = "/" + storagePoolName;

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,22 @@ public void setOntapStorage(OntapStorage ontapStorage) {
7777
@Override
7878
public CloudStackVolume createCloudStackVolume(CloudStackVolume cloudstackVolume) {
7979
s_logger.info("createCloudStackVolume: Create cloudstack volume " + cloudstackVolume);
80-
try {
81-
createFile(cloudstackVolume.getVolume().getUuid(),cloudstackVolume.getCloudstackVolName(), cloudstackVolume.getFile());
82-
s_logger.debug("Successfully created file in ONTAP under volume with path {} or name {} ", cloudstackVolume.getVolume().getUuid(), cloudstackVolume.getCloudstackVolName());
83-
FileInfo responseFile = cloudstackVolume.getFile();
84-
responseFile.setPath(cloudstackVolume.getCloudstackVolName());
85-
}catch (Exception e) {
86-
s_logger.error("Exception occurred while creating file or dir: {}. Exception: {}", cloudstackVolume.getCloudstackVolName(), e.getMessage());
87-
throw new CloudRuntimeException("Failed to create file: " + e.getMessage());
88-
}
80+
// Skip ontap file creation for now
81+
// try {
82+
// boolean created = createFile(cloudstackVolume.getVolume().getUuid(),cloudstackVolume.getCloudstackVolName(), cloudstackVolume.getFile());
83+
// if(created){
84+
// s_logger.debug("Successfully created file in ONTAP under volume with path {} or name {} ", cloudstackVolume.getVolume().getUuid(), cloudstackVolume.getCloudstackVolName());
85+
// FileInfo responseFile = cloudstackVolume.getFile();
86+
// responseFile.setPath(cloudstackVolume.getCloudstackVolName());
87+
// }else {
88+
// s_logger.error("File not created for volume {}", cloudstackVolume.getVolume().getUuid());
89+
// throw new CloudRuntimeException("File not created");
90+
// }
91+
//
92+
// }catch (Exception e) {
93+
// s_logger.error("Exception occurred while creating file or dir: {}. Exception: {}", cloudstackVolume.getCloudstackVolName(), e.getMessage());
94+
// throw new CloudRuntimeException("Failed to create file: " + e.getMessage());
95+
// }
8996
return cloudstackVolume;
9097
}
9198

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,38 @@ public static String generateAuthHeader (String username, String password) {
5858
return BASIC + StringUtils.SPACE + new String(encodedBytes);
5959
}
6060

61+
/**
62+
* Creates CloudStackVolume request object for ONTAP REST API calls.
63+
*
64+
* IMPORTANT: For Managed NFS (Option 2 Implementation):
65+
* - The NFS case below is DEPRECATED and NOT USED
66+
* - OntapPrimaryDatastoreDriver.createManagedNfsVolume() handles NFS volumes
67+
* - It returns UUID only without creating files (KVM creates qcow2 automatically)
68+
* - This method is ONLY used for iSCSI/block storage volumes
69+
*
70+
* @param storagePool Storage pool information
71+
* @param details Storage pool details with ONTAP connection info
72+
* @param volumeObject Volume information
73+
* @return CloudStackVolume request for ONTAP REST API
74+
*/
6175
public static CloudStackVolume createCloudStackVolumeRequestByProtocol(StoragePoolVO storagePool, Map<String, String> details, VolumeInfo volumeObject) {
6276
CloudStackVolume cloudStackVolumeRequest = null;
6377

6478
String protocol = details.get(Constants.PROTOCOL);
6579
ProtocolType protocolType = ProtocolType.valueOf(protocol);
6680
switch (protocolType) {
6781
case NFS:
68-
// TODO add logic for NFS file creation
82+
// DEPRECATED: This NFS case is NOT USED in Option 2 Implementation
83+
// For Managed NFS, OntapPrimaryDatastoreDriver.createManagedNfsVolume()
84+
// returns UUID only and lets KVM create qcow2 files automatically.
85+
// This legacy code remains for reference but is bypassed in current implementation.
86+
s_logger.warn("createCloudStackVolumeRequestByProtocol: NFS case should not be called. " +
87+
"Use OntapPrimaryDatastoreDriver.createManagedNfsVolume() instead.");
6988
cloudStackVolumeRequest = new CloudStackVolume();
7089
FileInfo file = new FileInfo();
71-
//file.setName("test1"); // to be replaced with volume name // this should not be passed for dir
72-
//file.setName(volumeObject.getName()); // to check whether this needs to be sent or not
73-
file.setSize(Long.parseLong("10000"));
7490
file.setSize(volumeObject.getSize());
75-
file.setUnixPermissions(755); // check if it is needed only for dir ? it is needed for dir
76-
file.setType(FileInfo.TypeEnum.DIRECTORY); // We are creating file for a cloudstack volume . Should it be dir ? // TODO change once multipart is done
91+
file.setUnixPermissions(755);
92+
file.setType(FileInfo.TypeEnum.FILE);
7793

7894
Volume poolVolume = new Volume();
7995
poolVolume.setName(details.get(Constants.VOLUME_NAME));

0 commit comments

Comments
 (0)