This commit is contained in:
Animesh Chaturvedi 2013-08-22 16:05:36 -07:00
commit 6abf2a31e4
12 changed files with 156 additions and 61 deletions

View File

@ -73,6 +73,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VMTemplateZoneVO;
@ -404,6 +405,11 @@ public class TemplateServiceImpl implements TemplateService {
s_logger.info("Skip downloading template " + tmplt.getUniqueName() + " since no url is specified.");
continue;
}
// if this is private template, skip sync to a new image store
if (!tmplt.isPublicTemplate() && !tmplt.isFeatured() && tmplt.getTemplateType() != TemplateType.SYSTEM) {
s_logger.info("Skip sync downloading private template " + tmplt.getUniqueName() + " to a new image store");
continue;
}
if (availHypers.contains(tmplt.getHypervisorType())) {
s_logger.info("Downloading template " + tmplt.getUniqueName() + " to image store "

View File

@ -185,12 +185,6 @@ public class ChildTestConfiguration extends TestConfiguration {
return Mockito.mock(VirtualMachineManager.class);
}
@Bean
public SnapshotManager snapshotMgr() {
return Mockito.mock(SnapshotManager.class);
}
@Bean
public ResourceManager resourceMgr() {
return Mockito.mock(ResourceManager.class);

View File

@ -18,6 +18,10 @@
*/
package org.apache.cloudstack.storage.test;
import com.cloud.storage.snapshot.SnapshotScheduler;
import com.cloud.storage.snapshot.SnapshotSchedulerImpl;
import com.cloud.user.DomainManager;
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
import org.apache.cloudstack.storage.datastore.provider.CloudStackPrimaryDataStoreProviderImpl;
import org.apache.cloudstack.storage.datastore.type.DataStoreType;
@ -35,4 +39,20 @@ public class FakeDriverTestConfiguration extends ChildTestConfiguration{
return provider;
}
@Bean
public DataMotionStrategy dataMotionStrategy() {
DataMotionStrategy strategy = new MockStorageMotionStrategy();
return strategy;
}
@Bean
public SnapshotScheduler SnapshotScheduler() {
return Mockito.mock(SnapshotScheduler.class);
}
@Bean
public DomainManager DomainManager() {
return Mockito.mock(DomainManager.class);
}
}

View File

@ -19,7 +19,11 @@
package org.apache.cloudstack.storage.test;
import java.util.Map;
import java.util.UUID;
import com.cloud.agent.api.to.DataObjectType;
import com.cloud.agent.api.to.DataTO;
import com.cloud.storage.Storage;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
@ -29,6 +33,9 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.host.Host;
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.cloudstack.storage.to.TemplateObjectTO;
public class MockStorageMotionStrategy implements DataMotionStrategy {
@ -45,7 +52,22 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
@Override
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult("something", null);
CopyCmdAnswer answer = null;
DataTO data = null;
if (destData.getType() == DataObjectType.SNAPSHOT) {
SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
newSnapshot.setPath(UUID.randomUUID().toString());
data = newSnapshot;
} else if (destData.getType() == DataObjectType.TEMPLATE) {
TemplateObjectTO newTemplate = new TemplateObjectTO();
newTemplate.setPath(UUID.randomUUID().toString());
newTemplate.setFormat(Storage.ImageFormat.QCOW2);
newTemplate.setSize(10L);
newTemplate.setPhysicalSize(10L);
data = newTemplate;
}
answer = new CopyCmdAnswer(data);
CopyCommandResult result = new CopyCommandResult("something", answer);
callback.complete(result);
return null;
}

View File

@ -29,6 +29,7 @@ import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.db.DB;
import junit.framework.Assert;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
@ -61,10 +62,17 @@ import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/fakeDriverTestContext.xml" })
public class SnapshotTestWithFakeData {
public class SnapshotTestWithFakeData {
@Inject
SnapshotService snapshotService;
@Inject
@ -85,6 +93,7 @@ public class SnapshotTestWithFakeData {
VolumeService volumeService;
@Inject
VolumeDataFactory volumeDataFactory;
VolumeInfo vol = null;
FakePrimaryDataStoreDriver driver = new FakePrimaryDataStoreDriver();
@Before
@ -191,4 +200,32 @@ public class SnapshotTestWithFakeData {
Assert.assertTrue(result == null);
}
@Test
public void testConcurrentSnapshot() throws URISyntaxException, InterruptedException, ExecutionException {
DataStore store = createDataStore();
FakePrimaryDataStoreDriver dataStoreDriver = (FakePrimaryDataStoreDriver)store.getDriver();
dataStoreDriver.makeTakeSnapshotSucceed(true);
final VolumeInfo volumeInfo = createVolume(1L, store);
Assert.assertTrue(volumeInfo.getState() == Volume.State.Ready);
vol = volumeInfo;
ExecutorService pool = Executors.newFixedThreadPool(2);
boolean result = false;
Future<Boolean> future = null;
for(int i = 0; i < 1; i++) {
future = pool.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
boolean r = false;
try {
SnapshotInfo newSnapshot = volumeService.takeSnapshot(vol);
Assert.assertTrue(newSnapshot != null);
} catch (Exception e) {
r = false;
}
return true;
}
});
}
future.get();
}
}

View File

@ -48,7 +48,6 @@
<bean id="clusterScopeStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ClusterScopeStoragePoolAllocator" />
<bean id="zoneWideStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ZoneWideStoragePoolAllocator" />
<bean id="dataStoreProviderManagerImpl" class="org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManagerImpl" />
<bean id="ancientDataMotionStrategy" class="org.apache.cloudstack.storage.motion.AncientDataMotionStrategy" />
<bean id="storageCacheManagerImpl" class="org.apache.cloudstack.storage.cache.manager.StorageCacheManagerImpl" />
<bean id="storageCacheRandomAllocator" class="org.apache.cloudstack.storage.cache.allocator.StorageCacheRandomAllocator" />
<bean id="xenserverSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.XenserverSnapshotStrategy" />
@ -84,4 +83,8 @@
<bean id="AccountGuestVlanMapDaoImpl" class="com.cloud.network.dao.AccountGuestVlanMapDaoImpl" />
<bean id="StorageCacheReplacementAlgorithm" class="org.apache.cloudstack.storage.cache.manager.StorageCacheReplacementAlgorithmLRU" />
<bean id="ServiceOfferingDetailsDao" class="com.cloud.service.dao.ServiceOfferingDetailsDaoImpl" />
<bean id='SnapshotManagerImpl' class='com.cloud.storage.snapshot.SnapshotManagerImpl'/>
<bean id='SnapshotPolicyDao' class='com.cloud.storage.dao.SnapshotPolicyDaoImpl'/>
<bean id='SnapshotScheduleDao' class='com.cloud.storage.dao.SnapshotScheduleDaoImpl' />
</beans>

View File

@ -266,6 +266,12 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
}
} else if (obj.getType() == DataObjectType.SNAPSHOT) {
return objectInStoreMgr.create(obj, this);
} else if (obj.getType() == DataObjectType.VOLUME) {
VolumeVO vol = volumeDao.findById(obj.getId());
if (vol != null) {
vol.setPoolId(this.getId());
volumeDao.update(vol.getId(), vol);
}
}
return objectInStoreMgr.get(obj, this);

