Merge branch '4.19'

This commit is contained in:
Vishesh 2024-05-07 12:44:51 +05:30
commit e9ff2707bb
No known key found for this signature in database
GPG Key ID: 4E395186CBFA790B
2 changed files with 64 additions and 4 deletions

View File

@ -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

View File

@ -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):