diff --git a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java index fcccd56dd6e..f2735b819a9 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java @@ -56,5 +56,5 @@ public interface CapacityDao extends GenericDao { float findClusterConsumption(Long clusterId, short capacityType, long computeRequested); - List orderHostsByFreeCapacity(Long clusterId, short capacityType); + List orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityType); } diff --git a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java index 5b14bd4af3b..72d5b070761 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -903,20 +903,28 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public List orderHostsByFreeCapacity(Long clusterId, short capacityTypeForOrdering){ + public List orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityTypeForOrdering){ TransactionLegacy txn = TransactionLegacy.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); StringBuilder sql = new StringBuilder(ORDER_HOSTS_BY_FREE_CAPACITY_PART1); - if(clusterId != null) { - sql.append("AND cluster_id = ?"); - } - sql.append(ORDER_HOSTS_BY_FREE_CAPACITY_PART2); + if (zoneId != null) { + sql.append(" AND data_center_id = ?"); + } + if (clusterId != null) { + sql.append(" AND cluster_id = ?"); + } + sql.append(ORDER_HOSTS_BY_FREE_CAPACITY_PART2); try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setShort(1, capacityTypeForOrdering); - if(clusterId != null) { - pstmt.setLong(2, clusterId); + int index = 2; + if (zoneId != null) { + pstmt.setLong(index, zoneId); + index ++; + } + if (clusterId != null) { + pstmt.setLong(index, clusterId); } ResultSet rs = pstmt.executeQuery(); diff --git a/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml b/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml index 944196da1fc..b8a227476ac 100644 --- a/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml +++ b/engine/storage/integration-test/src/test/resources/fakeDriverTestContext.xml @@ -49,7 +49,7 @@ - + diff --git a/engine/storage/integration-test/src/test/resources/storageContext.xml b/engine/storage/integration-test/src/test/resources/storageContext.xml index abf08767d9d..f65e2accde9 100644 --- a/engine/storage/integration-test/src/test/resources/storageContext.xml +++ b/engine/storage/integration-test/src/test/resources/storageContext.xml @@ -50,7 +50,7 @@ - + diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java similarity index 74% rename from engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java rename to engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java index 3ab2129bc0b..c0a2395aa34 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java @@ -21,7 +21,6 @@ import java.util.List; import javax.inject.Inject; import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; @@ -34,7 +33,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJob; -import org.apache.cloudstack.framework.jobs.dao.SyncQueueItemDao; import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; @@ -71,9 +69,8 @@ import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; -@Component -public class XenserverSnapshotStrategy extends SnapshotStrategyBase { - private static final Logger s_logger = Logger.getLogger(XenserverSnapshotStrategy.class); +public class DefaultSnapshotStrategy extends SnapshotStrategyBase { + private static final Logger s_logger = Logger.getLogger(DefaultSnapshotStrategy.class); @Inject SnapshotService snapshotSvr; @@ -90,12 +87,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { @Inject SnapshotDataFactory snapshotDataFactory; @Inject - private SnapshotDao _snapshotDao; - @Inject private SnapshotDetailsDao _snapshotDetailsDao; @Inject - private SyncQueueItemDao _syncQueueItemDao; - @Inject VolumeDetailsDao _volumeDetailsDaoImpl; @Override @@ -264,68 +257,147 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { return true; } - if (!Snapshot.State.BackedUp.equals(snapshotVO.getState()) && !Snapshot.State.Error.equals(snapshotVO.getState()) && + if (!Snapshot.State.BackedUp.equals(snapshotVO.getState()) && !Snapshot.State.Destroying.equals(snapshotVO.getState())) { throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is in " + snapshotVO.getState() + " Status"); } - // first mark the snapshot as destroyed, so that ui can't see it, but we - // may not destroy the snapshot on the storage, as other snapshots may - // depend on it. + Boolean deletedOnSecondary = deleteOnSecondaryIfNeeded(snapshotId); + boolean deletedOnPrimary = deleteOnPrimaryIfNeeded(snapshotId); + + if (deletedOnPrimary) { + s_logger.debug(String.format("Successfully deleted snapshot (id: %d) on primary storage.", snapshotId)); + } else { + s_logger.debug(String.format("The snapshot (id: %d) could not be found/deleted on primary storage.", snapshotId)); + } + if (null != deletedOnSecondary && deletedOnSecondary) { + s_logger.debug(String.format("Successfully deleted snapshot (id: %d) on secondary storage.", snapshotId)); + } + return (deletedOnSecondary != null) && deletedOnSecondary || deletedOnPrimary; + } + + private boolean deleteOnPrimaryIfNeeded(Long snapshotId) { + SnapshotVO snapshotVO; + boolean deletedOnPrimary = false; + snapshotVO = snapshotDao.findById(snapshotId); + SnapshotInfo snapshotOnPrimaryInfo = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + if (snapshotVO != null && snapshotVO.getState() == Snapshot.State.Destroyed) { + deletedOnPrimary = deleteSnapshotOnPrimary(snapshotId, snapshotOnPrimaryInfo); + } else { + // Here we handle snapshots which are to be deleted but are not marked as destroyed yet. + // This may occur for instance when they are created only on primary because + // snapshot.backup.to.secondary was set to false. + if (snapshotOnPrimaryInfo == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Snapshot (id: %d) not found on primary storage, skipping snapshot deletion on primary and marking it destroyed", snapshotId)); + } + snapshotVO.setState(Snapshot.State.Destroyed); + snapshotDao.update(snapshotId, snapshotVO); + deletedOnPrimary = true; + } else { + SnapshotObject obj = (SnapshotObject) snapshotOnPrimaryInfo; + try { + obj.processEvent(Snapshot.Event.DestroyRequested); + deletedOnPrimary = deleteSnapshotOnPrimary(snapshotId, snapshotOnPrimaryInfo); + if (!deletedOnPrimary) { + obj.processEvent(Snapshot.Event.OperationFailed); + } else { + obj.processEvent(Snapshot.Event.OperationSucceeded); + } + } catch (NoTransitionException e) { + s_logger.debug("Failed to set the state to destroying: ", e); + deletedOnPrimary = false; + } + } + } + return deletedOnPrimary; + } + + private Boolean deleteOnSecondaryIfNeeded(Long snapshotId) { + Boolean deletedOnSecondary = null; SnapshotInfo snapshotOnImage = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Image); if (snapshotOnImage == null) { - s_logger.debug("Can't find snapshot on backup storage, delete it in db"); - snapshotDao.remove(snapshotId); - return true; - } - - SnapshotObject obj = (SnapshotObject)snapshotOnImage; - try { - obj.processEvent(Snapshot.Event.DestroyRequested); - List volumesFromSnapshot; - volumesFromSnapshot = _volumeDetailsDaoImpl.findDetails("SNAPSHOT_ID", String.valueOf(snapshotId), null); - - if (volumesFromSnapshot.size() > 0) { - try { - obj.processEvent(Snapshot.Event.OperationFailed); - } catch (NoTransitionException e1) { - s_logger.debug("Failed to change snapshot state: " + e1.toString()); + s_logger.debug(String.format("Can't find snapshot [snapshot id: %d] on secondary storage", snapshotId)); + } else { + SnapshotObject obj = (SnapshotObject)snapshotOnImage; + try { + deletedOnSecondary = deleteSnapshotOnSecondaryStorage(snapshotId, snapshotOnImage, obj); + if (!deletedOnSecondary) { + s_logger.debug( + String.format("Failed to find/delete snapshot (id: %d) on secondary storage. Still necessary to check and delete snapshot on primary storage.", + snapshotId)); + } else { + s_logger.debug(String.format("Snapshot (id: %d) has been deleted on secondary storage.", snapshotId)); } - throw new InvalidParameterValueException("Unable to perform delete operation, Snapshot with id: " + snapshotId + " is in use "); + } catch (NoTransitionException e) { + s_logger.debug("Failed to set the state to destroying: ", e); +// deletedOnSecondary remain null } - } catch (NoTransitionException e) { - s_logger.debug("Failed to set the state to destroying: ", e); - return false; } + return deletedOnSecondary; + } - try { - boolean result = deleteSnapshotChain(snapshotOnImage); - obj.processEvent(Snapshot.Event.OperationSucceeded); - if (result) { - //snapshot is deleted on backup storage, need to delete it on primary storage - SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); - if (snapshotOnPrimary != null) { - SnapshotInfo snapshotOnPrimaryInfo = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); - long volumeId = snapshotOnPrimary.getVolumeId(); - VolumeVO volumeVO = volumeDao.findById(volumeId); - if (((PrimaryDataStoreImpl)snapshotOnPrimaryInfo.getDataStore()).getPoolType() == StoragePoolType.RBD && volumeVO != null) { - snapshotSvr.deleteSnapshot(snapshotOnPrimaryInfo); - } - snapshotOnPrimary.setState(State.Destroyed); - snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary); - } - } - } catch (Exception e) { - s_logger.debug("Failed to delete snapshot: ", e); + /** + * Deletes the snapshot on secondary storage. + * It can return false when the snapshot was stored on primary storage and not backed up on secondary; therefore, the snapshot should also be deleted on primary storage even when this method returns false. + */ + private boolean deleteSnapshotOnSecondaryStorage(Long snapshotId, SnapshotInfo snapshotOnImage, SnapshotObject obj) throws NoTransitionException { + obj.processEvent(Snapshot.Event.DestroyRequested); + List volumesFromSnapshot; + volumesFromSnapshot = _volumeDetailsDaoImpl.findDetails("SNAPSHOT_ID", String.valueOf(snapshotId), null); + + if (volumesFromSnapshot.size() > 0) { try { obj.processEvent(Snapshot.Event.OperationFailed); } catch (NoTransitionException e1) { - s_logger.debug("Failed to change snapshot state: " + e.toString()); + s_logger.debug("Failed to change snapshot state: " + e1.toString()); } - return false; + throw new InvalidParameterValueException("Unable to perform delete operation, Snapshot with id: " + snapshotId + " is in use "); } - return true; + boolean result = deleteSnapshotChain(snapshotOnImage); + obj.processEvent(Snapshot.Event.OperationSucceeded); + return result; + } + + /** + * Deletes the snapshot on primary storage. It returns true when the snapshot was not found on primary storage;
+ * In case of failure while deleting the snapshot, it will throw one of the following exceptions: CloudRuntimeException, InterruptedException, or ExecutionException.
+ */ + private boolean deleteSnapshotOnPrimary(Long snapshotId, SnapshotInfo snapshotOnPrimaryInfo) { + SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); + if (isSnapshotOnPrimaryStorage(snapshotId)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Snapshot reference is found on primary storage for snapshot id: %d, performing snapshot deletion on primary", snapshotId)); + } + if (snapshotSvr.deleteSnapshot(snapshotOnPrimaryInfo)) { + snapshotOnPrimary.setState(State.Destroyed); + snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary); + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Successfully deleted snapshot id: %d on primary storage", snapshotId)); + } + return true; + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Snapshot reference is not found on primary storage for snapshot id: %d, skipping snapshot deletion on primary", snapshotId)); + } + return true; + } + return false; + } + + /** + * Returns true if the snapshot volume is on primary storage. + */ + private boolean isSnapshotOnPrimaryStorage(long snapshotId) { + SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); + if (snapshotOnPrimary != null) { + long volumeId = snapshotOnPrimary.getVolumeId(); + VolumeVO volumeVO = volumeDao.findById(volumeId); + return volumeVO != null && volumeVO.getRemoved() == null; + } + return false; } @Override diff --git a/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml b/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml index b295398144c..2bfb3c368a5 100644 --- a/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml +++ b/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/storage/spring-engine-storage-snapshot-storage-context.xml @@ -27,8 +27,8 @@ http://www.springframework.org/schema/context/spring-context.xsd" > - + diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index ef5e21d8899..727d10af130 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -94,6 +94,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement protected List reorderPoolsByCapacity(DeploymentPlan plan, List pools) { + Long zoneId = plan.getDataCenterId(); Long clusterId = plan.getClusterId(); short capacityType; if(pools != null && pools.size() != 0){ @@ -102,7 +103,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement return null; } - List poolIdsByCapacity = capacityDao.orderHostsByFreeCapacity(clusterId, capacityType); + List poolIdsByCapacity = capacityDao.orderHostsByFreeCapacity(zoneId, clusterId, capacityType); if (s_logger.isDebugEnabled()) { s_logger.debug("List of pools in descending order of free capacity: "+ poolIdsByCapacity); } diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index aa077f33fef..301704a75a6 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -29,6 +29,8 @@ import org.springframework.stereotype.Component; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import com.cloud.capacity.Capacity; +import com.cloud.capacity.dao.CapacityDao; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -43,6 +45,8 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { private static final Logger LOGGER = Logger.getLogger(ZoneWideStoragePoolAllocator.class); @Inject private DataStoreManager dataStoreMgr; + @Inject + private CapacityDao capacityDao; @Override @@ -110,6 +114,40 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { return !ScopeType.ZONE.equals(storagePoolVO.getScope()) || !storagePoolVO.isManaged(); } + + @Override + protected List reorderPoolsByCapacity(DeploymentPlan plan, + List pools) { + Long zoneId = plan.getDataCenterId(); + short capacityType; + if(pools != null && pools.size() != 0){ + capacityType = pools.get(0).getPoolType().isShared() ? Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED : Capacity.CAPACITY_TYPE_LOCAL_STORAGE; + } else{ + return null; + } + + List poolIdsByCapacity = capacityDao.orderHostsByFreeCapacity(zoneId, null, capacityType); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("List of zone-wide storage pools in descending order of free capacity: "+ poolIdsByCapacity); + } + + //now filter the given list of Pools by this ordered list + Map poolMap = new HashMap<>(); + for (StoragePool pool : pools) { + poolMap.put(pool.getId(), pool); + } + List matchingPoolIds = new ArrayList<>(poolMap.keySet()); + + poolIdsByCapacity.retainAll(matchingPoolIds); + + List reorderedPools = new ArrayList<>(); + for(Long id: poolIdsByCapacity){ + reorderedPools.add(poolMap.get(id)); + } + + return reorderedPools; + } + @Override protected List reorderPoolsByNumberOfVolumes(DeploymentPlan plan, List pools, Account account) { if (account == null) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index dab80c9dc19..9e1ff7172ee 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -128,6 +128,14 @@ public class KVMStorageProcessor implements StorageProcessor { private String _manageSnapshotPath; private int _cmdsTimeout; + private static final String MANAGE_SNAPSTHOT_CREATE_OPTION = "-c"; + private static final String MANAGE_SNAPSTHOT_DESTROY_OPTION = "-d"; + private static final String NAME_OPTION = "-n"; + private static final String CEPH_MON_HOST = "mon_host"; + private static final String CEPH_AUTH_KEY = "key"; + private static final String CEPH_CLIENT_MOUNT_TIMEOUT = "client_mount_timeout"; + private static final String CEPH_DEFAULT_MOUNT_TIMEOUT = "30"; + public KVMStorageProcessor(final KVMStoragePoolManager storagePoolMgr, final LibvirtComputingResource resource) { this.storagePoolMgr = storagePoolMgr; this.resource = resource; @@ -563,7 +571,7 @@ public class KVMStorageProcessor implements StorageProcessor { final Script command = new Script(_createTmplPath, wait, s_logger); command.add("-f", disk.getPath()); command.add("-t", tmpltPath); - command.add("-n", templateName + ".qcow2"); + command.add(NAME_OPTION, templateName + ".qcow2"); final String result = command.execute(); @@ -949,7 +957,7 @@ public class KVMStorageProcessor implements StorageProcessor { } else { final Script command = new Script(_manageSnapshotPath, cmd.getWaitInMillSeconds(), s_logger); command.add("-b", snapshotDisk.getPath()); - command.add("-n", snapshotName); + command.add(NAME_OPTION, snapshotName); command.add("-p", snapshotDestPath); if (isCreatedFromVmSnapshot) { descName = UUID.randomUUID().toString(); @@ -1010,14 +1018,7 @@ public class KVMStorageProcessor implements StorageProcessor { } } else { if (primaryPool.getType() != StoragePoolType.RBD) { - final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); - command.add("-d", snapshotDisk.getPath()); - command.add("-n", snapshotName); - final String result = command.execute(); - if (result != null) { - s_logger.debug("Failed to delete snapshot on primary: " + result); - // return new CopyCmdAnswer("Failed to backup snapshot: " + result); - } + deleteSnapshotViaManageSnapshotScript(snapshotName, snapshotDisk); } } } catch (final Exception ex) { @@ -1035,6 +1036,16 @@ public class KVMStorageProcessor implements StorageProcessor { } } + private void deleteSnapshotViaManageSnapshotScript(final String snapshotName, KVMPhysicalDisk snapshotDisk) { + final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); + command.add(MANAGE_SNAPSTHOT_DESTROY_OPTION, snapshotDisk.getPath()); + command.add(NAME_OPTION, snapshotName); + final String result = command.execute(); + if (result != null) { + s_logger.debug("Failed to delete snapshot on primary: " + result); + } + } + protected synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach) throws LibvirtException, URISyntaxException, InternalErrorException { String isoXml = null; @@ -1494,12 +1505,7 @@ public class KVMStorageProcessor implements StorageProcessor { */ if (primaryPool.getType() == StoragePoolType.RBD) { try { - final Rados r = new Rados(primaryPool.getAuthUserName()); - r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort()); - r.confSet("key", primaryPool.getAuthSecret()); - r.confSet("client_mount_timeout", "30"); - r.connect(); - s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host")); + Rados r = radosConnect(primaryPool); final IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir()); final Rbd rbd = new Rbd(io); @@ -1516,8 +1522,8 @@ public class KVMStorageProcessor implements StorageProcessor { } else { /* VM is not running, create a snapshot by ourself */ final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); - command.add("-c", disk.getPath()); - command.add("-n", snapshotName); + command.add(MANAGE_SNAPSTHOT_CREATE_OPTION, disk.getPath()); + command.add(NAME_OPTION, snapshotName); final String result = command.execute(); if (result != null) { s_logger.debug("Failed to manage snapshot: " + result); @@ -1536,6 +1542,16 @@ public class KVMStorageProcessor implements StorageProcessor { } } + private Rados radosConnect(final KVMStoragePool primaryPool) throws RadosException { + Rados r = new Rados(primaryPool.getAuthUserName()); + r.confSet(CEPH_MON_HOST, primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort()); + r.confSet(CEPH_AUTH_KEY, primaryPool.getAuthSecret()); + r.confSet(CEPH_CLIENT_MOUNT_TIMEOUT, CEPH_DEFAULT_MOUNT_TIMEOUT); + r.connect(); + s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet(CEPH_MON_HOST)); + return r; + } + @Override public Answer deleteVolume(final DeleteCommand cmd) { final VolumeObjectTO vol = (VolumeObjectTO)cmd.getData(); @@ -1624,12 +1640,7 @@ public class KVMStorageProcessor implements StorageProcessor { String snapshotName = snapshotFullPath.substring(snapshotFullPath.lastIndexOf("/") + 1); snap_full_name = disk.getName() + "@" + snapshotName; if (primaryPool.getType() == StoragePoolType.RBD) { - Rados r = new Rados(primaryPool.getAuthUserName()); - r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort()); - r.confSet("key", primaryPool.getAuthSecret()); - r.confSet("client_mount_timeout", "30"); - r.connect(); - s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host")); + Rados r = radosConnect(primaryPool); IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir()); Rbd rbd = new Rbd(io); RbdImage image = rbd.open(disk.getName()); @@ -1649,6 +1660,9 @@ public class KVMStorageProcessor implements StorageProcessor { rbd.close(image); r.ioCtxDestroy(io); } + } else if (primaryPool.getType() == StoragePoolType.NetworkFilesystem) { + s_logger.info(String.format("Attempting to remove snapshot (id=%s, name=%s, path=%s, storage type=%s) on primary storage", snapshotTO.getId(), snapshotTO.getName(), snapshotTO.getPath(), primaryPool.getType())); + deleteSnapshotViaManageSnapshotScript(snapshotName, disk); } else { s_logger.warn("Operation not implemented for storage pool type of " + primaryPool.getType().toString()); throw new InternalErrorException("Operation not implemented for storage pool type of " + primaryPool.getType().toString()); diff --git a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index aab9510c4f0..698d6d73904 100644 --- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -371,6 +371,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { // Reorder hosts in the decreasing order of free capacity. private List reorderHostsByCapacity(DeploymentPlan plan, List hosts) { + Long zoneId = plan.getDataCenterId(); Long clusterId = plan.getClusterId(); //Get capacity by which we should reorder String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key()); @@ -378,7 +379,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { if("RAM".equalsIgnoreCase(capacityTypeToOrder)){ capacityType = CapacityVO.CAPACITY_TYPE_MEMORY; } - List hostIdsByFreeCapacity = _capacityDao.orderHostsByFreeCapacity(clusterId, capacityType); + List hostIdsByFreeCapacity = _capacityDao.orderHostsByFreeCapacity(zoneId, clusterId, capacityType); if (s_logger.isDebugEnabled()) { s_logger.debug("List of hosts in descending order of free capacity in the cluster: "+ hostIdsByFreeCapacity); } diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 267c81ae84e..e2190881074 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -3706,7 +3706,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q affinityGroups.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId)); } - return new Pair, Integer>(affinityGroups, uniqueGroupsPair.second()); + return new Pair, Integer>(affinityGroups, affinityGroups.size()); }