You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mt...@apache.org on 2015/10/14 20:09:45 UTC
[5/7] git commit: updated refs/heads/sf-plugins-a to 49ca3b4
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/49ca3b40/plugins/api/solidfire/src/org/apache/cloudstack/solidfire/SolidFireManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/api/solidfire/src/org/apache/cloudstack/solidfire/SolidFireManagerImpl.java b/plugins/api/solidfire/src/org/apache/cloudstack/solidfire/SolidFireManagerImpl.java
new file mode 100644
index 0000000..e02a9c5
--- /dev/null
+++ b/plugins/api/solidfire/src/org/apache/cloudstack/solidfire/SolidFireManagerImpl.java
@@ -0,0 +1,977 @@
+// 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.solidfire;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+import org.apache.cloudstack.dataaccess.dao.solidfire.SfClusterDao;
+import org.apache.cloudstack.dataaccess.dao.solidfire.SfVirtualNetworkDao;
+import org.apache.cloudstack.dataaccess.dao.solidfire.SfVolumeDao;
+import org.apache.cloudstack.dataaccess.vo.solidfire.SfClusterVO;
+import org.apache.cloudstack.dataaccess.vo.solidfire.SfVirtualNetworkVO;
+import org.apache.cloudstack.dataaccess.vo.solidfire.SfVolumeVO;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
+import org.apache.cloudstack.util.solidfire.SfUtil;
+import org.apache.cloudstack.util.solidfire.SolidFireConnection;
+import org.springframework.stereotype.Component;
+
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountDetailVO;
+import com.cloud.user.AccountDetailsDao;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Component
+public class SolidFireManagerImpl implements SolidFireManager {
+ private static final Logger s_logger = Logger.getLogger(SolidFireManagerImpl.class);
+ private static final int s_lockTimeInSeconds = 180;
+
+ private static final ConfigKey<Long> s_sfTotalAccountCapacity =
+ new ConfigKey<>(
+ "Advanced",
+ Long.class,
+ "sf.total.capacity",
+ "0",
+ "Total capacity the account can draw from any and all SolidFire clusters (in GBs)",
+ true, ConfigKey.Scope.Account);
+
+ private static final ConfigKey<Long> s_sfTotalAccountMinIops =
+ new ConfigKey<>(
+ "Advanced",
+ Long.class,
+ "sf.total.min.iops",
+ "0",
+ "Total minimum IOPS the account can draw from any and all SolidFire clusters",
+ true, ConfigKey.Scope.Account);
+
+ private static final ConfigKey<Long> s_sfTotalAccountMaxIops =
+ new ConfigKey<>(
+ "Advanced",
+ Long.class,
+ "sf.total.max.iops",
+ "0",
+ "Total maximum IOPS the account can draw from any and all SolidFire clusters",
+ true, ConfigKey.Scope.Account);
+
+ private static final ConfigKey<Long> s_sfTotalAccountBurstIops =
+ new ConfigKey<>(
+ "Advanced",
+ Long.class,
+ "sf.total.burst.iops",
+ "0",
+ "Total burst IOPS the account can draw from any and all SolidFire clusters",
+ true, ConfigKey.Scope.Account);
+
+ @Inject private AccountDao _accountDao;
+ @Inject private AccountDetailsDao _accountDetailsDao;
+ @Inject private DataCenterDao _zoneDao;
+ @Inject private SfClusterDao _sfClusterDao;
+ @Inject private SfVirtualNetworkDao _sfVirtualNetworkDao;
+ @Inject private SfVolumeDao _sfVolumeDao;
+ @Inject private SfUtil _sfUtil;
+
+ private SolidFireManagerImpl() {
+ }
+
+ @Override
+ public SfCluster listSolidFireCluster(String clusterName) {
+ s_logger.info("listSolidFireCluster invoked");
+
+ verifyRootAdmin();
+
+ return getSfCluster(clusterName);
+ }
+
+ @Override
+ public List<SfCluster> listSolidFireClusters() {
+ s_logger.info("listSolidFireClusters invoked");
+
+ verifyRootAdmin();
+
+ List<SfCluster> sfClusters = new ArrayList<>();
+
+ List<SfClusterVO> sfClusterVOs = _sfClusterDao.listAll();
+
+ if (sfClusterVOs != null) {
+ sfClusters.addAll(sfClusterVOs);
+ }
+
+ return sfClusters;
+ }
+
+ @Override
+ public SfCluster createReferenceToSolidFireCluster(String mvip, String username, String password, long totalCapacity,
+ long totalMinIops, long totalMaxIops, long totalBurstIops, long zoneId) {
+ s_logger.info("createReferenceToSolidFireCluster invoked");
+
+ verifyRootAdmin();
+
+ verifyClusterQuotas(totalCapacity, totalMinIops, totalMaxIops, totalBurstIops);
+
+ verifyZone(zoneId);
+
+ SolidFireConnection sfConnection = new SolidFireConnection(mvip, username, password);
+
+ String clusterName = sfConnection.getClusterName();
+
+ List<SfClusterVO> sfClusterVOs = _sfClusterDao.listAll();
+
+ for (SfCluster sfCluster : sfClusterVOs) {
+ if (sfCluster.getName().equals(clusterName)) {
+ throw new CloudRuntimeException("Unable to add a reference to cluster '" + clusterName + "' as a reference to a cluster by this name already exists");
+ }
+ }
+
+ SfClusterVO sfClusterVO = new SfClusterVO(clusterName, mvip, username, password, totalCapacity, totalMinIops, totalMaxIops, totalBurstIops, zoneId);
+
+ return _sfClusterDao.persist(sfClusterVO);
+ }
+
+ @Override
+ public SfCluster updateReferenceToSolidFireCluster(String clusterName, long newTotalCapacity,
+ long newTotalMinIops, long newTotalMaxIops, long newTotalBurstIops) {
+ s_logger.info("updateReferenceToSolidFireCluster invoked");
+
+ verifyRootAdmin();
+
+ verifyClusterQuotas(newTotalCapacity, newTotalMinIops, newTotalMaxIops, newTotalBurstIops);
+
+ SfClusterVO sfClusterVO = getSfCluster(clusterName);
+
+ GlobalLock sfClusterLock = GlobalLock.getInternLock(sfClusterVO.getUuid());
+
+ if (!sfClusterLock.lock(s_lockTimeInSeconds)) {
+ String errMsg = "Couldn't lock the DB on the following string (Storage cluster UUID): " + sfClusterVO.getUuid();
+
+ s_logger.debug(errMsg);
+
+ throw new CloudRuntimeException(errMsg);
+ }
+
+ try {
+ TotalRemaining totalRemainingInCluster = getTotalRemainingInCluster(sfClusterVO);
+
+ long totalUsedCapacityInCluster = sfClusterVO.getTotalCapacity() - totalRemainingInCluster.getTotalRemainingCapacity();
+ long totalUsedMinIopsInCluster = sfClusterVO.getTotalMinIops() - totalRemainingInCluster.getTotalRemainingMinIops();
+ long totalUsedMaxIopsInCluster = sfClusterVO.getTotalMaxIops() - totalRemainingInCluster.getTotalRemainingMaxIops();
+ long totalUsedBurstIopsInCluster = sfClusterVO.getTotalBurstIops() - totalRemainingInCluster.getTotalRemainingBurstIops();
+
+ if (totalUsedCapacityInCluster <= newTotalCapacity && totalUsedMinIopsInCluster <= newTotalMinIops &&
+ totalUsedMaxIopsInCluster <= newTotalMaxIops && totalUsedBurstIopsInCluster <= newTotalBurstIops) {
+ sfClusterVO.setTotalCapacity(newTotalCapacity);
+ sfClusterVO.setTotalMinIops(newTotalMinIops);
+ sfClusterVO.setTotalMaxIops(newTotalMaxIops);
+ sfClusterVO.setTotalBurstIops(newTotalBurstIops);
+
+ if (_sfClusterDao.update(sfClusterVO.getId(), sfClusterVO)) {
+ return sfClusterVO;
+ }
+
+ throw new CloudRuntimeException("Unable to update the cluster table");
+ }
+ else {
+ throw new CloudRuntimeException("Unable to update the cluster table as more capacity and/or performance is in use " +
+ "in the storage cluster than one or more of the values passed in");
+ }
+ }
+ finally {
+ sfClusterLock.unlock();
+ sfClusterLock.releaseRef();
+ }
+ }
+
+ @Override
+ public SfCluster deleteReferenceToSolidFireCluster(String clusterName) {
+ s_logger.info("deleteReferenceToSolidFireCluster invoked");
+
+ verifyRootAdmin();
+
+ SfCluster sfCluster = getSfCluster(clusterName);
+
+ List<SfVirtualNetworkVO> sfVirtualNetworks = _sfVirtualNetworkDao.findByClusterId(sfCluster.getId());
+
+ if (sfVirtualNetworks != null && sfVirtualNetworks.size() > 0) {
+ throw new CloudRuntimeException("Unable to delete a reference to a cluster that has one or more virtual networks");
+ }
+
+ if (!_sfClusterDao.remove(sfCluster.getId())) {
+ throw new CloudRuntimeException("Unable to remove the following cluster: " + clusterName);
+ }
+
+ return sfCluster;
+ }
+
+ @Override
+ public SfVirtualNetwork listSolidFireVirtualNetworkById(long id) {
+ s_logger.info("listSolidFireVirtualNetworkById invoked");
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(id);
+
+ verifyPermissionsForAccount(sfVirtualNetwork.getAccountId());
+
+ return getSfVirtualNetwork(id);
+ }
+
+ @Override
+ public List<SfVirtualNetwork> listSolidFireVirtualNetworkByClusterName(String clusterName) {
+ s_logger.info("listSolidFireVirtualNetworkByClusterName invoked");
+
+ verifyRootAdmin();
+
+ SfCluster sfCluster = getSfCluster(clusterName);
+
+ return filterVirtualNetworksByCluster(_sfVirtualNetworkDao.listAll(), sfCluster.getId());
+ }
+
+ @Override
+ public List<SfVirtualNetwork> listSolidFireVirtualNetworks(Long zoneId, Long accountId) {
+ s_logger.info("listSolidFireVirtualNetworks invoked");
+
+ final List<SfVirtualNetworkVO> sfVirtualNetworkVOs;
+
+ if (_sfUtil.isRootAdmin()) {
+ if (zoneId != null) {
+ if (accountId != null) {
+ sfVirtualNetworkVOs = filterVirtualNetworksByZone(_sfVirtualNetworkDao.findByAccountId(accountId), zoneId);
+ }
+ else {
+ sfVirtualNetworkVOs = filterVirtualNetworksByZone(_sfVirtualNetworkDao.listAll(), zoneId);
+ }
+ }
+ else {
+ if (accountId != null) {
+ sfVirtualNetworkVOs = _sfVirtualNetworkDao.findByAccountId(accountId);
+ }
+ else {
+ sfVirtualNetworkVOs = _sfVirtualNetworkDao.listAll();
+ }
+ }
+ }
+ else {
+ if (accountId != null && accountId != _sfUtil.getCallingAccount().getId()) {
+ throw new CloudRuntimeException("Only a root admin can specify an account other than his own.");
+ }
+
+ if (zoneId != null) {
+ sfVirtualNetworkVOs = filterVirtualNetworksByZone(_sfVirtualNetworkDao.findByAccountId(_sfUtil.getCallingAccount().getId()), zoneId);
+ }
+ else {
+ sfVirtualNetworkVOs = _sfVirtualNetworkDao.findByAccountId(_sfUtil.getCallingAccount().getId());
+ }
+ }
+
+ List<SfVirtualNetwork> sfVirtualNetworks = new ArrayList<>();
+
+ if (sfVirtualNetworkVOs != null) {
+ sfVirtualNetworks.addAll(sfVirtualNetworkVOs);
+ }
+
+ return sfVirtualNetworks;
+ }
+
+ @Override
+ public SfVirtualNetwork createSolidFireVirtualNetwork(String clusterName, String name, String tag, String startIp, int size,
+ String netmask, String svip, long accountId) {
+ s_logger.info("createSolidFireVirtualNetwork invoked");
+
+ verifyRootAdmin();
+
+ verifyAccount(accountId);
+
+ SfCluster sfCluster = getSfCluster(clusterName);
+
+ SolidFireConnection sfConnection = new SolidFireConnection(sfCluster.getMvip(), sfCluster.getUsername(), sfCluster.getPassword());
+
+ long sfVirtualNetworkId = sfConnection.createVirtualNetwork(name, tag, startIp, size, netmask, svip);
+
+ SfVirtualNetworkVO sfVirtualNetworkVO = new SfVirtualNetworkVO(sfVirtualNetworkId, name, tag, startIp, size, netmask, svip, accountId, sfCluster.getId());
+
+ return _sfVirtualNetworkDao.persist(sfVirtualNetworkVO);
+ }
+
+ @Override
+ public SfVirtualNetwork updateSolidFireVirtualNetwork(long id, String name, String startIp, int size, String netmask) {
+ s_logger.info("updateSolidFireVirtualNetwork invoked");
+
+ verifyRootAdmin();
+
+ SfVirtualNetworkVO sfVirtualNetworkVO = getSfVirtualNetwork(id);
+
+ long sfClusterId = sfVirtualNetworkVO.getSfClusterId();
+
+ SfClusterVO sfClusterVO = getSfCluster(sfClusterId);
+
+ SolidFireConnection sfConnection = new SolidFireConnection(sfClusterVO.getMvip(), sfClusterVO.getUsername(), sfClusterVO.getPassword());
+
+ sfConnection.modifyVirtualNetwork(sfVirtualNetworkVO.getSfId(), name, startIp, size, netmask);
+
+ sfVirtualNetworkVO.setName(name);
+ sfVirtualNetworkVO.setStartIp(startIp);
+ sfVirtualNetworkVO.setSize(size);
+ sfVirtualNetworkVO.setNetmask(netmask);
+
+ if (_sfVirtualNetworkDao.update(sfVirtualNetworkVO.getId(), sfVirtualNetworkVO)) {
+ return sfVirtualNetworkVO;
+ }
+
+ throw new CloudRuntimeException("Unable to update the virtual network table");
+ }
+
+ @Override
+ public SfVirtualNetwork deleteSolidFireVirtualNetwork(long id) {
+ s_logger.info("deleteSolidFireVirtualNetwork invoked");
+
+ verifyRootAdmin();
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(id);
+
+ List<SfVolumeVO> sfVolumes = _sfVolumeDao.findBySfVirtualNetworkId(sfVirtualNetwork.getId());
+
+ if (sfVolumes != null && sfVolumes.size() > 0) {
+ throw new CloudRuntimeException("Unable to delete a virtual network that has one or more volumes");
+ }
+
+ if (!_sfVirtualNetworkDao.remove(id)) {
+ throw new CloudRuntimeException("Unable to remove the following virtual network: " + id);
+ }
+
+ SfCluster sfCluster = getSfCluster(sfVirtualNetwork.getSfClusterId());
+
+ SolidFireConnection sfConnection = new SolidFireConnection(sfCluster.getMvip(), sfCluster.getUsername(), sfCluster.getPassword());
+
+ sfConnection.deleteVirtualNetwork(sfVirtualNetwork.getSfId());
+
+ return sfVirtualNetwork;
+ }
+
+ @Override
+ public SfVolume listSolidFireVolume(long id) {
+ s_logger.info("listSolidFireVolume invoked");
+
+ SfVolume sfVolume = getSfVolume(id);
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(sfVolume.getSfVirtualNetworkId());
+
+ verifyPermissionsForAccount(sfVirtualNetwork.getAccountId());
+
+ return sfVolume;
+ }
+
+ @Override
+ public List<SfVolume> listSolidFireVolumes() {
+ s_logger.info("listSolidFireVolumes invoked");
+
+ final List<SfVolumeVO> sfVolumeVOs;
+
+ if (_sfUtil.isRootAdmin()) {
+ sfVolumeVOs = _sfVolumeDao.listAll();
+ }
+ else {
+ sfVolumeVOs = new ArrayList<>();
+
+ List<SfVirtualNetworkVO> sfVirtualNetworkVOs = _sfVirtualNetworkDao.findByAccountId(_sfUtil.getCallingAccount().getId());
+
+ if (sfVirtualNetworkVOs != null) {
+ for (SfVirtualNetwork sfVirtualNetwork : sfVirtualNetworkVOs) {
+ List<SfVolumeVO> sfVolumeVOsForVirtualNetwork = _sfVolumeDao.findBySfVirtualNetworkId(sfVirtualNetwork.getId());
+
+ sfVolumeVOs.addAll(sfVolumeVOsForVirtualNetwork);
+ }
+ }
+ }
+
+ List<SfVolume> sfVolumes = new ArrayList<>();
+
+ if (sfVolumeVOs != null) {
+ sfVolumes.addAll(sfVolumeVOs);
+ }
+
+ return sfVolumes;
+ }
+
+ @Override
+ public SfVolume createSolidFireVolume(String name, long size, long minIops, long maxIops, long burstIops, long accountId, long sfVirtualNetworkId) {
+ s_logger.info("createSolidFireVolume invoked");
+
+ verifyPermissionsForAccount(accountId);
+
+ verifySfVirtualNetwork(sfVirtualNetworkId);
+
+ SfVolume sfVolume = createVolume(name, size, minIops, maxIops, burstIops, accountId, sfVirtualNetworkId);
+
+ if (sfVolume != null) {
+ return sfVolume;
+ }
+
+ throw new CloudRuntimeException("Unable to create the volume");
+ }
+
+ @Override
+ public SfVolume updateSolidFireVolume(long id, long size, long minIops, long maxIops, long burstIops) {
+ s_logger.info("updateSolidFireVolume invoked");
+
+ SfVolumeVO sfVolumeVO = getSfVolume(id);
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(sfVolumeVO.getSfVirtualNetworkId());
+
+ verifyPermissionsForAccount(sfVirtualNetwork.getAccountId());
+
+ if ((sfVolumeVO = updateVolume(sfVolumeVO, size, minIops, maxIops, burstIops)) != null) {
+ return sfVolumeVO;
+ }
+
+ throw new CloudRuntimeException("Unable to update the volume with the following id: " + id);
+ }
+
+ @Override
+ public SfVolume deleteSolidFireVolume(long id) {
+ s_logger.info("deleteSolidFireVolume invoked");
+
+ SfVolume sfVolume = getSfVolume(id);
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(sfVolume.getSfVirtualNetworkId());
+
+ verifyPermissionsForAccount(sfVirtualNetwork.getAccountId());
+
+ if (!_sfVolumeDao.remove(id)) {
+ throw new CloudRuntimeException("Unable to remove the following volume: " + id);
+ }
+
+ SfCluster sfCluster = getSfCluster(sfVirtualNetwork.getSfClusterId());
+
+ SolidFireConnection sfConnection = new SolidFireConnection(sfCluster.getMvip(), sfCluster.getUsername(), sfCluster.getPassword());
+
+ sfConnection.deleteVolume(sfVolume.getSfId());
+
+ return sfVolume;
+ }
+
+ @Override
+ public String getConfigComponentName() {
+ return SolidFireManagerImpl.class.getSimpleName();
+ }
+
+ @Override
+ public ConfigKey<?>[] getConfigKeys() {
+ return new ConfigKey<?>[] { s_sfTotalAccountCapacity, s_sfTotalAccountMinIops, s_sfTotalAccountMaxIops, s_sfTotalAccountBurstIops };
+ }
+
+ private SfClusterVO getSfCluster(String clusterName) {
+ SfClusterVO sfClusterVO = _sfClusterDao.findByName(clusterName);
+
+ if (sfClusterVO == null) {
+ throw new CloudRuntimeException("The following SolidFire cluster name cannot be located in the database: '" + clusterName + "'.");
+ }
+
+ return sfClusterVO;
+ }
+
+ private SfClusterVO getSfCluster(long sfClusterId) {
+ SfClusterVO sfClusterVO = _sfClusterDao.findById(sfClusterId);
+
+ if (sfClusterVO == null) {
+ throw new CloudRuntimeException("The SolidFire cluster with the following ID cannot be located in the database: '" + sfClusterId + "'.");
+ }
+
+ return sfClusterVO;
+ }
+
+ private SfVirtualNetworkVO getSfVirtualNetwork(long id) {
+ SfVirtualNetworkVO sfVirtualNetworkVO = _sfVirtualNetworkDao.findById(id);
+
+ if (sfVirtualNetworkVO == null) {
+ throw new CloudRuntimeException("The SolidFire VLAN with the following ID cannot be located in the database: '" + id + "'.");
+ }
+
+ return sfVirtualNetworkVO;
+ }
+
+ private SfVolumeVO getSfVolume(long id) {
+ SfVolumeVO sfVolumeVO = _sfVolumeDao.findById(id);
+
+ if (sfVolumeVO == null) {
+ throw new CloudRuntimeException("The SolidFire volume with the following ID cannot be located in the database: '" + id + "'.");
+ }
+
+ return sfVolumeVO;
+ }
+
+ private void verifyRootAdmin() {
+ if (!_sfUtil.isRootAdmin()) {
+ throw new PermissionDeniedException("Only a root admin can perform this operation.");
+ }
+ }
+
+ private void verifyPermissionsForAccount(long accountId) {
+ Account account = _sfUtil.getCallingAccount();
+
+ if (_sfUtil.isRootAdmin(account.getId())) {
+ return; // permissions OK
+ }
+
+ if (account.getId() == accountId) {
+ return; // permissions OK
+ }
+
+ throw new PermissionDeniedException("Only a root admin or a user of the owning account can perform this operation.");
+ }
+
+ private void verifyClusterQuotas(long totalCapacity, long totalMinIops, long totalMaxIops, long totalBurstIops) {
+ if (totalCapacity < 0) {
+ throw new CloudRuntimeException("The total capacity of the cluster must be a positive whole number.");
+ }
+
+ if (totalMinIops < 0) {
+ throw new CloudRuntimeException("The total minimum IOPS of the cluster must be a positive whole number.");
+ }
+
+ if (totalMaxIops < 0) {
+ throw new CloudRuntimeException("The total maximum IOPS of the cluster must be a positive whole number.");
+ }
+
+ if (totalBurstIops < 0) {
+ throw new CloudRuntimeException("The total burst IOPS of the cluster must be a positive whole number.");
+ }
+
+ if (totalMinIops > totalMaxIops) {
+ throw new CloudRuntimeException("The total minimum IOPS of the cluster must be less than or equal to the total maximum IOPS of the cluster.");
+ }
+
+ if (totalMaxIops > totalBurstIops) {
+ throw new CloudRuntimeException("The total maximum IOPS of the cluster must be less than or equal to the total burst IOPS of the cluster.");
+ }
+ }
+
+ private void verifyAccount(long accountId) {
+ Account account = _accountDao.findById(accountId);
+
+ if (account == null) {
+ throw new CloudRuntimeException("Unable to locate the following account: " + accountId);
+ }
+ }
+
+ private void verifySfVirtualNetwork(long sfVirtualNetworkId) {
+ SfVirtualNetwork sfVirtualNetwork = _sfVirtualNetworkDao.findById(sfVirtualNetworkId);
+
+ if (sfVirtualNetwork == null) {
+ throw new CloudRuntimeException("Unable to locate the following virtual network: " + sfVirtualNetworkId);
+ }
+ }
+
+ private void verifyZone(long zoneId) {
+ DataCenterVO dataCenterVO = _zoneDao.findById(zoneId);
+
+ if (dataCenterVO == null) {
+ throw new CloudRuntimeException("Unable to locate the following zone: " + zoneId);
+ }
+ }
+
+ private SfVolume createVolume(String name, long size, long minIops, long maxIops, long burstIops, long accountId, long sfVirtualNetworkId) {
+ verifyIops(minIops, maxIops, burstIops);
+
+ Account account = _accountDao.findById(accountId);
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(sfVirtualNetworkId);
+ SfCluster sfCluster = getSfCluster(sfVirtualNetwork.getSfClusterId());
+
+ GlobalLock accountLock = GlobalLock.getInternLock(account.getUuid());
+
+ if (!accountLock.lock(s_lockTimeInSeconds)) {
+ String errMsg = "Couldn't lock the DB on the following string (Account UUID): " + sfCluster.getUuid();
+
+ s_logger.debug(errMsg);
+
+ throw new CloudRuntimeException(errMsg);
+ }
+
+ GlobalLock sfClusterLock = GlobalLock.getInternLock(sfCluster.getUuid());
+
+ boolean clusterLockSuccess = false;
+
+ try {
+ clusterLockSuccess = sfClusterLock.lock(s_lockTimeInSeconds);
+ }
+ catch (Throwable t) {
+ // clusterLockSuccess should still be false
+ }
+
+ if (!clusterLockSuccess) {
+ accountLock.unlock();
+ accountLock.releaseRef();
+
+ String errMsg = "Couldn't lock the DB on the following string (Storage cluster UUID): " + sfCluster.getUuid();
+
+ s_logger.debug(errMsg);
+
+ throw new CloudRuntimeException(errMsg);
+ }
+
+ try {
+ TotalRemaining totalRemainingInAccount = getTotalRemainingInAccount(accountId);
+
+ long totalRemainingCapacityInAccount = totalRemainingInAccount.getTotalRemainingCapacity() - size;
+ long totalRemainingMinIopsInAccount = totalRemainingInAccount.getTotalRemainingMinIops() - minIops;
+ long totalRemainingMaxIopsInAccount = totalRemainingInAccount.getTotalRemainingMaxIops() - maxIops;
+ long totalRemainingBurstIopsInAccount = totalRemainingInAccount.getTotalRemainingBurstIops() - burstIops;
+
+ if (totalRemainingCapacityInAccount >= 0 && totalRemainingMinIopsInAccount >= 0 && totalRemainingMaxIopsInAccount >= 0 && totalRemainingBurstIopsInAccount >= 0) {
+ TotalRemaining totalRemainingInCluster = getTotalRemainingInCluster(sfCluster);
+
+ long totalRemainingCapacityInCluster = totalRemainingInCluster.getTotalRemainingCapacity() - size;
+ long totalRemainingMinIopsInCluster = totalRemainingInCluster.getTotalRemainingMinIops() - minIops;
+ long totalRemainingMaxIopsInCluster = totalRemainingInCluster.getTotalRemainingMaxIops() - maxIops;
+ long totalRemainingBurstIopsInCluster = totalRemainingInCluster.getTotalRemainingBurstIops() - burstIops;
+
+ if (totalRemainingCapacityInCluster >= 0 && totalRemainingMinIopsInCluster >= 0 && totalRemainingMaxIopsInCluster >= 0 && totalRemainingBurstIopsInCluster >= 0) {
+ SolidFireConnection sfConnection = new SolidFireConnection(sfCluster.getMvip(), sfCluster.getUsername(), sfCluster.getPassword());
+
+ long sfClusterId = sfCluster.getId();
+
+ AccountDetailVO accountDetail = getAccountDetail(accountId, sfClusterId);
+
+ if (accountDetail == null || accountDetail.getValue() == null) {
+ String sfAccountName = getSolidFireAccountName(accountId, account.getUuid());
+ SolidFireConnection.SolidFireAccount sfAccount = sfConnection.getSolidFireAccount(sfAccountName);
+
+ if (sfAccount == null) {
+ sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
+ }
+
+ updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, sfClusterId);
+
+ accountDetail = getAccountDetail(accountId, sfClusterId);
+ }
+
+ long sfAccountId = Long.parseLong(accountDetail.getValue());
+
+ long sfVolumeId = sfConnection.createVolume(name, sfAccountId, size, minIops, maxIops, burstIops);
+
+ SolidFireConnection.SolidFireVolume sfVolume = sfConnection.getVolume(sfVolumeId);
+
+ SfVolumeVO sfVolumeVO = new SfVolumeVO(sfVolumeId, name, sfVolume.getIqn(), size, minIops, maxIops, burstIops, sfVirtualNetworkId);
+
+ return _sfVolumeDao.persist(sfVolumeVO);
+ }
+ else {
+ throw new CloudRuntimeException("Unable to create the volume due to insufficient capacity or performance remaining in the storage cluster");
+ }
+ }
+ else {
+ throw new CloudRuntimeException("Unable to create the volume due to insufficient capacity or performance remaining in the account");
+ }
+ }
+ finally {
+ sfClusterLock.unlock();
+ sfClusterLock.releaseRef();
+
+ accountLock.unlock();
+ accountLock.releaseRef();
+ }
+ }
+
+ private SfVolumeVO updateVolume(SfVolumeVO sfVolumeVO, long size, long minIops, long maxIops, long burstIops) {
+ verifyIops(minIops, maxIops, burstIops);
+
+ SfVirtualNetwork sfVirtualNetwork = getSfVirtualNetwork(sfVolumeVO.getSfVirtualNetworkId());
+
+ Account account = _accountDao.findById(sfVirtualNetwork.getAccountId());
+ SfCluster sfCluster = getSfCluster(sfVirtualNetwork.getSfClusterId());
+
+ GlobalLock accountLock = GlobalLock.getInternLock(account.getUuid());
+
+ if (!accountLock.lock(s_lockTimeInSeconds)) {
+ String errMsg = "Couldn't lock the DB on the following string (Account UUID): " + sfCluster.getUuid();
+
+ s_logger.debug(errMsg);
+
+ throw new CloudRuntimeException(errMsg);
+ }
+
+ GlobalLock sfClusterLock = GlobalLock.getInternLock(sfCluster.getUuid());
+
+ boolean clusterLockSuccess = false;
+
+ try {
+ clusterLockSuccess = sfClusterLock.lock(s_lockTimeInSeconds);
+ }
+ catch (Throwable t) {
+ // clusterLockSuccess should still be false
+ }
+
+ if (!clusterLockSuccess) {
+ accountLock.unlock();
+ accountLock.releaseRef();
+
+ String errMsg = "Couldn't lock the DB on the following string (Storage cluster UUID): " + sfCluster.getUuid();
+
+ s_logger.debug(errMsg);
+
+ throw new CloudRuntimeException(errMsg);
+ }
+
+ try {
+ TotalRemaining totalRemainingInAccount = getTotalRemainingInAccount(account.getId());
+
+ long totalRemainingCapacityInAccount = totalRemainingInAccount.getTotalRemainingCapacity() - size;
+ long totalRemainingMinIopsInAccount = totalRemainingInAccount.getTotalRemainingMinIops() - minIops;
+ long totalRemainingMaxIopsInAccount = totalRemainingInAccount.getTotalRemainingMaxIops() - maxIops;
+ long totalRemainingBurstIopsInAccount = totalRemainingInAccount.getTotalRemainingBurstIops() - burstIops;
+
+ if (totalRemainingCapacityInAccount >= 0 && totalRemainingMinIopsInAccount >= 0 && totalRemainingMaxIopsInAccount >= 0 && totalRemainingBurstIopsInAccount >= 0) {
+ TotalRemaining totalRemainingInCluster = getTotalRemainingInCluster(sfCluster, sfVolumeVO);
+
+ long totalRemainingCapacityInCluster = totalRemainingInCluster.getTotalRemainingCapacity() - size;
+ long totalRemainingMinIopsInCluster = totalRemainingInCluster.getTotalRemainingMinIops() - minIops;
+ long totalRemainingMaxIopsInCluster = totalRemainingInCluster.getTotalRemainingMaxIops() - maxIops;
+ long totalRemainingBurstIopsInCluster = totalRemainingInCluster.getTotalRemainingBurstIops() - burstIops;
+
+ if (totalRemainingCapacityInCluster >= 0 && totalRemainingMinIopsInCluster >= 0 && totalRemainingMaxIopsInCluster >= 0 && totalRemainingBurstIopsInCluster >= 0) {
+ SolidFireConnection sfConnection = new SolidFireConnection(sfCluster.getMvip(), sfCluster.getUsername(), sfCluster.getPassword());
+
+ sfConnection.modifyVolume(sfVolumeVO.getSfId(), size, minIops, maxIops, burstIops);
+
+ sfVolumeVO.setSize(size);
+ sfVolumeVO.setMinIops(minIops);
+ sfVolumeVO.setMaxIops(maxIops);
+ sfVolumeVO.setBurstIops(burstIops);
+
+ if (!_sfVolumeDao.update(sfVolumeVO.getId(), sfVolumeVO)) {
+ throw new CloudRuntimeException("Unable to update the following volume:" + sfVolumeVO.getId());
+ }
+
+ return sfVolumeVO;
+ }
+ else {
+ throw new CloudRuntimeException("Unable to update the volume due to insufficient capacity or performance remaining in the storage cluster");
+ }
+ }
+ else {
+ throw new CloudRuntimeException("Unable to update the volume due to insufficient capacity or performance remaining in the account");
+ }
+ }
+ finally {
+ sfClusterLock.unlock();
+ sfClusterLock.releaseRef();
+
+ accountLock.unlock();
+ accountLock.releaseRef();
+ }
+ }
+
+ private TotalRemaining getTotalRemainingInAccount(long accountId) {
+ return getTotalRemainingInAccount(accountId, null);
+ }
+
+ private TotalRemaining getTotalRemainingInAccount(long accountId, SfVolume volumeToExclude) {
+ Long totalRemainingCapacity = s_sfTotalAccountCapacity.valueIn(accountId);
+ Long totalRemainingMinIops = s_sfTotalAccountMinIops.valueIn(accountId);
+ Long totalRemainingMaxIops = s_sfTotalAccountMaxIops.valueIn(accountId);
+ Long totalRemainingBurstIops = s_sfTotalAccountBurstIops.valueIn(accountId);
+
+ List<SfVolume> sfVolumesInAccount = new ArrayList<>();
+
+ List<SfVirtualNetworkVO> sfVirtualNetworkVOs = _sfVirtualNetworkDao.findByAccountId(accountId);
+
+ if (sfVirtualNetworkVOs != null) {
+ for (SfVirtualNetwork sfVirtualNetwork : sfVirtualNetworkVOs) {
+ List<SfVolumeVO> sfVolumeVOs = _sfVolumeDao.findBySfVirtualNetworkId(sfVirtualNetwork.getId());
+
+ sfVolumesInAccount.addAll(sfVolumeVOs);
+ }
+ }
+
+ for (SfVolume sfVolumeInAccount : sfVolumesInAccount) {
+ if (volumeToExclude == null || sfVolumeInAccount.getId() != volumeToExclude.getId()) {
+ totalRemainingCapacity -= sfVolumeInAccount.getSize();
+ totalRemainingMinIops -= sfVolumeInAccount.getMinIops();
+ totalRemainingMaxIops -= sfVolumeInAccount.getMaxIops();
+ totalRemainingBurstIops -= sfVolumeInAccount.getBurstIops();
+ }
+ }
+
+ return new TotalRemaining(totalRemainingCapacity, totalRemainingMinIops, totalRemainingMaxIops, totalRemainingBurstIops);
+ }
+
+ private TotalRemaining getTotalRemainingInCluster(SfCluster sfCluster) {
+ return getTotalRemainingInCluster(sfCluster, null);
+ }
+
+ private TotalRemaining getTotalRemainingInCluster(SfCluster sfCluster, SfVolume volumeToExclude) {
+ long totalRemainingCapacity = sfCluster.getTotalCapacity();
+ long totalRemainingMinIops = sfCluster.getTotalMinIops();
+ long totalRemainingMaxIops = sfCluster.getTotalMaxIops();
+ long totalRemainingBurstIops = sfCluster.getTotalBurstIops();
+
+ List<SfVolume> sfVolumesInCluster = new ArrayList<>();
+
+ List<SfVirtualNetworkVO> sfVirtualNetworkVOs = _sfVirtualNetworkDao.findByClusterId(sfCluster.getId());
+
+ if (sfVirtualNetworkVOs != null) {
+ for (SfVirtualNetwork sfVirtualNetwork : sfVirtualNetworkVOs) {
+ List<SfVolumeVO> sfVolumeVOs = _sfVolumeDao.findBySfVirtualNetworkId(sfVirtualNetwork.getId());
+
+ sfVolumesInCluster.addAll(sfVolumeVOs);
+ }
+ }
+
+ for (SfVolume sfVolumeInCluster : sfVolumesInCluster) {
+ if (volumeToExclude == null || sfVolumeInCluster.getId() != volumeToExclude.getId()) {
+ totalRemainingCapacity -= sfVolumeInCluster.getSize();
+ totalRemainingMinIops -= sfVolumeInCluster.getMinIops();
+ totalRemainingMaxIops -= sfVolumeInCluster.getMaxIops();
+ totalRemainingBurstIops -= sfVolumeInCluster.getBurstIops();
+ }
+ }
+
+ return new TotalRemaining(totalRemainingCapacity, totalRemainingMinIops, totalRemainingMaxIops, totalRemainingBurstIops);
+ }
+
+ private static class TotalRemaining {
+ private final long _totalRemainingCapacity;
+ private final long _totalRemainingMinIops;
+ private final long _totalRemainingMaxIops;
+ private final long _totalRemainingBurstIops;
+
+ public TotalRemaining(long totalRemainingCapacity, long totalRemainingMinIops, long totalRemainingMaxIops, long totalRemainingBurstIops) {
+ _totalRemainingCapacity = totalRemainingCapacity;
+ _totalRemainingMinIops = totalRemainingMinIops;
+ _totalRemainingMaxIops = totalRemainingMaxIops;
+ _totalRemainingBurstIops = totalRemainingBurstIops;
+ }
+
+ public long getTotalRemainingCapacity() {
+ return _totalRemainingCapacity;
+ }
+
+ public long getTotalRemainingMinIops() {
+ return _totalRemainingMinIops;
+ }
+
+ public long getTotalRemainingMaxIops() {
+ return _totalRemainingMaxIops;
+ }
+
+ public long getTotalRemainingBurstIops() {
+ return _totalRemainingBurstIops;
+ }
+ }
+
+ private static String getSolidFireAccountName(long accountId, String accountUuid) {
+ return "CloudStack_" + accountId + "_" + accountUuid;
+ }
+
+ private static String getAccountKey(long sfClusterId) {
+ return "sfAccountIdForClusterId_" + sfClusterId;
+ }
+
+ private AccountDetailVO getAccountDetail(long accountId, long sfClusterId) {
+ return _accountDetailsDao.findDetail(accountId, getAccountKey(sfClusterId));
+ }
+
+ private SolidFireConnection.SolidFireAccount createSolidFireAccount(SolidFireConnection sfConnection, String sfAccountName) {
+ long accountNumber = sfConnection.createSolidFireAccount(sfAccountName);
+
+ return sfConnection.getSolidFireAccountById(accountNumber);
+ }
+
+ private void updateCsDbWithSolidFireAccountInfo(long accountId, SolidFireConnection.SolidFireAccount sfAccount, long sfClusterId) {
+ AccountDetailVO accountDetail = new AccountDetailVO(accountId,
+ getAccountKey(sfClusterId),
+ String.valueOf(sfAccount.getId()));
+
+ _accountDetailsDao.persist(accountDetail);
+
+ accountDetail = new AccountDetailVO(accountId,
+ SolidFireUtil.CHAP_INITIATOR_USERNAME,
+ sfAccount.getName());
+
+ _accountDetailsDao.persist(accountDetail);
+
+ accountDetail = new AccountDetailVO(accountId,
+ SolidFireUtil.CHAP_INITIATOR_SECRET,
+ sfAccount.getInitiatorSecret());
+
+ _accountDetailsDao.persist(accountDetail);
+
+ accountDetail = new AccountDetailVO(accountId,
+ SolidFireUtil.CHAP_TARGET_USERNAME,
+ sfAccount.getName());
+
+ _accountDetailsDao.persist(accountDetail);
+
+ accountDetail = new AccountDetailVO(accountId,
+ SolidFireUtil.CHAP_TARGET_SECRET,
+ sfAccount.getTargetSecret());
+
+ _accountDetailsDao.persist(accountDetail);
+ }
+
+ private List<SfVirtualNetwork> filterVirtualNetworksByCluster(List<SfVirtualNetworkVO> sfVirtualNetworkVOs, long clusterId) {
+ List<SfVirtualNetwork> sfVirtualNetworkVOsToReturn = new ArrayList<>();
+
+ if (sfVirtualNetworkVOs != null) {
+ for (SfVirtualNetworkVO sfVirtualNetworkVO : sfVirtualNetworkVOs) {
+ long sfClusterId = sfVirtualNetworkVO.getSfClusterId();
+
+ if (sfClusterId == clusterId) {
+ sfVirtualNetworkVOsToReturn.add(sfVirtualNetworkVO);
+ }
+ }
+ }
+
+ return sfVirtualNetworkVOsToReturn;
+ }
+
+ private List<SfVirtualNetworkVO> filterVirtualNetworksByZone(List<SfVirtualNetworkVO> sfVirtualNetworkVOs, long zoneId) {
+ List<SfVirtualNetworkVO> sfVirtualNetworkVOsToReturn = new ArrayList<>();
+
+ if (sfVirtualNetworkVOs != null) {
+ for (SfVirtualNetworkVO sfVirtualNetworkVO : sfVirtualNetworkVOs) {
+ SfCluster sfCluster = getSfCluster(sfVirtualNetworkVO.getSfClusterId());
+
+ if (sfCluster.getZoneId() == zoneId) {
+ sfVirtualNetworkVOsToReturn.add(sfVirtualNetworkVO);
+ }
+ }
+ }
+
+ return sfVirtualNetworkVOsToReturn;
+ }
+
+ private static void verifyIops(long minIops, long maxIops, long burstIops) {
+ if (minIops <= 0 || maxIops <= 0 || burstIops <= 0) {
+ throw new IllegalArgumentException("The 'Min IOPS', 'Max IOPS', and 'Burst IOPS' values must be greater than 0.");
+ }
+
+ if (minIops > maxIops) {
+ throw new IllegalArgumentException("The 'Min IOPS' value cannot exceed the 'Max IOPS' value.");
+ }
+
+ if (maxIops > burstIops) {
+ throw new IllegalArgumentException("The 'Max IOPS' value cannot exceed the 'Burst IOPS' value.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/49ca3b40/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SfUtil.java
----------------------------------------------------------------------
diff --git a/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SfUtil.java b/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SfUtil.java
new file mode 100644
index 0000000..ea9df30
--- /dev/null
+++ b/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SfUtil.java
@@ -0,0 +1,221 @@
+package org.apache.cloudstack.util.solidfire;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.response.solidfire.ApiSolidFireClusterResponse;
+import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVirtualNetworkResponse;
+import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.dataaccess.dao.solidfire.SfClusterDao;
+import org.apache.cloudstack.dataaccess.dao.solidfire.SfVirtualNetworkDao;
+import org.apache.cloudstack.solidfire.SfCluster;
+import org.apache.cloudstack.solidfire.SfVirtualNetwork;
+import org.apache.cloudstack.solidfire.SfVolume;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
+
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountDetailVO;
+import com.cloud.user.AccountDetailsDao;
+import com.cloud.user.AccountManager;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class SfUtil {
+ @Inject private AccountDao _accountDao;
+ @Inject private AccountDetailsDao _accountDetailsDao;
+ @Inject private AccountManager _accountMgr;
+ @Inject private SfClusterDao _sfClusterDao;
+ @Inject private DataCenterDao _zoneDao;
+ @Inject private SfVirtualNetworkDao _sfVirtualNetworkDao;
+
+ private SfUtil() {
+ }
+
+ public ApiSolidFireClusterResponse getApiSolidFireClusterResponse(SfCluster sfCluster) {
+ ApiSolidFireClusterResponse sfResponse = new ApiSolidFireClusterResponse();
+
+ sfResponse.setId(sfCluster.getId());
+ sfResponse.setUuid(sfCluster.getUuid());
+ sfResponse.setName(sfCluster.getName());
+ sfResponse.setMvip(sfCluster.getMvip());
+ sfResponse.setUsername(sfCluster.getUsername());
+ sfResponse.setTotalCapacity(sfCluster.getTotalCapacity());
+ sfResponse.setTotalMinIops(sfCluster.getTotalMinIops());
+ sfResponse.setTotalMaxIops(sfCluster.getTotalMaxIops());
+ sfResponse.setTotalBurstIops(sfCluster.getTotalBurstIops());
+ sfResponse.setZoneId(sfCluster.getZoneId());
+
+ DataCenterVO dataCenterVO = _zoneDao.findById(sfCluster.getZoneId());
+
+ sfResponse.setZoneName(dataCenterVO.getName());
+
+ sfResponse.setObjectName("sfcluster");
+
+ return sfResponse;
+ }
+
+ public List<ApiSolidFireClusterResponse> getApiSolidFireClusterResponse(List<SfCluster> sfClusters) {
+ List<ApiSolidFireClusterResponse> sfResponse = new ArrayList<>();
+
+ if (sfClusters != null) {
+ for (SfCluster sfCluster : sfClusters) {
+ ApiSolidFireClusterResponse response = getApiSolidFireClusterResponse(sfCluster);
+
+ sfResponse.add(response);
+ }
+ }
+
+ return sfResponse;
+ }
+
+ public ApiSolidFireVirtualNetworkResponse getApiSolidFireVirtualNetworkResponse(SfVirtualNetwork sfVirtualNetwork, ResponseView responseView) {
+ ApiSolidFireVirtualNetworkResponse sfResponse = new ApiSolidFireVirtualNetworkResponse();
+
+ sfResponse.setId(sfVirtualNetwork.getId());
+ sfResponse.setUuid(sfVirtualNetwork.getUuid());
+ sfResponse.setName(sfVirtualNetwork.getName());
+ sfResponse.setSvip(sfVirtualNetwork.getSvip());
+ sfResponse.setAccountId(sfVirtualNetwork.getAccountId());
+
+ Account account = _accountDao.findById(sfVirtualNetwork.getAccountId());
+
+ sfResponse.setAccountUuid(account.getUuid());
+ sfResponse.setAccountName(account.getAccountName());
+
+ SfCluster sfCluster = _sfClusterDao.findById(sfVirtualNetwork.getSfClusterId());
+
+ sfResponse.setZoneId(sfCluster.getZoneId());
+
+ DataCenterVO dataCenterVO = _zoneDao.findById(sfCluster.getZoneId());
+
+ sfResponse.setZoneUuid(dataCenterVO.getUuid());
+ sfResponse.setZoneName(dataCenterVO.getName());
+
+ if (ResponseView.Full.equals(responseView)) {
+ sfResponse.setTag(sfVirtualNetwork.getTag());
+ sfResponse.setStartIp(sfVirtualNetwork.getStartIp());
+ sfResponse.setSize(sfVirtualNetwork.getSize());
+ sfResponse.setNetmask(sfVirtualNetwork.getNetmask());
+ sfResponse.setClusterName(sfCluster.getName());
+ }
+
+ sfResponse.setObjectName("sfvirtualnetwork");
+
+ return sfResponse;
+ }
+
+ public List<ApiSolidFireVirtualNetworkResponse> getApiSolidFireVirtualNetworkResponse(List<SfVirtualNetwork> sfVirtualNetworks, ResponseView responseView) {
+ List<ApiSolidFireVirtualNetworkResponse> sfResponse = new ArrayList<>();
+
+ if (sfVirtualNetworks != null) {
+ for (SfVirtualNetwork sfVirtualNetwork : sfVirtualNetworks) {
+ ApiSolidFireVirtualNetworkResponse response = getApiSolidFireVirtualNetworkResponse(sfVirtualNetwork, responseView);
+
+ sfResponse.add(response);
+ }
+ }
+
+ return sfResponse;
+ }
+
+ public ApiSolidFireVolumeResponse getApiSolidFireVolumeResponse(SfVolume sfVolume, ResponseView responseView) {
+ ApiSolidFireVolumeResponse sfResponse = new ApiSolidFireVolumeResponse();
+
+ sfResponse.setId(sfVolume.getId());
+ sfResponse.setUuid(sfVolume.getUuid());
+ sfResponse.setName(sfVolume.getName());
+ sfResponse.setIqn(sfVolume.getIqn());
+ sfResponse.setSize(sfVolume.getSize());
+ sfResponse.setMinIops(sfVolume.getMinIops());
+ sfResponse.setMaxIops(sfVolume.getMaxIops());
+ sfResponse.setBurstIops(sfVolume.getBurstIops());
+ sfResponse.setCreated(sfVolume.getCreated());
+
+ SfVirtualNetwork sfVirtualNetwork = _sfVirtualNetworkDao.findById(sfVolume.getSfVirtualNetworkId());
+
+ sfResponse.setAccountId(sfVirtualNetwork.getAccountId());
+
+ Account account = _accountDao.findById(sfVirtualNetwork.getAccountId());
+
+ sfResponse.setAccountUuid(account.getUuid());
+ sfResponse.setAccountName(account.getAccountName());
+
+ SfCluster sfCluster = _sfClusterDao.findById(sfVirtualNetwork.getSfClusterId());
+
+ sfResponse.setZoneId(sfCluster.getZoneId());
+
+ DataCenterVO dataCenterVO = _zoneDao.findById(sfCluster.getZoneId());
+
+ sfResponse.setZoneUuid(dataCenterVO.getUuid());
+ sfResponse.setZoneName(dataCenterVO.getName());
+
+ if (ResponseView.Full.equals(responseView)) {
+ sfResponse.setClusterName(sfCluster.getName());
+ }
+
+ sfResponse.setTargetPortal(sfVirtualNetwork.getSvip());
+ sfResponse.setVlanId(sfVirtualNetwork.getId());
+ sfResponse.setVlanUuid(sfVirtualNetwork.getUuid());
+ sfResponse.setVlanName(sfVirtualNetwork.getName());
+
+ AccountDetailVO accountDetail = _accountDetailsDao.findDetail(sfVirtualNetwork.getAccountId(), SolidFireUtil.CHAP_INITIATOR_USERNAME);
+
+ sfResponse.setChapInitiatorUsername(accountDetail.getValue());
+
+ accountDetail = _accountDetailsDao.findDetail(sfVirtualNetwork.getAccountId(), SolidFireUtil.CHAP_INITIATOR_SECRET);
+
+ sfResponse.setChapInitiatorSecret(accountDetail.getValue());
+
+ accountDetail = _accountDetailsDao.findDetail(sfVirtualNetwork.getAccountId(), SolidFireUtil.CHAP_TARGET_USERNAME);
+
+ sfResponse.setChapTargetUsername(accountDetail.getValue());
+
+ accountDetail = _accountDetailsDao.findDetail(sfVirtualNetwork.getAccountId(), SolidFireUtil.CHAP_TARGET_SECRET);
+
+ sfResponse.setChapTargetSecret(accountDetail.getValue());
+
+ sfResponse.setObjectName("sfvolume");
+
+ return sfResponse;
+ }
+
+ public List<ApiSolidFireVolumeResponse> getApiSolidFireVolumeResponse(List<SfVolume> sfVolumes, ResponseView responseView) {
+ List<ApiSolidFireVolumeResponse> sfResponse = new ArrayList<>();
+
+ if (sfVolumes != null) {
+ for (SfVolume sfVolume : sfVolumes) {
+ ApiSolidFireVolumeResponse response = getApiSolidFireVolumeResponse(sfVolume, responseView);
+
+ sfResponse.add(response);
+ }
+ }
+
+ return sfResponse;
+ }
+
+ public boolean isRootAdmin() {
+ Account account = getCallingAccount();
+
+ return isRootAdmin(account.getId());
+ }
+
+ public boolean isRootAdmin(long accountId) {
+ return _accountMgr.isRootAdmin(accountId);
+ }
+
+ public Account getCallingAccount() {
+ Account account = CallContext.current().getCallingAccount();
+
+ if (account == null) {
+ throw new CloudRuntimeException("The user's account cannot be determined.");
+ }
+
+ return account;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/49ca3b40/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SolidFireConnection.java
----------------------------------------------------------------------
diff --git a/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SolidFireConnection.java b/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SolidFireConnection.java
new file mode 100644
index 0000000..e9e011c
--- /dev/null
+++ b/plugins/api/solidfire/src/org/apache/cloudstack/util/solidfire/SolidFireConnection.java
@@ -0,0 +1,950 @@
+// 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.util.solidfire;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.cloudstack.utils.security.SSLUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.BasicClientConnectionManager;
+import org.apache.log4j.Logger;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@SuppressWarnings("deprecation")
+public class SolidFireConnection {
+ private static final Logger s_logger = Logger.getLogger(SolidFireConnection.class.getName());
+
+ private final String _managementVip;
+ private final int _managementPort = 443;
+ private final String _clusterAdminUsername;
+ private final String _clusterAdminPassword;
+
+ public SolidFireConnection(String managementVip, String clusterAdminUsername, String clusterAdminPassword) {
+ _managementVip = managementVip;
+ _clusterAdminUsername = clusterAdminUsername;
+ _clusterAdminPassword = clusterAdminPassword;
+ }
+
+ public String getClusterName() {
+ final Gson gson = new GsonBuilder().create();
+
+ ClusterInfoToGet clusterInfoToGet = new ClusterInfoToGet();
+
+ String strClusterInfoToGetJson = gson.toJson(clusterInfoToGet);
+
+ String strClusterInfoToGetResultJson = executeJsonRpc(strClusterInfoToGetJson);
+
+ ClusterInfoGetResult clusterInfoGetResult = gson.fromJson(strClusterInfoToGetResultJson, ClusterInfoGetResult.class);
+
+ verifyResult(clusterInfoGetResult.result, strClusterInfoToGetResultJson, gson);
+
+ return clusterInfoGetResult.result.clusterInfo.name;
+ }
+
+ public long createVirtualNetwork(String name, String tag, String startIp, int size, String netmask, String svip) {
+ final Gson gson = new GsonBuilder().create();
+
+ VirtualNetworkToAdd virtualNetworkToAdd = new VirtualNetworkToAdd(name, tag, startIp, size, netmask, svip);
+
+ String strVirtualNetworkToAddJson = gson.toJson(virtualNetworkToAdd);
+
+ String strVirtualNetworkToAddResultJson = executeJsonRpc(strVirtualNetworkToAddJson);
+
+ VirtualNetworkAddResult virtualNetworkAddResult = gson.fromJson(strVirtualNetworkToAddResultJson, VirtualNetworkAddResult.class);
+
+ verifyResult(virtualNetworkAddResult.result, strVirtualNetworkToAddResultJson, gson);
+
+ return virtualNetworkAddResult.result.virtualNetworkID;
+ }
+
+ public void modifyVirtualNetwork(long id, String name, String startIp, int size, String netmask) {
+ final Gson gson = new GsonBuilder().create();
+
+ VirtualNetworkToModify virtualNetworkToModify = new VirtualNetworkToModify(id, name, startIp, size, netmask);
+
+ String strVirtualNetworkToModifyJson = gson.toJson(virtualNetworkToModify);
+
+ String strVirtualNetworkToModifyResultJson = executeJsonRpc(strVirtualNetworkToModifyJson);
+
+ JsonError jsonError = gson.fromJson(strVirtualNetworkToModifyResultJson, JsonError.class);
+
+ if (jsonError.error != null) {
+ throw new IllegalStateException(jsonError.error.message);
+ }
+ }
+
+ public void deleteVirtualNetwork(long id) {
+ final Gson gson = new GsonBuilder().create();
+
+ VirtualNetworkToDelete virtualNetworkToDelete = new VirtualNetworkToDelete(id);
+
+ String strVolumeToDeleteJson = gson.toJson(virtualNetworkToDelete);
+
+ String strVirtualNetworkToDeleteResultJson = executeJsonRpc(strVolumeToDeleteJson);
+
+ JsonError jsonError = gson.fromJson(strVirtualNetworkToDeleteResultJson, JsonError.class);
+
+ if (jsonError.error != null) {
+ throw new IllegalStateException(jsonError.error.message);
+ }
+ }
+
+ public SolidFireVolume getVolume(long lVolumeId) {
+ final Gson gson = new GsonBuilder().create();
+
+ VolumeToGet volumeToGet = new VolumeToGet(lVolumeId);
+
+ String strVolumeToGetJson = gson.toJson(volumeToGet);
+
+ String strVolumeGetResultJson = executeJsonRpc(strVolumeToGetJson);
+
+ VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class);
+
+ verifyResult(volumeGetResult.result, strVolumeGetResultJson, gson);
+
+ String strVolumeName = getVolumeName(volumeGetResult, lVolumeId);
+ String strVolumeIqn = getVolumeIqn(volumeGetResult, lVolumeId);
+ long lAccountId = getVolumeAccountId(volumeGetResult, lVolumeId);
+ String strVolumeStatus = getVolumeStatus(volumeGetResult, lVolumeId);
+ long lTotalSize = getVolumeTotalSize(volumeGetResult, lVolumeId);
+
+ return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize);
+ }
+
+ public long createVolume(String name, long accountId, long totalSizeInGBs, long minIops, long maxIops, long burstIops) {
+ final Gson gson = new GsonBuilder().create();
+
+ long totalSizeInBytes = convertGBsToBytes(totalSizeInGBs);
+
+ VolumeToCreate volumeToCreate = new VolumeToCreate(name, accountId, totalSizeInBytes, true, minIops, maxIops, burstIops);
+
+ String strVolumeToCreateJson = gson.toJson(volumeToCreate);
+
+ String strVolumeCreateResultJson = executeJsonRpc(strVolumeToCreateJson);
+
+ VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class);
+
+ verifyResult(volumeCreateResult.result, strVolumeCreateResultJson, gson);
+
+ return volumeCreateResult.result.volumeID;
+ }
+
+ public void modifyVolume(long volumeId, long totalSizeInGBs, long minIops, long maxIops, long burstIops)
+ {
+ final Gson gson = new GsonBuilder().create();
+
+ long totalSizeInBytes = convertGBsToBytes(totalSizeInGBs);
+
+ VolumeToModify volumeToModify = new VolumeToModify(volumeId, totalSizeInBytes, minIops, maxIops, burstIops);
+
+ String strVolumeToModifyJson = gson.toJson(volumeToModify);
+
+ String strVolumeModifyResultJson = executeJsonRpc(strVolumeToModifyJson);
+
+ JsonError jsonError = gson.fromJson(strVolumeModifyResultJson, JsonError.class);
+
+ if (jsonError.error != null) {
+ throw new IllegalStateException(jsonError.error.message);
+ }
+ }
+
+ public void deleteVolume(long id)
+ {
+ final Gson gson = new GsonBuilder().create();
+
+ VolumeToDelete volumeToDelete = new VolumeToDelete(id);
+
+ String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
+
+ String strVolumeToDeleteResultJson = executeJsonRpc(strVolumeToDeleteJson);
+
+ JsonError jsonError = gson.fromJson(strVolumeToDeleteResultJson, JsonError.class);
+
+ if (jsonError.error != null) {
+ throw new IllegalStateException(jsonError.error.message);
+ }
+ }
+
+ public long createSolidFireAccount(String strAccountName)
+ {
+ final Gson gson = new GsonBuilder().create();
+
+ AccountToAdd accountToAdd = new AccountToAdd(strAccountName);
+
+ String strAccountAddJson = gson.toJson(accountToAdd);
+
+ String strAccountAddResultJson = executeJsonRpc(strAccountAddJson);
+
+ AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class);
+
+ verifyResult(accountAddResult.result, strAccountAddResultJson, gson);
+
+ return accountAddResult.result.accountID;
+ }
+
+ public SolidFireAccount getSolidFireAccount(String sfAccountName) {
+ try {
+ return getSolidFireAccountByName(sfAccountName);
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+ public SolidFireAccount getSolidFireAccountById(long lSfAccountId)
+ {
+ final Gson gson = new GsonBuilder().create();
+
+ AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId);
+
+ String strAccountToGetByIdJson = gson.toJson(accountToGetById);
+
+ String strAccountGetByIdResultJson = executeJsonRpc(strAccountToGetByIdJson);
+
+ AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class);
+
+ verifyResult(accountGetByIdResult.result, strAccountGetByIdResultJson, gson);
+
+ String strSfAccountName = accountGetByIdResult.result.account.username;
+ String strSfAccountInitiatorSecret = accountGetByIdResult.result.account.initiatorSecret;
+ String strSfAccountTargetSecret = accountGetByIdResult.result.account.targetSecret;
+
+ return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
+ }
+
+ public SolidFireAccount getSolidFireAccountByName(String strSfAccountName)
+ {
+ final Gson gson = new GsonBuilder().create();
+
+ AccountToGetByName accountToGetByName = new AccountToGetByName(strSfAccountName);
+
+ String strAccountToGetByNameJson = gson.toJson(accountToGetByName);
+
+ String strAccountGetByNameResultJson = executeJsonRpc(strAccountToGetByNameJson);
+
+ AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class);
+
+ verifyResult(accountGetByNameResult.result, strAccountGetByNameResultJson, gson);
+
+ long lSfAccountId = accountGetByNameResult.result.account.accountID;
+ String strSfAccountInitiatorSecret = accountGetByNameResult.result.account.initiatorSecret;
+ String strSfAccountTargetSecret = accountGetByNameResult.result.account.targetSecret;
+
+ return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
+ }
+
+ private String executeJsonRpc(String strJsonToExecute) {
+ DefaultHttpClient httpClient = null;
+ StringBuilder sb = new StringBuilder();
+
+ try {
+ StringEntity input = new StringEntity(strJsonToExecute);
+
+ input.setContentType("application/json");
+
+ httpClient = getHttpClient(_managementPort);
+
+ URI uri = new URI("https://" + _managementVip + ":" + _managementPort + "/json-rpc/7.0");
+ AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
+ UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(_clusterAdminUsername, _clusterAdminPassword);
+
+ httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
+
+ HttpPost postRequest = new HttpPost(uri);
+
+ postRequest.setEntity(input);
+
+ HttpResponse response = httpClient.execute(postRequest);
+
+ if (!isSuccess(response.getStatusLine().getStatusCode())) {
+ throw new CloudRuntimeException("Failed on JSON-RPC API call. HTTP error code = " + response.getStatusLine().getStatusCode());
+ }
+
+ try(BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));) {
+ String strOutput;
+ while ((strOutput = br.readLine()) != null) {
+ sb.append(strOutput);
+ }
+ }catch (IOException ex) {
+ throw new CloudRuntimeException(ex.getMessage());
+ }
+ } catch (Throwable t) {
+ s_logger.error(t.getMessage());
+
+ throw new CloudRuntimeException(t.getMessage());
+ } finally {
+ if (httpClient != null) {
+ try {
+ httpClient.getConnectionManager().shutdown();
+ } catch (Exception t) {
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private static DefaultHttpClient getHttpClient(int iPort) {
+ DefaultHttpClient client = null;
+
+ try {
+ SSLContext sslContext = SSLUtils.getSSLContext();
+
+ X509TrustManager tm = new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ };
+
+ sslContext.init(null, new TrustManager[] { tm }, new SecureRandom());
+
+ SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ SchemeRegistry registry = new SchemeRegistry();
+
+ registry.register(new Scheme("https", iPort, socketFactory));
+
+ BasicClientConnectionManager mgr = new BasicClientConnectionManager(registry);
+ client = new DefaultHttpClient();
+
+ return new DefaultHttpClient(mgr, client.getParams());
+ } catch (NoSuchAlgorithmException ex) {
+ s_logger.error(ex.getMessage());
+
+ throw new CloudRuntimeException(ex.getMessage());
+ } catch (KeyManagementException ex) {
+ s_logger.error(ex.getMessage());
+
+ throw new CloudRuntimeException(ex.getMessage());
+ }
+ finally {
+ if (client != null) {
+ try {
+ client.close();
+ }
+ catch (Throwable t) {
+ s_logger.error(t.getMessage());
+
+ throw t;
+ }
+ }
+ }
+ }
+
+ private static boolean isSuccess(int iCode) {
+ return iCode >= 200 && iCode < 300;
+ }
+
+ @SuppressWarnings("unused")
+ private static final class ClusterInfoToGet {
+ private final String method = "GetClusterInfo";
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VirtualNetworkToAdd {
+ private final String method = "AddVirtualNetwork";
+ private final VirtualNetworkToAddParams params;
+
+ public VirtualNetworkToAdd(String name, String tag, String startIp, int size, String netmask, String svip) {
+ params = new VirtualNetworkToAddParams(name, tag, startIp, size, netmask, svip);
+ }
+
+ private static final class VirtualNetworkToAddParams {
+ private final String name;
+ private final String virtualNetworkTag;
+ private final AddressBlock[] addressBlocks = new AddressBlock[1];
+ private final String netmask;
+ private final String svip;
+
+ public VirtualNetworkToAddParams(String name, String tag, String startIp, int size, String netmask, String svip) {
+ this.name = name;
+ this.virtualNetworkTag = tag;
+
+ this.addressBlocks[0] = new AddressBlock(startIp, size);
+
+ this.netmask = netmask;
+ this.svip = svip;
+ }
+
+ private static final class AddressBlock {
+ private final String start;
+ private final int size;
+
+ public AddressBlock(String start, int size) {
+ this.start = start;
+ this.size = size;
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VirtualNetworkToModify {
+ private final String method = "ModifyVirtualNetwork";
+ private final VirtualNetworkToModifyParams params;
+
+ public VirtualNetworkToModify(long id, String name, String startIp, int size, String netmask) {
+ params = new VirtualNetworkToModifyParams(id, name, startIp, size, netmask);
+ }
+
+ private static final class VirtualNetworkToModifyParams {
+ private final long virtualNetworkID;
+ private final String name;
+ private final AddressBlock[] addressBlocks = new AddressBlock[1];
+ private final String netmask;
+
+ public VirtualNetworkToModifyParams(long id, String name, String startIp, int size, String netmask) {
+ this.virtualNetworkID = id;
+ this.name = name;
+
+ this.addressBlocks[0] = new AddressBlock(startIp, size);
+
+ this.netmask = netmask;
+ }
+
+ private static final class AddressBlock {
+ private final String start;
+ private final int size;
+
+ public AddressBlock(String start, int size) {
+ this.start = start;
+ this.size = size;
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VirtualNetworkToDelete
+ {
+ private final String method = "RemoveVirtualNetwork";
+ private final VirtualNetworkToDeleteParams params;
+
+ private VirtualNetworkToDelete(long id) {
+ params = new VirtualNetworkToDeleteParams(id);
+ }
+
+ private static final class VirtualNetworkToDeleteParams {
+ private final long virtualNetworkID;
+
+ private VirtualNetworkToDeleteParams(long id) {
+ virtualNetworkID = id;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VolumeToGet
+ {
+ private final String method = "ListActiveVolumes";
+ private final VolumeToGetParams params;
+
+ private VolumeToGet(final long lVolumeId)
+ {
+ params = new VolumeToGetParams(lVolumeId);
+ }
+
+ private static final class VolumeToGetParams
+ {
+ private final long startVolumeID;
+ private final long limit = 1;
+
+ private VolumeToGetParams(final long lVolumeId)
+ {
+ startVolumeID = lVolumeId;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VolumeToCreate {
+ private final String method = "CreateVolume";
+ private final VolumeToCreateParams params;
+
+ private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
+ final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+ params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, lMinIOPS, lMaxIOPS, lBurstIOPS);
+ }
+
+ private static final class VolumeToCreateParams {
+ private final String name;
+ private final long accountID;
+ private final long totalSize;
+ private final boolean enable512e;
+ private final VolumeToCreateParamsQoS qos;
+
+ private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
+ final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+ name = strVolumeName;
+ accountID = lAccountId;
+ totalSize = lTotalSize;
+ enable512e = bEnable512e;
+
+ qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
+ }
+
+ private static final class VolumeToCreateParamsQoS {
+ private final long minIOPS;
+ private final long maxIOPS;
+ private final long burstIOPS;
+
+ private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+ minIOPS = lMinIOPS;
+ maxIOPS = lMaxIOPS;
+ burstIOPS = lBurstIOPS;
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VolumeToModify
+ {
+ private final String method = "ModifyVolume";
+ private final VolumeToModifyParams params;
+
+ private VolumeToModify(long id, long totalSize, long minIOPS, long maxIOPS, long burstIOPS)
+ {
+ params = new VolumeToModifyParams(id, totalSize, minIOPS, maxIOPS, burstIOPS);
+ }
+
+ private static final class VolumeToModifyParams
+ {
+ private final long volumeID;
+ private final long totalSize;
+ private final VolumeToModifyParamsQoS qos;
+
+ private VolumeToModifyParams(long id, long totalSize, long minIOPS, long maxIOPS, long burstIOPS)
+ {
+ this.volumeID = id;
+ this.totalSize = totalSize;
+
+ this.qos = new VolumeToModifyParamsQoS(minIOPS, maxIOPS, burstIOPS);
+ }
+ }
+
+ private static final class VolumeToModifyParamsQoS {
+ private final long minIOPS;
+ private final long maxIOPS;
+ private final long burstIOPS;
+
+ private VolumeToModifyParamsQoS(long minIOPS, long maxIOPS, long burstIOPS) {
+ this.minIOPS = minIOPS;
+ this.maxIOPS = maxIOPS;
+ this.burstIOPS = burstIOPS;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class VolumeToDelete
+ {
+ private final String method = "DeleteVolume";
+ private final VolumeToDeleteParams params;
+
+ private VolumeToDelete(final long lVolumeId) {
+ params = new VolumeToDeleteParams(lVolumeId);
+ }
+
+ private static final class VolumeToDeleteParams {
+ private long volumeID;
+
+ private VolumeToDeleteParams(final long lVolumeId) {
+ volumeID = lVolumeId;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class AccountToAdd
+ {
+ private final String method = "AddAccount";
+ private final AccountToAddParams params;
+
+ private AccountToAdd(final String strAccountName)
+ {
+ params = new AccountToAddParams(strAccountName);
+ }
+
+ private static final class AccountToAddParams
+ {
+ private final String username;
+
+ private AccountToAddParams(final String strAccountName)
+ {
+ username = strAccountName;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class AccountToGetById
+ {
+ private final String method = "GetAccountByID";
+ private final AccountToGetByIdParams params;
+
+ private AccountToGetById(final long lAccountId)
+ {
+ params = new AccountToGetByIdParams(lAccountId);
+ }
+
+ private static final class AccountToGetByIdParams
+ {
+ private final long accountID;
+
+ private AccountToGetByIdParams(final long lAccountId)
+ {
+ accountID = lAccountId;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static final class AccountToGetByName
+ {
+ private final String method = "GetAccountByName";
+ private final AccountToGetByNameParams params;
+
+ private AccountToGetByName(final String strUsername)
+ {
+ params = new AccountToGetByNameParams(strUsername);
+ }
+
+ private static final class AccountToGetByNameParams
+ {
+ private final String username;
+
+ private AccountToGetByNameParams(final String strUsername)
+ {
+ username = strUsername;
+ }
+ }
+ }
+
+ private static final class ClusterInfoGetResult
+ {
+ private Result result;
+
+ private static final class Result
+ {
+ private ClusterInfo clusterInfo;
+
+ private static final class ClusterInfo
+ {
+ private String name;
+ }
+ }
+ }
+
+ private static final class VirtualNetworkAddResult
+ {
+ private Result result;
+
+ private static final class Result
+ {
+ private long virtualNetworkID;
+ }
+ }
+
+ private static final class VolumeGetResult {
+ private Result result;
+
+ private static final class Result {
+ private Volume[] volumes;
+
+ private static final class Volume {
+ private long volumeID;
+ private String name;
+ private String iqn;
+ private long accountID;
+ private String status;
+ private long totalSize;
+ }
+ }
+ }
+
+ private static final class VolumeCreateResult {
+ private Result result;
+
+ private static final class Result {
+ private long volumeID;
+ }
+ }
+
+ private static final class AccountAddResult {
+ private Result result;
+
+ private static final class Result {
+ private long accountID;
+ }
+ }
+
+ private static final class AccountGetResult {
+ private Result result;
+
+ private static final class Result {
+ private Account account;
+
+ private static final class Account {
+ private long accountID;
+ private String username;
+ private String initiatorSecret;
+ private String targetSecret;
+ }
+ }
+ }
+
+ private static final class JsonError
+ {
+ private Error error;
+
+ private static final class Error {
+ private String message;
+ }
+ }
+
+ private static void verifyResult(Object result, String strJson, Gson gson) throws IllegalStateException {
+ if (result != null) {
+ return;
+ }
+
+ JsonError jsonError = gson.fromJson(strJson, JsonError.class);
+
+ if (jsonError != null) {
+ throw new IllegalStateException(jsonError.error.message);
+ }
+
+ throw new IllegalStateException("Problem with the following JSON: " + strJson);
+ }
+
+ private static final String ACTIVE = "active";
+
+ public static class SolidFireVolume {
+ private final long _id;
+ private final String _name;
+ private final String _iqn;
+ private final long _accountId;
+ private final String _status;
+ private final long _totalSize;
+
+ public SolidFireVolume(long id, String name, String iqn,
+ long accountId, String status, long totalSize)
+ {
+ _id = id;
+ _name = name;
+ _iqn = iqn;
+ _accountId = accountId;
+ _status = status;
+ _totalSize = totalSize;
+ }
+
+ public long getId() {
+ return _id;
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ public String getIqn() {
+ return _iqn;
+ }
+
+ public long getAccountId() {
+ return _accountId;
+ }
+
+ public boolean isActive() {
+ return ACTIVE.equalsIgnoreCase(_status);
+ }
+
+ public long getTotalSize() {
+ return _totalSize;
+ }
+
+ @Override
+ public int hashCode() {
+ return _iqn.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return _name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (!obj.getClass().equals(SolidFireVolume.class)) {
+ return false;
+ }
+
+ SolidFireVolume sfv = (SolidFireVolume)obj;
+
+ if (_id == sfv._id && _name.equals(sfv._name) &&
+ _iqn.equals(sfv._iqn) && _accountId == sfv._accountId &&
+ isActive() == sfv.isActive() && getTotalSize() == sfv.getTotalSize()) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public static class SolidFireAccount
+ {
+ private final long _id;
+ private final String _name;
+ private final String _initiatorSecret;
+ private final String _targetSecret;
+
+ public SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret) {
+ _id = id;
+ _name = name;
+ _initiatorSecret = initiatorSecret;
+ _targetSecret = targetSecret;
+ }
+
+ public long getId() {
+ return _id;
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ public String getInitiatorSecret() {
+ return _initiatorSecret;
+ }
+
+ public String getTargetSecret() {
+ return _targetSecret;
+ }
+
+ @Override
+ public int hashCode() {
+ return (_id + _name).hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return _name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (!obj.getClass().equals(SolidFireAccount.class)) {
+ return false;
+ }
+
+ SolidFireAccount sfa = (SolidFireAccount)obj;
+
+ if (_id == sfa._id && _name.equals(sfa._name) &&
+ _initiatorSecret.equals(sfa._initiatorSecret) &&
+ _targetSecret.equals(sfa._targetSecret)) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private static long convertGBsToBytes(long gbs) {
+ return gbs * 1024 * 1024 * 1024;
+ }
+
+ private static String getVolumeName(VolumeGetResult volumeGetResult, long lVolumeId) {
+ if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
+ return volumeGetResult.result.volumes[0].name;
+ }
+
+ throw new CloudRuntimeException("Could not determine the name of the volume for volume ID of " + lVolumeId + ".");
+ }
+
+ private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolumeId) {
+ if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
+ return volumeGetResult.result.volumes[0].iqn;
+ }
+
+ throw new CloudRuntimeException("Could not determine the IQN of the volume for volume ID of " + lVolumeId + ".");
+ }
+
+ private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVolumeId) {
+ if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
+ return volumeGetResult.result.volumes[0].accountID;
+ }
+
+ throw new CloudRuntimeException("Could not determine the account ID of the volume for volume ID of " + lVolumeId + ".");
+ }
+
+ private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVolumeId) {
+ if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
+ return volumeGetResult.result.volumes[0].status;
+ }
+
+ throw new CloudRuntimeException("Could not determine the status of the volume for volume ID of " + lVolumeId + ".");
+ }
+
+ private static long getVolumeTotalSize(VolumeGetResult volumeGetResult, long lVolumeId)
+ {
+ if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
+ volumeGetResult.result.volumes[0].volumeID == lVolumeId)
+ {
+ return volumeGetResult.result.volumes[0].totalSize;
+ }
+
+ throw new CloudRuntimeException("Could not determine the total size of the volume for volume ID of " + lVolumeId + ".");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/49ca3b40/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 1706fe8..cf74dc4 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -38,6 +38,7 @@
</build>
<modules>
<module>api/rate-limit</module>
+ <module>api/solidfire</module>
<module>api/solidfire-intg-test</module>
<module>api/discovery</module>
<module>acl/static-role-based</module>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/49ca3b40/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
index dcbabe6..6c6c41d 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
@@ -259,8 +259,10 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve();
if (hypervisorSnapshotReserve != null) {
- if (hypervisorSnapshotReserve < 50) {
- hypervisorSnapshotReserve = 50;
+ int minimumHypervisorSnapshotReserve = 10;
+
+ if (hypervisorSnapshotReserve < minimumHypervisorSnapshotReserve) {
+ hypervisorSnapshotReserve = minimumHypervisorSnapshotReserve;
}
volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f);