-
Notifications
You must be signed in to change notification settings - Fork 0
CSTACKEX-35 Create Async #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,13 +18,17 @@ | |
| */ | ||
| package org.apache.cloudstack.storage.driver; | ||
|
|
||
| import com.cloud.agent.api.Answer; | ||
| import com.cloud.agent.api.to.DataObjectType; | ||
| import com.cloud.agent.api.to.DataStoreTO; | ||
| import com.cloud.agent.api.to.DataTO; | ||
| import com.cloud.exception.InvalidParameterValueException; | ||
| import com.cloud.host.Host; | ||
| import com.cloud.storage.Storage; | ||
| import com.cloud.storage.StoragePool; | ||
| import com.cloud.storage.Volume; | ||
| import com.cloud.utils.Pair; | ||
| import com.cloud.utils.exception.CloudRuntimeException; | ||
| import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; | ||
| import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; | ||
| import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; | ||
|
|
@@ -37,15 +41,30 @@ | |
| 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.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.OntapStorage; | ||
| import org.apache.cloudstack.storage.provider.StorageProviderFactory; | ||
| 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.utils.Constants; | ||
| import org.apache.cloudstack.storage.utils.Utility; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
|
|
||
| import javax.inject.Inject; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver { | ||
|
|
||
| private static final Logger s_logger = (Logger)LogManager.getLogger(OntapPrimaryDatastoreDriver.class); | ||
|
|
||
| @Inject private Utility utils; | ||
| @Inject private StoragePoolDetailsDao storagePoolDetailsDao; | ||
| @Inject private PrimaryDataStoreDao storagePoolDao; | ||
| @Override | ||
| public Map<String, String> getCapabilities() { | ||
| s_logger.trace("OntapPrimaryDatastoreDriver: getCapabilities: Called"); | ||
|
|
@@ -68,9 +87,71 @@ public DataStoreTO getStoreTO(DataStore store) { | |
| } | ||
|
|
||
| @Override | ||
| public void createAsync(DataStore store, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) { | ||
| public void createAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CreateCmdResult> callback) { | ||
| CreateCmdResult createCmdResult = null; | ||
| String path = null; | ||
| String errMsg = null; | ||
| if (dataStore == null) { | ||
| throw new InvalidParameterValueException("createAsync: dataStore should not be null"); | ||
| } | ||
| if (dataObject == null) { | ||
| throw new InvalidParameterValueException("createAsync: dataObject should not be null"); | ||
| } | ||
| if (callback == null) { | ||
| throw new InvalidParameterValueException("createAsync: callback should not be null"); | ||
| } | ||
| try { | ||
| s_logger.info("createAsync: Volume creation starting for data store [{}] and data object [{}] of type [{}]", | ||
|
||
| dataStore, dataObject, dataObject.getType()); | ||
| if (dataObject.getType() == DataObjectType.VOLUME) { | ||
| path = createCloudStackVolumeForTypeVolume(dataStore, dataObject); | ||
| createCmdResult = new CreateCmdResult(path, new Answer(null, true, null)); | ||
| } else { | ||
| errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; | ||
| s_logger.error(errMsg); | ||
| throw new CloudRuntimeException(errMsg); | ||
| } | ||
| } catch (Exception e) { | ||
| errMsg = e.getMessage(); | ||
| s_logger.error("createAsync: Volume creation failed for dataObject [{}]: {}", dataObject, errMsg); | ||
| createCmdResult = new CreateCmdResult(null, new Answer(null, false, errMsg)); | ||
| createCmdResult.setResult(e.toString()); | ||
| } finally { | ||
| callback.complete(createCmdResult); | ||
| } | ||
| } | ||
|
|
||
| s_logger.trace("OntapPrimaryDatastoreDriver: createAsync: Store: "+store+", data: "+data); | ||
| private String createCloudStackVolumeForTypeVolume(DataStore dataStore, DataObject dataObject) { | ||
| StoragePoolVO storagePool = storagePoolDao.findById(dataStore.getId()); | ||
| if(storagePool == null) { | ||
| throw new CloudRuntimeException("createCloudStackVolume : Storage Pool not found for id: " + dataStore.getId()); | ||
| } | ||
| Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(dataStore.getId()); | ||
| if(details == null || details.isEmpty()) { | ||
|
||
| throw new CloudRuntimeException("createCloudStackVolume : Storage Details not found for id: " + dataStore.getId()); | ||
| } | ||
| String protocol = details.get(Constants.PROTOCOL); | ||
| OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD), | ||
| details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), ProtocolType.valueOf(protocol), | ||
| Boolean.parseBoolean(details.get(Constants.IS_DISAGGREGATED))); | ||
| StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage); | ||
| boolean isValid = storageStrategy.connect(); | ||
| if (isValid) { | ||
| s_logger.info("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest", details.get(Constants.SVM_NAME)); | ||
| CloudStackVolume cloudStackVolumeRequest = utils.createCloudStackVolumeRequestByProtocol(storagePool, details, dataObject); | ||
| CloudStackVolume cloudStackVolume = storageStrategy.createCloudStackVolume(cloudStackVolumeRequest); | ||
| if (ProtocolType.ISCSI.name().equalsIgnoreCase(protocol) && cloudStackVolume.getLun() != null && cloudStackVolume.getLun().getName() != null) { | ||
| return cloudStackVolume.getLun().getName(); | ||
| } else { | ||
| String errMsg = "createCloudStackVolumeForTypeVolume: Volume creation failed. Lun or Lun Path is null for dataObject: " + dataObject; | ||
| s_logger.error(errMsg); | ||
| throw new CloudRuntimeException(errMsg); | ||
| } | ||
| } else { | ||
| String errMsg = "createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [" + details.get(Constants.SVM_NAME) + "] failed"; | ||
| s_logger.error(errMsg); | ||
| throw new CloudRuntimeException(errMsg); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,21 +19,59 @@ | |
|
|
||
| package org.apache.cloudstack.storage.service; | ||
|
|
||
| import com.cloud.utils.exception.CloudRuntimeException; | ||
| import org.apache.cloudstack.storage.feign.client.SANFeignClient; | ||
| import org.apache.cloudstack.storage.feign.model.Lun; | ||
| import org.apache.cloudstack.storage.feign.model.OntapStorage; | ||
| import org.apache.cloudstack.storage.feign.model.response.OntapResponse; | ||
| import org.apache.cloudstack.storage.service.model.AccessGroup; | ||
| import org.apache.cloudstack.storage.service.model.CloudStackVolume; | ||
| import org.apache.cloudstack.storage.utils.Constants; | ||
| import org.apache.cloudstack.storage.utils.Utility; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
|
|
||
| import javax.inject.Inject; | ||
| import java.net.URI; | ||
| import java.util.Map; | ||
|
|
||
| public class UnifiedSANStrategy extends SANStrategy{ | ||
| public class UnifiedSANStrategy extends SANStrategy { | ||
|
|
||
| private static final Logger s_logger = (Logger) LogManager.getLogger(UnifiedSANStrategy.class); | ||
| @Inject private Utility utils; | ||
| @Inject private SANFeignClient sanFeignClient; | ||
| public UnifiedSANStrategy(OntapStorage ontapStorage) { | ||
| super(ontapStorage); | ||
| } | ||
|
|
||
| @Override | ||
| public CloudStackVolume createCloudStackVolume(CloudStackVolume cloudstackVolume) { | ||
| //TODO | ||
| return null; | ||
| s_logger.info("createCloudStackVolume : Creating Lun with cloudstackVolume request {} ", cloudstackVolume); | ||
| if (cloudstackVolume == null || cloudstackVolume.getLun() == null) { | ||
| s_logger.error("createCloudStackVolume: LUN creation failed. Invalid cloudstackVolume request: {}", cloudstackVolume); | ||
| throw new CloudRuntimeException("createCloudStackVolume : Failed to create Lun, invalid cloudstackVolume request"); | ||
|
||
| } | ||
| try { | ||
| // Get AuthHeader | ||
| String authHeader = utils.generateAuthHeader(storage.getUsername(), storage.getPassword()); | ||
| // Create URI for lun creation | ||
| URI url = utils.generateURI(Constants.CREATE_LUN); | ||
| OntapResponse<Lun> createdLun = sanFeignClient.createLun(url, authHeader, true, cloudstackVolume.getLun()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add TODO, based on testing need to covert this createLun to Async
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||
| if (createdLun == null || createdLun.getRecords() == null || createdLun.getRecords().size() == 0) { | ||
| s_logger.error("createCloudStackVolume: LUN creation failed for Lun {}", cloudstackVolume.getLun().getName()); | ||
| throw new CloudRuntimeException("Failed to create Lun: " + cloudstackVolume.getLun().getName()); | ||
| } | ||
| Lun lun = createdLun.getRecords().get(0); | ||
| s_logger.debug("createCloudStackVolume: LUN created successfully. Lun: {}", lun); | ||
| s_logger.info("createCloudStackVolume: LUN created successfully. LunName: {}", lun.getName()); | ||
|
|
||
| CloudStackVolume createdCloudStackVolume = new CloudStackVolume(); | ||
| createdCloudStackVolume.setLun(lun); | ||
| return createdCloudStackVolume; | ||
| } catch (Exception e) { | ||
| s_logger.error("Exception occurred while creating LUN: {}. Exception: {}", cloudstackVolume.getLun().getName(), e.getMessage()); | ||
| throw new CloudRuntimeException("Failed to create Lun: " + e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,33 +20,89 @@ | |
| package org.apache.cloudstack.storage.utils; | ||
|
|
||
| import com.cloud.utils.StringUtils; | ||
| import com.cloud.utils.exception.CloudRuntimeException; | ||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; | ||
| 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.Lun; | ||
| import org.apache.cloudstack.storage.feign.model.LunSpace; | ||
| import org.apache.cloudstack.storage.feign.model.OntapStorage; | ||
| import org.apache.cloudstack.storage.feign.model.Svm; | ||
| import org.apache.cloudstack.storage.service.model.CloudStackVolume; | ||
| import org.apache.cloudstack.storage.service.model.ProtocolType; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.util.Base64Utils; | ||
|
|
||
| import javax.inject.Inject; | ||
| import java.net.URI; | ||
| import java.util.Map; | ||
|
|
||
| @Component | ||
| public class Utility { | ||
| @Inject | ||
| OntapStorage ontapStorage; | ||
|
|
||
| private static final Logger s_logger = (Logger) LogManager.getLogger(Utility.class); | ||
| @Inject private OntapStorage ontapStorage; | ||
| @Inject private PrimaryDataStoreDao storagePoolDao; | ||
| @Inject private StoragePoolDetailsDao storagePoolDetailsDao; | ||
|
|
||
| private static final String BASIC = "Basic"; | ||
| private static final String AUTH_HEADER_COLON = ":"; | ||
|
|
||
| /** | ||
| * Method generates authentication headers using storage backend credentials passed as normal string | ||
| * @param username -->> username of the storage backend | ||
| * @param password -->> normal decoded password of the storage backend | ||
| * | ||
| * @param username -->> username of the storage backend | ||
| * @param password -->> normal decoded password of the storage backend | ||
| * @return | ||
| */ | ||
| public String generateAuthHeader(String username, String password) { | ||
| public String generateAuthHeader (String username, String password) { | ||
| byte[] encodedBytes = Base64Utils.encode((username + AUTH_HEADER_COLON + password).getBytes()); | ||
| return BASIC + StringUtils.SPACE + new String(encodedBytes); | ||
| } | ||
|
|
||
| public URI generateURI(String path) { | ||
| public URI generateURI (String path) { | ||
| String uriString = Constants.HTTPS + ontapStorage.getManagementLIF() + path; | ||
| return URI.create(uriString); | ||
| } | ||
|
|
||
| public CloudStackVolume createCloudStackVolumeRequestByProtocol(StoragePoolVO storagePool, Map<String, String> details, DataObject dataObject) { | ||
| CloudStackVolume cloudStackVolumeRequest = null; | ||
|
|
||
| String protocol = details.get(Constants.PROTOCOL); | ||
| if (ProtocolType.ISCSI.name().equalsIgnoreCase(protocol)) { | ||
| cloudStackVolumeRequest = new CloudStackVolume(); | ||
| Lun lunRequest = new Lun(); | ||
| Svm svm = new Svm(); | ||
| svm.setName(details.get(Constants.SVM_NAME)); | ||
| lunRequest.setSvm(svm); | ||
|
|
||
| LunSpace lunSpace = new LunSpace(); | ||
| lunSpace.setSize(dataObject.getSize()); | ||
| lunRequest.setSpace(lunSpace); | ||
|
|
||
| String lunFullName = Constants.VOLUME_PATH_PREFIX + storagePool.getName() + Constants.PATH_SEPARATOR + dataObject.getName(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add example for lun full name
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||
| lunRequest.setName(lunFullName); | ||
|
|
||
| String hypervisorType = storagePool.getHypervisor().name(); | ||
| String osType = null; | ||
| switch (hypervisorType) { | ||
| case Constants.KVM: | ||
| osType = Lun.OsTypeEnum.LINUX.getValue(); | ||
| break; | ||
| default: | ||
| String errMsg = "createCloudStackVolume : Unsupported hypervisor type " + hypervisorType + " for ONTAP storage"; | ||
| s_logger.error(errMsg); | ||
| throw new CloudRuntimeException(errMsg); | ||
| } | ||
| lunRequest.setOsType(Lun.OsTypeEnum.valueOf(osType)); | ||
|
|
||
| cloudStackVolumeRequest.setLun(lunRequest); | ||
| return cloudStackVolumeRequest; | ||
| } else { | ||
| throw new CloudRuntimeException("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets remove this type cast
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!