mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Merge branch '4.19'
This commit is contained in:
		
						commit
						e9ff2707bb
					
				| @ -102,6 +102,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | |||||||
| import org.apache.cloudstack.storage.datastore.util.LinstorConfigurationManager; | import org.apache.cloudstack.storage.datastore.util.LinstorConfigurationManager; | ||||||
| import org.apache.cloudstack.storage.datastore.util.LinstorUtil; | import org.apache.cloudstack.storage.datastore.util.LinstorUtil; | ||||||
| import org.apache.cloudstack.storage.to.SnapshotObjectTO; | import org.apache.cloudstack.storage.to.SnapshotObjectTO; | ||||||
|  | import org.apache.cloudstack.storage.to.VolumeObjectTO; | ||||||
| import org.apache.cloudstack.storage.volume.VolumeObject; | import org.apache.cloudstack.storage.volume.VolumeObject; | ||||||
| import org.apache.logging.log4j.Logger; | import org.apache.logging.log4j.Logger; | ||||||
| import org.apache.logging.log4j.LogManager; | import org.apache.logging.log4j.LogManager; | ||||||
| @ -798,6 +799,15 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver | |||||||
|             || srcData.getDataStore().getRole() == DataStoreRole.ImageCache); |             || srcData.getDataStore().getRole() == DataStoreRole.ImageCache); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private static boolean canCopyVolumeCond(DataObject srcData, DataObject dstData) { | ||||||
|  |         // Volume download from Linstor primary storage | ||||||
|  |         return srcData.getType() == DataObjectType.VOLUME | ||||||
|  |                 && (dstData.getType() == DataObjectType.VOLUME || dstData.getType() == DataObjectType.TEMPLATE) | ||||||
|  |                 && srcData.getDataStore().getRole() == DataStoreRole.Primary | ||||||
|  |                 && (dstData.getDataStore().getRole() == DataStoreRole.Image | ||||||
|  |                 || dstData.getDataStore().getRole() == DataStoreRole.ImageCache); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean canCopy(DataObject srcData, DataObject dstData) |     public boolean canCopy(DataObject srcData, DataObject dstData) | ||||||
|     { |     { | ||||||
| @ -814,6 +824,10 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver | |||||||
|             return storagePoolVO != null |             return storagePoolVO != null | ||||||
|                 && storagePoolVO.getPoolType() == Storage.StoragePoolType.Linstor |                 && storagePoolVO.getPoolType() == Storage.StoragePoolType.Linstor | ||||||
|                 && tInfo.getSize() != null; |                 && tInfo.getSize() != null; | ||||||
|  |         } else if (canCopyVolumeCond(srcData, dstData)) { | ||||||
|  |             VolumeInfo srcVolInfo = (VolumeInfo) srcData; | ||||||
|  |             StoragePoolVO storagePool = _storagePoolDao.findById(srcVolInfo.getPoolId()); | ||||||
|  |             return storagePool.getStorageProviderName().equals(LinstorUtil.PROVIDER_NAME); | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| @ -844,6 +858,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver | |||||||
|         } else if (canCopyTemplateCond(srcData, dstData)) { |         } else if (canCopyTemplateCond(srcData, dstData)) { | ||||||
|             Answer answer = copyTemplate(srcData, dstData); |             Answer answer = copyTemplate(srcData, dstData); | ||||||
|             res = new CopyCommandResult(null, answer); |             res = new CopyCommandResult(null, answer); | ||||||
|  |         } else if (canCopyVolumeCond(srcData, dstData)) { | ||||||
|  |             Answer answer = copyVolume(srcData, dstData); | ||||||
|  |             res = new CopyCommandResult(null, answer); | ||||||
|         } else { |         } else { | ||||||
|             Answer answer = new Answer(null, false, "noimpl"); |             Answer answer = new Answer(null, false, "noimpl"); | ||||||
|             res = new CopyCommandResult(null, answer); |             res = new CopyCommandResult(null, answer); | ||||||
| @ -965,6 +982,43 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver | |||||||
|         return answer; |         return answer; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private Answer copyVolume(DataObject srcData, DataObject dstData) { | ||||||
|  |         VolumeInfo srcVolInfo = (VolumeInfo) srcData; | ||||||
|  |         final StoragePoolVO pool = _storagePoolDao.findById(srcVolInfo.getDataStore().getId()); | ||||||
|  |         final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress()); | ||||||
|  |         final String rscName = LinstorUtil.RSC_PREFIX + srcVolInfo.getUuid(); | ||||||
|  | 
 | ||||||
|  |         VolumeObjectTO to = (VolumeObjectTO) srcVolInfo.getTO(); | ||||||
|  |         // patch source format | ||||||
|  |         // Linstor volumes are stored as RAW, but we can't set the correct format as RAW (we use QCOW2) | ||||||
|  |         // otherwise create template from snapshot won't work, because this operation | ||||||
|  |         // uses the format of the base volume and we backup snapshots as QCOW2 | ||||||
|  |         // https://github.com/apache/cloudstack/pull/8802#issuecomment-2024019927 | ||||||
|  |         to.setFormat(Storage.ImageFormat.RAW); | ||||||
|  |         int nMaxExecutionSeconds = NumbersUtil.parseInt( | ||||||
|  |                 _configDao.getValue(Config.CopyVolumeWait.key()), 10800); | ||||||
|  |         CopyCommand cmd = new CopyCommand( | ||||||
|  |                 to, | ||||||
|  |                 dstData.getTO(), | ||||||
|  |                 nMaxExecutionSeconds, | ||||||
|  |                 VirtualMachineManager.ExecuteInSequence.value()); | ||||||
|  |         Answer answer; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName); | ||||||
|  |             if (optEP.isPresent()) { | ||||||
|  |                 answer = optEP.get().sendMessage(cmd); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint."); | ||||||
|  |             } | ||||||
|  |         } catch (ApiException exc) { | ||||||
|  |             logger.error("copy volume failed: ", exc); | ||||||
|  |             throw new CloudRuntimeException(exc.getBestMessage()); | ||||||
|  |         } | ||||||
|  |         return answer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Create a temporary resource from the snapshot to backup, so we can copy the data on a diskless agent |      * Create a temporary resource from the snapshot to backup, so we can copy the data on a diskless agent | ||||||
|      * @param api Linstor Developer api object |      * @param api Linstor Developer api object | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ class TestRestoreVM(cloudstackTestCase): | |||||||
|         testClient = super(TestRestoreVM, cls).getClsTestClient() |         testClient = super(TestRestoreVM, cls).getClsTestClient() | ||||||
|         cls.apiclient = testClient.getApiClient() |         cls.apiclient = testClient.getApiClient() | ||||||
|         cls.services = testClient.getParsedTestDataConfig() |         cls.services = testClient.getParsedTestDataConfig() | ||||||
|  |         cls._cleanup = [] | ||||||
| 
 | 
 | ||||||
|         # Get Zone, Domain and templates |         # Get Zone, Domain and templates | ||||||
|         cls.domain = get_domain(cls.apiclient) |         cls.domain = get_domain(cls.apiclient) | ||||||
| @ -42,16 +43,21 @@ class TestRestoreVM(cloudstackTestCase): | |||||||
|         cls.services["virtual_machine"]["zoneid"] = cls.zone.id |         cls.services["virtual_machine"]["zoneid"] = cls.zone.id | ||||||
| 
 | 
 | ||||||
|         cls.service_offering = ServiceOffering.create(cls.apiclient, cls.services["service_offering"]) |         cls.service_offering = ServiceOffering.create(cls.apiclient, cls.services["service_offering"]) | ||||||
|  |         cls._cleanup.append(cls.service_offering) | ||||||
| 
 | 
 | ||||||
|         cls.template_t1 = Template.register(cls.apiclient, cls.services["test_templates"][ |         template_t1 = Template.register(cls.apiclient, cls.services["test_templates"][ | ||||||
|             cls.hypervisor.lower() if cls.hypervisor.lower() != 'simulator' else 'xenserver'], |             cls.hypervisor.lower() if cls.hypervisor.lower() != 'simulator' else 'xenserver'], | ||||||
|                                             zoneid=cls.zone.id, hypervisor=cls.hypervisor.lower()) |                                             zoneid=cls.zone.id, hypervisor=cls.hypervisor.lower()) | ||||||
|  |         cls._cleanup.append(template_t1) | ||||||
|  |         template_t1.download(cls.apiclient) | ||||||
|  |         cls.template_t1 = Template.list(cls.apiclient, templatefilter='all', id=template_t1.id)[0] | ||||||
| 
 | 
 | ||||||
|         cls.template_t2 = Template.register(cls.apiclient, cls.services["test_templates"][ |         template_t2 = Template.register(cls.apiclient, cls.services["test_templates"][ | ||||||
|             cls.hypervisor.lower() if cls.hypervisor.lower() != 'simulator' else 'xenserver'], |             cls.hypervisor.lower() if cls.hypervisor.lower() != 'simulator' else 'xenserver'], | ||||||
|                                             zoneid=cls.zone.id, hypervisor=cls.hypervisor.lower()) |                                             zoneid=cls.zone.id, hypervisor=cls.hypervisor.lower()) | ||||||
| 
 |         cls._cleanup.append(template_t2) | ||||||
|         cls._cleanup = [cls.service_offering, cls.template_t1, cls.template_t2] |         template_t2.download(cls.apiclient) | ||||||
|  |         cls.template_t2 = Template.list(cls.apiclient, templatefilter='all', id=template_t2.id)[0] | ||||||
| 
 | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def tearDownClass(cls): |     def tearDownClass(cls): | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user