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