@Override
  public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
    long accountId = volumeInfo.getAccountId();

    AccountDetailVO accountDetail =
        _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_USERNAME);

    String chapInitiatorUsername = accountDetail.getValue();

    accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_SECRET);

    String chapInitiatorSecret = accountDetail.getValue();

    StoragePoolDetailVO storagePoolDetail =
        _storagePoolDetailsDao.findDetail(
            volumeInfo.getPoolId(), SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE);

    boolean useMutualChapForVMware = new Boolean(storagePoolDetail.getValue());

    String chapTargetUsername = null;
    String chapTargetSecret = null;

    if (useMutualChapForVMware) {
      accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME);

      chapTargetUsername = accountDetail.getValue();

      accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET);

      chapTargetSecret = accountDetail.getValue();
    }

    return new ChapInfoImpl(
        chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
  }
  @Override
  public void createAsync(
      DataStore dataStore,
      DataObject dataObject,
      AsyncCompletionCallback<CreateCmdResult> callback) {
    String iqn = null;
    String errMsg = null;

    if (dataObject.getType() == DataObjectType.VOLUME) {
      VolumeInfo volumeInfo = (VolumeInfo) dataObject;
      AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
      String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId());

      long storagePoolId = dataStore.getId();
      SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);

      if (!sfAccountExists(sfAccountName, sfConnection)) {
        SolidFireUtil.SolidFireAccount sfAccount =
            createSolidFireAccount(sfAccountName, sfConnection);

        updateCsDbWithAccountInfo(account.getId(), sfAccount);
      }

      SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(volumeInfo, sfConnection);

      iqn = sfVolume.getIqn();

      VolumeVO volume = this._volumeDao.findById(volumeInfo.getId());

      volume.set_iScsiName(iqn);
      volume.setFolder(String.valueOf(sfVolume.getId()));
      volume.setPoolType(StoragePoolType.IscsiLUN);
      volume.setPoolId(storagePoolId);

      _volumeDao.update(volume.getId(), volume);

      StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId());

      long capacityBytes = storagePool.getCapacityBytes();
      long usedBytes = storagePool.getUsedBytes();

      usedBytes += volumeInfo.getSize();

      storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes);

      _storagePoolDao.update(storagePoolId, storagePool);
    } else {
      errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
    }

    // path = iqn
    // size is pulled from DataObject instance, if errMsg is null
    CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));

    result.setResult(errMsg);

    callback.complete(result);
  }
  @Override
  public void deleteAsync(
      DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
    String errMsg = null;

    if (dataObject.getType() == DataObjectType.VOLUME) {
      VolumeInfo volumeInfo = (VolumeInfo) dataObject;
      AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
      AccountDetailVO accountDetails =
          _accountDetailsDao.findDetail(account.getAccountId(), SolidFireUtil.ACCOUNT_ID);
      long sfAccountId = Long.parseLong(accountDetails.getValue());

      long storagePoolId = dataStore.getId();
      SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);

      deleteSolidFireVolume(volumeInfo, sfConnection);

      _volumeDao.deleteVolumesByInstance(volumeInfo.getId());

      //            if (!sfAccountHasVolume(sfAccountId, sfConnection)) {
      //                // delete the account from the SolidFire SAN
      //                deleteSolidFireAccount(sfAccountId, sfConnection);
      //
      //                // delete the info in the account_details table
      //                // that's related to the SolidFire account
      //                _accountDetailsDao.deleteDetails(account.getAccountId());
      //            }

      StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);

      long usedBytes = storagePool.getUsedBytes();

      usedBytes -= volumeInfo.getSize();

      storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes);

      _storagePoolDao.update(storagePoolId, storagePool);
    } else {
      errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync";
    }

    CommandResult result = new CommandResult();

    result.setResult(errMsg);

    callback.complete(result);
  }
  private SolidFireUtil.SolidFireVolume createSolidFireVolume(
      VolumeInfo volumeInfo, SolidFireConnection sfConnection) {
    String mVip = sfConnection.getManagementVip();
    int mPort = sfConnection.getManagementPort();
    String clusterAdminUsername = sfConnection.getClusterAdminUsername();
    String clusterAdminPassword = sfConnection.getClusterAdminPassword();

    AccountDetailVO accountDetail =
        _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID);
    long sfAccountId = Long.parseLong(accountDetail.getValue());

    long storagePoolId = volumeInfo.getDataStore().getId();

    final Iops iops;

    Long minIops = volumeInfo.getMinIops();
    Long maxIops = volumeInfo.getMaxIops();

    if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) {
      long defaultMaxIops = getDefaultMaxIops(storagePoolId);

      iops =
          new Iops(
              getDefaultMinIops(storagePoolId),
              defaultMaxIops,
              getDefaultBurstIops(storagePoolId, defaultMaxIops));
    } else {
      iops =
          new Iops(
              volumeInfo.getMinIops(),
              volumeInfo.getMaxIops(),
              getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops()));
    }

    long sfVolumeId =
        SolidFireUtil.createSolidFireVolume(
            mVip,
            mPort,
            clusterAdminUsername,
            clusterAdminPassword,
            getSolidFireVolumeName(volumeInfo.getName()),
            sfAccountId,
            volumeInfo.getSize(),
            true,
            iops.getMinIops(),
            iops.getMaxIops(),
            iops.getBurstIops());

    return SolidFireUtil.getSolidFireVolume(
        mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
  }
  private void deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) {
    Long storagePoolId = volumeInfo.getPoolId();

    if (storagePoolId == null) {
      return; // this volume was never assigned to a storage pool, so no SAN volume should exist for
              // it
    }

    String mVip = sfConnection.getManagementVip();
    int mPort = sfConnection.getManagementPort();
    String clusterAdminUsername = sfConnection.getClusterAdminUsername();
    String clusterAdminPassword = sfConnection.getClusterAdminPassword();

    long sfVolumeId = Long.parseLong(volumeInfo.getFolder());

    SolidFireUtil.deleteSolidFireVolume(
        mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
  }
  /** Marshall the given parameter object, and output to a SdkJsonGenerator */
  public void marshall(VolumeInfo volumeInfo, StructuredJsonGenerator jsonGenerator) {

    if (volumeInfo == null) {
      throw new AmazonClientException("Invalid argument passed to marshall(...)");
    }

    try {
      jsonGenerator.writeStartObject();

      if (volumeInfo.getVolumeARN() != null) {
        jsonGenerator.writeFieldName("VolumeARN").writeValue(volumeInfo.getVolumeARN());
      }
      if (volumeInfo.getVolumeType() != null) {
        jsonGenerator.writeFieldName("VolumeType").writeValue(volumeInfo.getVolumeType());
      }

      jsonGenerator.writeEndObject();
    } catch (Throwable t) {
      throw new AmazonClientException("Unable to marshall request to JSON: " + t.getMessage(), t);
    }
  }