diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java index 5e79aa2298da..90d075594498 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java @@ -27,6 +27,11 @@ import com.cloud.storage.Storage; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.SnapshotDetailsDao; +import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDetailsDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; @@ -41,14 +46,18 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.feign.model.FileInfo; import org.apache.cloudstack.storage.service.StorageStrategy; import org.apache.cloudstack.storage.service.model.CloudStackVolume; import org.apache.cloudstack.storage.service.model.ProtocolType; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.utils.Constants; import org.apache.cloudstack.storage.utils.Utility; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -62,6 +71,9 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver { @Inject private StoragePoolDetailsDao storagePoolDetailsDao; @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private VolumeDao volumeDao; + @Inject private VolumeDetailsDao volumeDetailsDao; + @Inject private SnapshotDetailsDao snapshotDetailsDao; @Override public Map getCapabilities() { @@ -227,6 +239,79 @@ public long getUsedIops(StoragePool storagePool) { @Override public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { + CreateCmdResult result; + + try { + VolumeInfo volumeInfo = snapshot.getBaseVolume(); + + VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId()); + if(volumeVO == null) { + throw new CloudRuntimeException("takeSnapshot: VolumeVO not found for id: " + volumeInfo.getId()); + } + + /** we are keeping file path at volumeVO.getPath() */ + + StoragePoolVO storagePool = storagePoolDao.findById(volumeVO.getPoolId()); + if(storagePool == null) { + s_logger.error("takeSnapshot : Storage Pool not found for id: " + volumeVO.getPoolId()); + throw new CloudRuntimeException("takeSnapshot : Storage Pool not found for id: " + volumeVO.getPoolId()); + } + Map poolDetails = storagePoolDetailsDao.listDetailsKeyPairs(volumeVO.getPoolId()); + StorageStrategy storageStrategy = Utility.getStrategyByStoragePoolDetails(poolDetails); + + CloudStackVolume cloudStackVolumeRequest = getCloudStackVolumeRequestByProtocol(poolDetails, volumeVO.getPath()); + CloudStackVolume cloudStackVolume = storageStrategy.getCloudStackVolume(cloudStackVolumeRequest); + if (cloudStackVolume == null || cloudStackVolume.getFile() == null) { + throw new CloudRuntimeException("takeSnapshot: Failed to get source file to take snapshot"); + } + long capacityBytes = storagePool.getCapacityBytes(); + + long usedBytes = getUsedBytes(storagePool); + long fileSize = cloudStackVolume.getFile().getSize(); + + usedBytes += fileSize; + + if (usedBytes > capacityBytes) { + throw new CloudRuntimeException("Insufficient space remains in this primary storage to take a snapshot"); + } + + storagePool.setUsedBytes(usedBytes); + + SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshot.getTO(); + + String fileSnapshotName = volumeInfo.getName() + "-" + snapshot.getUuid(); + + int maxSnapshotNameLength = 64; + int trimRequired = fileSnapshotName.length() - maxSnapshotNameLength; + + if (trimRequired > 0) { + fileSnapshotName = StringUtils.left(volumeInfo.getName(), (volumeInfo.getName().length() - trimRequired)) + "-" + snapshot.getUuid(); + } + + CloudStackVolume snapCloudStackVolumeRequest = snapshotCloudStackVolumeRequestByProtocol(poolDetails, volumeVO.getPath(), fileSnapshotName); + CloudStackVolume cloneCloudStackVolume = storageStrategy.snapshotCloudStackVolume(snapCloudStackVolumeRequest); + + updateSnapshotDetails(snapshot.getId(), volumeInfo.getId(), poolDetails.get(Constants.VOLUME_UUID), cloneCloudStackVolume.getFile().getPath(), volumeVO.getPoolId(), fileSize); + + snapshotObjectTo.setPath(Constants.ONTAP_SNAP_ID +"="+cloneCloudStackVolume.getFile().getPath()); + + /** Update size for the storage-pool including snapshot size */ + storagePoolDao.update(volumeVO.getPoolId(), storagePool); + + CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer(snapshotObjectTo); + + result = new CreateCmdResult(null, createObjectAnswer); + + result.setResult(null); + } + catch (Exception ex) { + s_logger.error("takeSnapshot: Failed due to ", ex); + result = new CreateCmdResult(null, new CreateObjectAnswer(ex.toString())); + + result.setResult(ex.toString()); + } + + callback.complete(result); } @Override @@ -293,4 +378,87 @@ public boolean isStorageSupportHA(Storage.StoragePoolType type) { public void detachVolumeFromAllStorageNodes(Volume volume) { } + + + private CloudStackVolume getCloudStackVolumeRequestByProtocol(Map details, String filePath) { + CloudStackVolume cloudStackVolumeRequest = null; + ProtocolType protocolType = null; + String protocol = null; + + try { + protocol = details.get(Constants.PROTOCOL); + protocolType = ProtocolType.valueOf(protocol); + } catch (IllegalArgumentException e) { + throw new CloudRuntimeException("getCloudStackVolumeRequestByProtocol: Protocol: "+ protocol +" is not valid"); + } + switch (protocolType) { + case NFS3: + cloudStackVolumeRequest = new CloudStackVolume(); + FileInfo fileInfo = new FileInfo(); + fileInfo.setPath(filePath); + cloudStackVolumeRequest.setFile(fileInfo); + String volumeUuid = details.get(Constants.VOLUME_UUID); + cloudStackVolumeRequest.setFlexVolumeUuid(volumeUuid); + break; + default: + throw new CloudRuntimeException("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol); + } + return cloudStackVolumeRequest; + } + +private CloudStackVolume snapshotCloudStackVolumeRequestByProtocol(Map details, + String sourcePath, + String destinationPath) { + CloudStackVolume cloudStackVolumeRequest = null; + ProtocolType protocolType = null; + String protocol = null; + + try { + protocol = details.get(Constants.PROTOCOL); + protocolType = ProtocolType.valueOf(protocol); + } catch (IllegalArgumentException e) { + throw new CloudRuntimeException("getCloudStackVolumeRequestByProtocol: Protocol: "+ protocol +" is not valid"); + } + switch (protocolType) { + case NFS3: + cloudStackVolumeRequest = new CloudStackVolume(); + FileInfo fileInfo = new FileInfo(); + fileInfo.setPath(sourcePath); + cloudStackVolumeRequest.setFile(fileInfo); + String volumeUuid = details.get(Constants.VOLUME_UUID); + cloudStackVolumeRequest.setFlexVolumeUuid(volumeUuid); + cloudStackVolumeRequest.setDestinationPath(destinationPath); + break; + default: + throw new CloudRuntimeException("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol); + + } + return cloudStackVolumeRequest; +} + + /** + * + * @param csSnapshotId: generated snapshot id from cloudstack + * @param csVolumeId: Source CS volume id + * @param ontapVolumeUuid: storage flexvolume id + * @param ontapNewSnapshot: generated snapshot id from ONTAP + * @param storagePoolId: primary storage pool id + * @param ontapSnapSize: Size of snapshot CS volume(LUN/file) + */ + private void updateSnapshotDetails(long csSnapshotId, long csVolumeId, String ontapVolumeUuid, String ontapNewSnapshot, long storagePoolId, long ontapSnapSize) { + SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(csSnapshotId, Constants.SRC_CS_VOLUME_ID, String.valueOf(csVolumeId), false); + snapshotDetailsDao.persist(snapshotDetail); + + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, Constants.BASE_ONTAP_FV_ID, String.valueOf(ontapVolumeUuid), false); + snapshotDetailsDao.persist(snapshotDetail); + + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, Constants.ONTAP_SNAP_ID, String.valueOf(ontapNewSnapshot), false); + snapshotDetailsDao.persist(snapshotDetail); + + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, Constants.PRIMARY_POOL_ID, String.valueOf(storagePoolId), false); + snapshotDetailsDao.persist(snapshotDetail); + + snapshotDetail = new SnapshotDetailsVO(csSnapshotId, Constants.ONTAP_SNAP_SIZE, String.valueOf(ontapSnapSize), false); + snapshotDetailsDao.persist(snapshotDetail); +} } diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/NASFeignClient.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/NASFeignClient.java index f48f83dc28de..8d4df6d8c4f1 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/NASFeignClient.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/NASFeignClient.java @@ -21,7 +21,9 @@ import feign.QueryMap; import org.apache.cloudstack.storage.feign.model.ExportPolicy; +import org.apache.cloudstack.storage.feign.model.FileClone; import org.apache.cloudstack.storage.feign.model.FileInfo; +import org.apache.cloudstack.storage.feign.model.response.JobResponse; import org.apache.cloudstack.storage.feign.model.response.OntapResponse; import feign.Headers; import feign.Param; @@ -58,6 +60,11 @@ void createFile(@Param("authHeader") String authHeader, @Param("path") String filePath, FileInfo file); + @RequestLine("POST /api/storage/volumes/{volumeUuid}/files/{path}") + @Headers({"Authorization: {authHeader}"}) + JobResponse cloneFile(@Param("authHeader") String authHeader, + FileClone fileClone); + // Export Policy Operations @RequestLine("POST /api/protocols/nfs/export-policies") @Headers({"Authorization: {authHeader}"}) diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/FileClone.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/FileClone.java new file mode 100644 index 000000000000..a117ec6e6a0b --- /dev/null +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/FileClone.java @@ -0,0 +1,51 @@ +/* + * 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 org.apache.cloudstack.storage.feign.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FileClone { + @JsonProperty("source_path") + private String sourcePath; + @JsonProperty("destination_path") + private String destinationPath; + @JsonProperty("volume") + private VolumeConcise volume; + public VolumeConcise getVolume() { + return volume; + } + public void setVolume(VolumeConcise volume) { + this.volume = volume; + } + public String getSourcePath() { + return sourcePath; + } + public void setSourcePath(String sourcePath) { + this.sourcePath = sourcePath; + } + public String getDestinationPath() { + return destinationPath; + } + public void setDestinationPath(String destinationPath) {} +} diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/VolumeConcise.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/VolumeConcise.java new file mode 100644 index 000000000000..eaa5b2ed2ae9 --- /dev/null +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/VolumeConcise.java @@ -0,0 +1,43 @@ +/* + * 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 org.apache.cloudstack.storage.feign.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class VolumeConcise { + @JsonProperty("uuid") + private String uuid; + @JsonProperty("name") + private String name; + public String getUuid() { + return uuid; + } + public void setUuid(String uuid) { + this.uuid = uuid; + } + public String getName() { + return name; + } + public void setName(String name) {} +} diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java index 822e09851f39..88d21ec28ac1 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java @@ -393,8 +393,6 @@ public String getStoragePath() { return targetIqn; } - - /** * Get the network ip interface * @@ -484,7 +482,19 @@ public String getNetworkInterface() { * @param cloudstackVolume the CloudStack volume to retrieve * @return the retrieved CloudStackVolume object */ - abstract CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume); + public abstract CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume); + + /** + * Method encapsulates the behavior based on the opted protocol in subclasses. + * it is going to mimic + * snapshotLun for iSCSI, FC protocols + * snapshotFile for NFS3.0 and NFS4.1 protocols + * + * + * @param cloudstackVolume the source CloudStack volume + * @return the retrieved snapshot CloudStackVolume object + */ + public abstract CloudStackVolume snapshotCloudStackVolume(CloudStackVolume cloudstackVolume); /** * Method encapsulates the behavior based on the opted protocol in subclasses @@ -547,7 +557,7 @@ public String getNetworkInterface() { */ abstract void disableLogicalAccess(Map values); - private Boolean jobPollForSuccess(String jobUUID) { + public Boolean jobPollForSuccess(String jobUUID) { //Create URI for GET Job API int jobRetryCount = 0; Job jobResp = null; diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java index b35bedf2ef3c..3a6c0998c087 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java @@ -38,12 +38,14 @@ import org.apache.cloudstack.storage.feign.client.VolumeFeignClient; import org.apache.cloudstack.storage.feign.model.ExportPolicy; import org.apache.cloudstack.storage.feign.model.ExportRule; +import org.apache.cloudstack.storage.feign.model.FileClone; import org.apache.cloudstack.storage.feign.model.FileInfo; import org.apache.cloudstack.storage.feign.model.Job; import org.apache.cloudstack.storage.feign.model.Nas; import org.apache.cloudstack.storage.feign.model.OntapStorage; import org.apache.cloudstack.storage.feign.model.Svm; import org.apache.cloudstack.storage.feign.model.Volume; +import org.apache.cloudstack.storage.feign.model.VolumeConcise; import org.apache.cloudstack.storage.feign.model.response.JobResponse; import org.apache.cloudstack.storage.feign.model.response.OntapResponse; import org.apache.cloudstack.storage.service.model.AccessGroup; @@ -115,9 +117,71 @@ void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { } @Override - CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume) { - //TODO - return null; + public CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolumeArg) { + s_logger.info("getCloudStackVolume: Get cloudstack volume " + cloudstackVolumeArg); + CloudStackVolume cloudStackVolume = null; + FileInfo fileInfo = getFile(cloudstackVolumeArg.getFlexVolumeUuid(),cloudstackVolumeArg.getFile().getPath()); + + if(fileInfo != null){ + cloudStackVolume = new CloudStackVolume(); + cloudStackVolume.setFlexVolumeUuid(cloudstackVolumeArg.getFlexVolumeUuid()); + cloudStackVolume.setFile(fileInfo); + } + + return cloudStackVolume; + } + + @Override + public CloudStackVolume snapshotCloudStackVolume(CloudStackVolume cloudstackVolumeArg) { + s_logger.info("snapshotCloudStackVolume: Get cloudstack volume " + cloudstackVolumeArg); + CloudStackVolume cloudStackVolume = null; + String authHeader = Utility.generateAuthHeader(storage.getUsername(), storage.getPassword()); + JobResponse jobResponse = null; + + FileClone fileClone = new FileClone(); + VolumeConcise volumeConcise = new VolumeConcise(); + volumeConcise.setUuid(cloudstackVolumeArg.getFlexVolumeUuid()); + fileClone.setVolume(volumeConcise); + + fileClone.setSourcePath(cloudstackVolumeArg.getFile().getPath()); + fileClone.setDestinationPath(cloudstackVolumeArg.getDestinationPath()); + + try { + /** Clone file call to storage */ + jobResponse = nasFeignClient.cloneFile(authHeader, fileClone); + if (jobResponse == null || jobResponse.getJob() == null) { + throw new CloudRuntimeException("Failed to initiate file clone" + cloudstackVolumeArg.getFile().getPath()); + } + String jobUUID = jobResponse.getJob().getUuid(); + + /** Create URI for GET Job API */ + Boolean jobSucceeded = jobPollForSuccess(jobUUID); + if (!jobSucceeded) { + s_logger.error("File clone failed: " + cloudstackVolumeArg.getFile().getPath()); + throw new CloudRuntimeException("File clone failed: " + cloudstackVolumeArg.getFile().getPath()); + } + s_logger.info("File clone job completed successfully for file: " + cloudstackVolumeArg.getFile().getPath()); + + } catch (FeignException e) { + s_logger.error("Failed to clone file response: " + cloudstackVolumeArg.getFile().getPath(), e); + throw new CloudRuntimeException("File not found: " + e.getMessage()); + } catch (Exception e) { + s_logger.error("Exception to get file: {}", cloudstackVolumeArg.getFile().getPath(), e); + throw new CloudRuntimeException("Failed to get the file: " + e.getMessage()); + } + + FileInfo clonedFileInfo = null; + try { + /** Get cloned file call from storage */ + clonedFileInfo = getFile(cloudstackVolumeArg.getFlexVolumeUuid(), cloudstackVolumeArg.getDestinationPath()); + } catch (Exception e) { + s_logger.error("Exception to get cloned file: {}", cloudstackVolumeArg.getDestinationPath(), e); + throw new CloudRuntimeException("Failed to get the cloned file: " + e.getMessage()); + } + cloudStackVolume = new CloudStackVolume(); + cloudStackVolume.setFlexVolumeUuid(cloudstackVolumeArg.getFlexVolumeUuid()); + cloudStackVolume.setFile(clonedFileInfo); + return cloudStackVolume; } @Override @@ -460,4 +524,26 @@ private Answer createVolumeOnKVMHost(DataObject volumeInfo) { return new Answer(null, false, e.toString()); } } + + private FileInfo getFile(String volumeUuid, String filePath) { + s_logger.info("Get File: {} for volume: {}", filePath, volumeUuid); + + String authHeader = Utility.generateAuthHeader(storage.getUsername(), storage.getPassword()); + OntapResponse fileResponse = null; + try { + fileResponse = nasFeignClient.getFileResponse(authHeader, volumeUuid, filePath); + if (fileResponse == null || fileResponse.getRecords().isEmpty()) { + throw new CloudRuntimeException("File " + filePath + " not not found on ONTAP. " + + "Received successful response but file does not exist."); + } + } catch (FeignException e) { + s_logger.error("Failed to get file response: " + filePath, e); + throw new CloudRuntimeException("File not found: " + e.getMessage()); + } catch (Exception e) { + s_logger.error("Exception to get file: {}", filePath, e); + throw new CloudRuntimeException("Failed to get the file: " + e.getMessage()); + } + s_logger.info("File retrieved successfully with name {}", filePath); + return fileResponse.getRecords().get(0); + } } diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java index 7b5372c69bdd..f738e3e5d2da 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java @@ -104,11 +104,16 @@ void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { } @Override - CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume) { + public CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume) { //TODO return null; } + @Override + public CloudStackVolume snapshotCloudStackVolume(CloudStackVolume cloudstackVolume) { + return null; + } + @Override public AccessGroup createAccessGroup(AccessGroup accessGroup) { s_logger.info("createAccessGroup : Create Igroup"); diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/model/CloudStackVolume.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/model/CloudStackVolume.java index 6c51e4630800..c62d093fe071 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/model/CloudStackVolume.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/model/CloudStackVolume.java @@ -25,9 +25,27 @@ public class CloudStackVolume { + /** + * Filed used for request: + * a. snapshot workflows will get source file details from it. + */ private FileInfo file; + /** + * Filed used for request: + * a. snapshot workflows will get source LUN details from it. + */ private Lun lun; private String datastoreId; + /** + * FlexVolume UUID on which this cloudstack volume is created. + * a. Field is eligible for unified storage only. + * b. It will be null for the disaggregated storage. + */ + private String flexVolumeUuid; + /** + * Field serves for snapshot workflows + */ + private String destinationPath; private DataObject volumeInfo; // This is needed as we need DataObject to be passed to agent to create volume public FileInfo getFile() { return file; @@ -37,6 +55,10 @@ public void setFile(FileInfo file) { this.file = file; } + public String getDestinationPath() { return this.destinationPath; } + + public void setDestinationPath(String destinationPath) { this.destinationPath = destinationPath; } + public Lun getLun() { return lun; } @@ -56,4 +78,10 @@ public DataObject getVolumeInfo() { public void setVolumeInfo(DataObject volumeInfo) { this.volumeInfo = volumeInfo; } + public String getFlexVolumeUuid() { + return flexVolumeUuid; + } + public void setFlexVolumeUuid(String flexVolumeUuid) { + this.flexVolumeUuid = flexVolumeUuid; + } } diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/Constants.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/Constants.java index 23425aa6b797..5909a540af24 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/Constants.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/Constants.java @@ -84,4 +84,9 @@ public class Constants { public static final String IGROUP_DOT_UUID = "igroup.uuid"; public static final String UNDERSCORE = "_"; public static final String CS = "cs"; + public static final String SRC_CS_VOLUME_ID = "src_cs_volume_id"; + public static final String BASE_ONTAP_FV_ID = "base_ontap_fv_id"; + public static final String ONTAP_SNAP_ID = "ontap_snap_id"; + public static final String PRIMARY_POOL_ID = "primary_pool_id"; + public static final String ONTAP_SNAP_SIZE = "ontap_snap_size"; }