View File

@ -3644,10 +3644,10 @@ ServerResource {
physicalDisk = secondaryStorage.getPhysicalDisk(volName);
} else if (volume.getType() != Volume.Type.ISO) {
PrimaryDataStoreTO store = (PrimaryDataStoreTO)data.getDataStore();
pool = _storagePoolMgr.getStoragePool(
store.getPoolType(),
store.getUuid());
physicalDisk = pool.getPhysicalDisk(data.getPath());
physicalDisk = _storagePoolMgr.getPhysicalDisk( store.getPoolType(),
store.getUuid(),
data.getPath());
pool = physicalDisk.getPool();
}
String volPath = null;
@ -3720,10 +3720,9 @@ ServerResource {
if (volume.getType() == Volume.Type.ROOT) {
DataTO data = volume.getData();
PrimaryDataStoreTO store = (PrimaryDataStoreTO)data.getDataStore();
KVMStoragePool pool = _storagePoolMgr.getStoragePool(
store.getPoolType(),
store.getUuid());
KVMPhysicalDisk physicalDisk = pool.getPhysicalDisk(data.getPath());
KVMPhysicalDisk physicalDisk = _storagePoolMgr.getPhysicalDisk( store.getPoolType(),
store.getUuid(),
data.getPath());
FilesystemDef rootFs = new FilesystemDef(physicalDisk.getPath(), "/");
vm.getDevices().addDevice(rootFs);
break;
@ -3765,6 +3764,10 @@ ServerResource {
// need to umount secondary storage
String path = disk.getDiskPath();
String poolUuid = null;
if (path.endsWith("systemvm.iso")) {
//Don't need to clean up system vm iso, as it's stored in local
return true;
}
if (path != null) {
String[] token = path.split("/");
if (token.length > 3) {

View File

@ -31,8 +31,11 @@ import com.cloud.hypervisor.kvm.resource.KVMHAMonitor;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.log4j.Logger;
public class KVMStoragePoolManager {
private static final Logger s_logger = Logger
.getLogger(KVMStoragePoolManager.class);
private class StoragePoolInformation {
String name;
String host;
@ -133,6 +136,36 @@ public class KVMStoragePoolManager {
return createStoragePool(uuid, sourceHost, 0, sourcePath, "", protocol, false);
}
public KVMPhysicalDisk getPhysicalDisk(StoragePoolType type, String poolUuid, String volName) {
int cnt = 0;
int retries = 10;
KVMPhysicalDisk vol = null;
//harden get volume, try cnt times to get volume, in case volume is created on other host
String errMsg = "";
while (cnt < retries) {
try {
KVMStoragePool pool = getStoragePool(type, poolUuid);
vol = pool.getPhysicalDisk(volName);
if (vol != null) {
break;
}
Thread.sleep(10000);
} catch (Exception e) {
s_logger.debug("Failed to find volume:" + volName + " due to" + e.toString() + ", retry:" + cnt);
errMsg = e.toString();
}
cnt++;
}
if (vol == null) {
throw new CloudRuntimeException(errMsg);
} else {
return vol;
}
}
public KVMStoragePool createStoragePool( String name, String host, int port,
String path, String userInfo,
StoragePoolType type) {

View File

@ -289,8 +289,8 @@ public class KVMStorageProcessor implements StorageProcessor {
if (primaryPool.getType() == StoragePoolType.CLVM) {
vol = templateToPrimaryDownload(templatePath, primaryPool);
} else {
BaseVol = primaryPool.getPhysicalDisk(templatePath);
vol = storagePoolMgr.createDiskFromTemplate(BaseVol, UUID.randomUUID().toString(), primaryPool);
BaseVol = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), templatePath);
vol = storagePoolMgr.createDiskFromTemplate(BaseVol, UUID.randomUUID().toString(), BaseVol.getPool());
}
if (vol == null) {
return new CopyCmdAnswer(" Can't create storage volume on storage pool");
@ -386,28 +386,12 @@ public class KVMStorageProcessor implements StorageProcessor {
String destVolumePath = destData.getPath();
String secondaryStorageUrl = nfsStore.getUrl();
KVMStoragePool secondaryStoragePool = null;
KVMStoragePool primaryPool = null;
try {
try {
primaryPool = storagePoolMgr.getStoragePool(
primaryStore.getPoolType(),
primaryStore.getUuid());
} catch (CloudRuntimeException e) {
if (e.getMessage().contains("not found")) {
primaryPool = storagePoolMgr.createStoragePool(primaryStore.getUuid(),
primaryStore.getHost(), primaryStore.getPort(),
primaryStore.getPath(), null,
primaryStore.getPoolType());
} else {
return new CopyCmdAnswer(e.getMessage());
}
}
try {
String volumeName = UUID.randomUUID().toString();
String destVolumeName = volumeName + ".qcow2";
KVMPhysicalDisk volume = primaryPool.getPhysicalDisk(srcVolumePath);
KVMPhysicalDisk volume = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), srcVolumePath);
secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(
secondaryStorageUrl);
secondaryStoragePool.createFolder(destVolumePath);
@ -450,18 +434,9 @@ public class KVMStorageProcessor implements StorageProcessor {
secondaryStorage = storagePoolMgr.getStoragePoolByURI(nfsImageStore.getUrl());
try {
primary = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
} catch (CloudRuntimeException e) {
if (e.getMessage().contains("not found")) {
primary = storagePoolMgr.createStoragePool(primaryStore.getUuid(), primaryStore.getHost(),
primaryStore.getPort(), primaryStore.getPath(), null, primaryStore.getPoolType());
} else {
return new CopyCmdAnswer(e.getMessage());
}
}
primary = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
KVMPhysicalDisk disk = primary.getPhysicalDisk(volume.getPath());
KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath());
String tmpltPath = secondaryStorage.getLocalPath() + File.separator + templateFolder;
this.storageLayer.mkdirs(tmpltPath);
String templateName = UUID.randomUUID().toString();
@ -651,9 +626,9 @@ public class KVMStorageProcessor implements StorageProcessor {
snapshotRelPath = destSnapshot.getPath();
snapshotDestPath = ssPmountPath + File.separator + snapshotRelPath;
KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(),
primaryStore.getUuid());
KVMPhysicalDisk snapshotDisk = primaryPool.getPhysicalDisk(volumePath);
KVMPhysicalDisk snapshotDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(),
primaryStore.getUuid(), volumePath);
KVMStoragePool primaryPool = snapshotDisk.getPool();
/**
* RBD snapshots can't be copied using qemu-img, so we have to use
@ -788,6 +763,7 @@ public class KVMStorageProcessor implements StorageProcessor {
}
}
protected synchronized String attachOrDetachISO(Connect conn, String vmName, String isoPath, boolean isAttach)
throws LibvirtException, URISyntaxException, InternalErrorException {
String isoXml = null;
@ -957,9 +933,8 @@ public class KVMStorageProcessor implements StorageProcessor {
String vmName = cmd.getVmName();
try {
Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
KVMStoragePool primary = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath());
KVMPhysicalDisk phyDisk = primary.getPhysicalDisk(vol.getPath());
attachOrDetachDisk(conn, true, vmName, phyDisk, disk.getDiskSeq().intValue());
return new AttachAnswer(disk);
@ -980,9 +955,8 @@ public class KVMStorageProcessor implements StorageProcessor {
String vmName = cmd.getVmName();
try {
Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
KVMStoragePool primary = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath());
KVMPhysicalDisk phyDisk = primary.getPhysicalDisk(vol.getPath());
attachOrDetachDisk(conn, false, vmName, phyDisk, disk.getDiskSeq().intValue());
return new DettachAnswer(disk);
@ -1054,7 +1028,8 @@ public class KVMStorageProcessor implements StorageProcessor {
KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(),
primaryStore.getUuid());
KVMPhysicalDisk disk = primaryPool.getPhysicalDisk(volume.getPath());
KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(),
primaryStore.getUuid(), volume.getPath());
if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryPool.isExternalSnapshot()) {
String vmUuid = vm.getUUIDString();
Object[] args = new Object[] { snapshotName, vmUuid };

View File

@ -3120,7 +3120,7 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setIp(ApiDBUtils.findIpAddressById(result.getAddrId()).getAddress().toString());
Vpc vpc = ApiDBUtils.findVpcById(result.getVpcId());
if (vpc != null) {
response.setVpcId(result.getUuid());
response.setVpcId(vpc.getUuid());
}
response.setRemoved(result.getRemoved());
response.setObjectName("vpngateway");

View File

@ -139,8 +139,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject
protected VMTemplateDao _templateDao;
@Inject
protected HostDao _hostDao;
@Inject
protected UserVmDao _vmDao;
@Inject
protected VolumeDao _volsDao;
@ -157,8 +155,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject
protected PrimaryDataStoreDao _storagePoolDao;
@Inject
protected EventDao _eventDao;
@Inject
protected SnapshotPolicyDao _snapshotPolicyDao = null;
@Inject
protected SnapshotScheduleDao _snapshotScheduleDao;