| /* |
| * 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.storage.test; |
| |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.UUID; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.Future; |
| |
| import javax.inject.Inject; |
| |
| 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.DataStoreProvider; |
| import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; |
| import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; |
| import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; |
| import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; |
| import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult; |
| import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; |
| import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; |
| import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; |
| import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; |
| import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; |
| import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; |
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; |
| import org.apache.cloudstack.storage.volume.VolumeObject; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.Matchers; |
| import org.springframework.test.context.ContextConfiguration; |
| import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; |
| |
| import com.cloud.dc.ClusterVO; |
| import com.cloud.dc.DataCenter; |
| import com.cloud.dc.DataCenterVO; |
| import com.cloud.dc.HostPodVO; |
| import com.cloud.dc.dao.ClusterDao; |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.dc.dao.HostPodDao; |
| import com.cloud.hypervisor.Hypervisor; |
| import com.cloud.org.Cluster; |
| import com.cloud.org.Managed; |
| import com.cloud.server.LockMasterListener; |
| import com.cloud.storage.CreateSnapshotPayload; |
| import com.cloud.storage.DataStoreRole; |
| import com.cloud.storage.ScopeType; |
| import com.cloud.storage.Snapshot; |
| import com.cloud.storage.Snapshot.LocationType; |
| import com.cloud.storage.SnapshotPolicyVO; |
| import com.cloud.storage.SnapshotVO; |
| import com.cloud.storage.Storage; |
| import com.cloud.storage.StoragePoolStatus; |
| import com.cloud.storage.Volume; |
| import com.cloud.storage.VolumeVO; |
| import com.cloud.storage.dao.SnapshotDao; |
| import com.cloud.storage.dao.SnapshotPolicyDao; |
| import com.cloud.storage.dao.VolumeDao; |
| import com.cloud.user.Account; |
| import com.cloud.user.AccountManager; |
| import com.cloud.user.User; |
| import com.cloud.utils.DateUtil; |
| import com.cloud.utils.component.ComponentContext; |
| import com.cloud.utils.db.Merovingian2; |
| |
| import junit.framework.Assert; |
| |
| @RunWith(SpringJUnit4ClassRunner.class) |
| @ContextConfiguration(locations = {"classpath:/fakeDriverTestContext.xml"}) |
| public class SnapshotTestWithFakeData { |
| @Inject |
| SnapshotService snapshotService; |
| @Inject |
| SnapshotDao snapshotDao; |
| @Inject |
| PrimaryDataStoreDao primaryDataStoreDao; |
| @Inject |
| DataStoreManager dataStoreManager; |
| @Inject |
| SnapshotDataFactory snapshotDataFactory; |
| @Inject |
| PrimaryDataStoreProvider primaryDataStoreProvider; |
| @Inject |
| SnapshotDataStoreDao snapshotDataStoreDao; |
| @Inject |
| VolumeDao volumeDao; |
| @Inject |
| VolumeService volumeService; |
| @Inject |
| VolumeDataFactory volumeDataFactory; |
| @Inject |
| DataCenterDao dcDao; |
| Long dcId; |
| @Inject |
| HostPodDao podDao; |
| Long podId; |
| @Inject |
| ClusterDao clusterDao; |
| Long clusterId; |
| @Inject |
| ImageStoreDao imageStoreDao; |
| ImageStoreVO imageStore; |
| @Inject |
| AccountManager accountManager; |
| LockMasterListener lockMasterListener; |
| VolumeInfo vol = null; |
| FakePrimaryDataStoreDriver driver = new FakePrimaryDataStoreDriver(); |
| @Inject |
| MockStorageMotionStrategy mockStorageMotionStrategy; |
| Merovingian2 _lockMaster; |
| @Inject |
| SnapshotPolicyDao snapshotPolicyDao; |
| |
| @Before |
| public void setUp() { |
| // create data center |
| |
| DataCenterVO dc = |
| new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", null, null, DataCenter.NetworkType.Basic, null, |
| null, true, true, null, null); |
| dc = dcDao.persist(dc); |
| dcId = dc.getId(); |
| // create pod |
| |
| HostPodVO pod = new HostPodVO(UUID.randomUUID().toString(), dc.getId(), "10.223.0.1", "10.233.2.2/25", 8, "test"); |
| pod = podDao.persist(pod); |
| podId = pod.getId(); |
| // create xenserver cluster |
| ClusterVO cluster = new ClusterVO(dc.getId(), pod.getId(), "devcloud cluster"); |
| cluster.setHypervisorType(Hypervisor.HypervisorType.XenServer.toString()); |
| cluster.setClusterType(Cluster.ClusterType.CloudManaged); |
| cluster.setManagedState(Managed.ManagedState.Managed); |
| cluster = clusterDao.persist(cluster); |
| clusterId = cluster.getId(); |
| |
| imageStore = new ImageStoreVO(); |
| imageStore.setName(UUID.randomUUID().toString()); |
| imageStore.setDataCenterId(dcId); |
| imageStore.setProviderName(DataStoreProvider.NFS_IMAGE); |
| imageStore.setRole(DataStoreRole.Image); |
| imageStore.setUrl(UUID.randomUUID().toString()); |
| imageStore.setUuid(UUID.randomUUID().toString()); |
| imageStore.setProtocol("nfs"); |
| imageStore = imageStoreDao.persist(imageStore); |
| |
| when(primaryDataStoreProvider.configure(Matchers.anyMap())).thenReturn(true); |
| Set<DataStoreProvider.DataStoreProviderType> types = new HashSet<DataStoreProvider.DataStoreProviderType>(); |
| types.add(DataStoreProvider.DataStoreProviderType.PRIMARY); |
| |
| when(primaryDataStoreProvider.getTypes()).thenReturn(types); |
| when(primaryDataStoreProvider.getName()).thenReturn(DataStoreProvider.DEFAULT_PRIMARY); |
| when(primaryDataStoreProvider.getDataStoreDriver()).thenReturn(driver); |
| User user = mock(User.class); |
| when(user.getId()).thenReturn(1L); |
| Account account = mock(Account.class); |
| when(account.getId()).thenReturn(1L); |
| when(accountManager.getSystemAccount()).thenReturn(account); |
| when(accountManager.getSystemUser()).thenReturn(user); |
| |
| if (Merovingian2.getLockMaster() == null) { |
| _lockMaster = Merovingian2.createLockMaster(1234); |
| } else { |
| _lockMaster = Merovingian2.getLockMaster(); |
| } |
| _lockMaster.cleanupThisServer(); |
| ComponentContext.initComponentsLifeCycle(); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| _lockMaster.cleanupThisServer(); |
| } |
| |
| private SnapshotVO createSnapshotInDb() { |
| Snapshot.Type snapshotType = Snapshot.Type.RECURRING; |
| SnapshotVO snapshotVO = |
| new SnapshotVO(dcId, 2, 1, 1L, 1L, UUID.randomUUID().toString(), (short)snapshotType.ordinal(), snapshotType.name(), 100, 1L, 100L, Hypervisor.HypervisorType.XenServer, |
| LocationType.PRIMARY); |
| return snapshotDao.persist(snapshotVO); |
| } |
| |
| private SnapshotVO createSnapshotInDb(Long volumeId) { |
| Snapshot.Type snapshotType = Snapshot.Type.DAILY; |
| SnapshotVO snapshotVO = |
| new SnapshotVO(dcId, 2, 1, 1L, 1L, UUID.randomUUID().toString(), (short)snapshotType.ordinal(), snapshotType.name(), 100, 1L, 100L, Hypervisor.HypervisorType.XenServer, |
| LocationType.PRIMARY); |
| return snapshotDao.persist(snapshotVO); |
| } |
| |
| private VolumeInfo createVolume(Long templateId, DataStore store) { |
| VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), dcId, 1L, 1L, 1L, Storage.ProvisioningType.THIN, 1000, 0L, 0L, ""); |
| volume.setPoolId(store.getId()); |
| |
| volume = volumeDao.persist(volume); |
| VolumeInfo volumeInfo = volumeDataFactory.getVolume(volume.getId(), store); |
| volumeInfo.stateTransit(Volume.Event.CreateRequested); |
| volumeInfo.stateTransit(Volume.Event.OperationSucceeded); |
| return volumeInfo; |
| } |
| |
| private DataStore createDataStore() throws URISyntaxException { |
| StoragePoolVO pool = new StoragePoolVO(); |
| pool.setClusterId(clusterId); |
| pool.setDataCenterId(dcId); |
| URI uri = new URI("nfs://jfkdkf/fjdkfj"); |
| pool.setHostAddress(uri.getHost()); |
| pool.setPath(uri.getPath()); |
| pool.setPort(0); |
| pool.setName(UUID.randomUUID().toString()); |
| pool.setUuid(UUID.randomUUID().toString()); |
| pool.setStatus(StoragePoolStatus.Up); |
| pool.setPoolType(Storage.StoragePoolType.NetworkFilesystem); |
| pool.setPodId(podId); |
| pool.setScope(ScopeType.CLUSTER); |
| pool.setStorageProviderName(DataStoreProvider.DEFAULT_PRIMARY); |
| pool = primaryDataStoreDao.persist(pool); |
| DataStore store = dataStoreManager.getPrimaryDataStore(pool.getId()); |
| return store; |
| } |
| |
| //@Test |
| public void testTakeSnapshot() throws URISyntaxException { |
| SnapshotVO snapshotVO = createSnapshotInDb(); |
| DataStore store = createDataStore(); |
| try { |
| SnapshotInfo snapshotInfo = snapshotDataFactory.getSnapshot(snapshotVO.getId(), store); |
| SnapshotResult result = snapshotService.takeSnapshot(snapshotInfo); |
| Assert.assertTrue(result.isSuccess()); |
| SnapshotDataStoreVO storeRef = snapshotDataStoreDao.findByStoreSnapshot(store.getRole(), store.getId(), snapshotVO.getId()); |
| Assert.assertTrue(storeRef != null); |
| Assert.assertTrue(storeRef.getState() == ObjectInDataStoreStateMachine.State.Ready); |
| snapshotInfo = result.getSnapshot(); |
| boolean deletResult = snapshotService.deleteSnapshot(snapshotInfo); |
| Assert.assertTrue(deletResult); |
| snapshotDataStoreDao.expunge(storeRef.getId()); |
| } finally { |
| snapshotDao.expunge(snapshotVO.getId()); |
| primaryDataStoreDao.remove(store.getId()); |
| } |
| } |
| |
| //@Test |
| public void testTakeSnapshotWithFailed() throws URISyntaxException { |
| SnapshotVO snapshotVO = createSnapshotInDb(); |
| DataStore store = null; |
| try { |
| store = createDataStore(); |
| FakePrimaryDataStoreDriver dataStoreDriver = (FakePrimaryDataStoreDriver)store.getDriver(); |
| dataStoreDriver.makeTakeSnapshotSucceed(false); |
| SnapshotInfo snapshotInfo = snapshotDataFactory.getSnapshot(snapshotVO.getId(), store); |
| SnapshotResult result = snapshotService.takeSnapshot(snapshotInfo); |
| Assert.assertFalse(result.isSuccess()); |
| SnapshotDataStoreVO storeRef = snapshotDataStoreDao.findByStoreSnapshot(store.getRole(), store.getId(), snapshotVO.getId()); |
| Assert.assertTrue(storeRef == null); |
| } finally { |
| snapshotDao.expunge(snapshotVO.getId()); |
| if (store != null) { |
| primaryDataStoreDao.remove(store.getId()); |
| } |
| } |
| } |
| |
| //@Test |
| public void testTakeSnapshotFromVolume() throws URISyntaxException { |
| DataStore store = createDataStore(); |
| FakePrimaryDataStoreDriver dataStoreDriver = (FakePrimaryDataStoreDriver)store.getDriver(); |
| dataStoreDriver.makeTakeSnapshotSucceed(false); |
| VolumeInfo volumeInfo = createVolume(1L, store); |
| Assert.assertTrue(volumeInfo.getState() == Volume.State.Ready); |
| SnapshotInfo result = volumeService.takeSnapshot(volumeInfo); |
| Assert.assertTrue(volumeInfo.getState() == Volume.State.Ready); |
| Assert.assertTrue(result == null); |
| } |
| |
| protected SnapshotPolicyVO createSnapshotPolicy(Long volId) { |
| SnapshotPolicyVO policyVO = new SnapshotPolicyVO(volId, "jfkd", "fdfd", DateUtil.IntervalType.DAILY, 8, true); |
| policyVO = snapshotPolicyDao.persist(policyVO); |
| return policyVO; |
| } |
| |
| @Test |
| public void testConcurrentSnapshot() throws URISyntaxException, InterruptedException, ExecutionException { |
| DataStore store = createDataStore(); |
| final FakePrimaryDataStoreDriver dataStoreDriver = (FakePrimaryDataStoreDriver)store.getDriver(); |
| dataStoreDriver.makeTakeSnapshotSucceed(true); |
| final VolumeInfo volumeInfo = createVolume(1L, store); |
| Assert.assertTrue(volumeInfo.getState() == Volume.State.Ready); |
| vol = volumeInfo; |
| // final SnapshotPolicyVO policyVO = createSnapshotPolicy(vol.getId()); |
| |
| ExecutorService pool = Executors.newFixedThreadPool(2); |
| boolean result = false; |
| List<Future<Boolean>> future = new ArrayList<Future<Boolean>>(); |
| for (int i = 0; i < 12; i++) { |
| final int cnt = i; |
| Future<Boolean> task = pool.submit(new Callable<Boolean>() { |
| @Override |
| public Boolean call() throws Exception { |
| boolean r = true; |
| try { |
| SnapshotVO snapshotVO = createSnapshotInDb(vol.getId()); |
| VolumeObject volumeObject = (VolumeObject)vol; |
| Account account = mock(Account.class); |
| when(account.getId()).thenReturn(1L); |
| CreateSnapshotPayload createSnapshotPayload = mock(CreateSnapshotPayload.class); |
| when(createSnapshotPayload.getAccount()).thenReturn(account); |
| when(createSnapshotPayload.getSnapshotId()).thenReturn(snapshotVO.getId()); |
| when(createSnapshotPayload.getSnapshotPolicyId()).thenReturn(0L); |
| volumeObject.addPayload(createSnapshotPayload); |
| if (cnt > 8) { |
| mockStorageMotionStrategy.makeBackupSnapshotSucceed(false); |
| } |
| SnapshotInfo newSnapshot = volumeService.takeSnapshot(vol); |
| if (newSnapshot == null) { |
| r = false; |
| } |
| } catch (Exception e) { |
| r = false; |
| } |
| return r; |
| } |
| }); |
| Assert.assertTrue(task.get()); |
| } |
| |
| } |
| } |