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.LinstorUtil;
|
||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
import org.apache.cloudstack.storage.volume.VolumeObject;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -798,6 +799,15 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
|| 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
|
||||
public boolean canCopy(DataObject srcData, DataObject dstData)
|
||||
{
|
||||
@ -814,6 +824,10 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
return storagePoolVO != null
|
||||
&& storagePoolVO.getPoolType() == Storage.StoragePoolType.Linstor
|
||||
&& 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;
|
||||
}
|
||||
@ -844,6 +858,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
} else if (canCopyTemplateCond(srcData, dstData)) {
|
||||
Answer answer = copyTemplate(srcData, dstData);
|
||||
res = new CopyCommandResult(null, answer);
|
||||
} else if (canCopyVolumeCond(srcData, dstData)) {
|
||||
Answer answer = copyVolume(srcData, dstData);
|
||||
res = new CopyCommandResult(null, answer);
|
||||
} else {
|
||||
Answer answer = new Answer(null, false, "noimpl");
|
||||
res = new CopyCommandResult(null, answer);
|
||||
@ -965,6 +982,43 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
|
||||
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
|
||||
* @param api Linstor Developer api object
|
||||
|
||||
@ -32,6 +32,7 @@ class TestRestoreVM(cloudstackTestCase):
|
||||
testClient = super(TestRestoreVM, cls).getClsTestClient()
|
||||
cls.apiclient = testClient.getApiClient()
|
||||
cls.services = testClient.getParsedTestDataConfig()
|
||||
cls._cleanup = []
|
||||
|
||||
# Get Zone, Domain and templates
|
||||
cls.domain = get_domain(cls.apiclient)
|
||||
@ -42,16 +43,21 @@ class TestRestoreVM(cloudstackTestCase):
|
||||
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
|
||||
|
||||
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'],
|
||||
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'],
|
||||
zoneid=cls.zone.id, hypervisor=cls.hypervisor.lower())
|
||||
|
||||
cls._cleanup = [cls.service_offering, cls.template_t1, cls.template_t2]
|
||||
cls._cleanup.append(template_t2)
|
||||
template_t2.download(cls.apiclient)
|
||||
cls.template_t2 = Template.list(cls.apiclient, templatefilter='all', id=template_t2.id)[0]
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user