Merge remote-tracking branch 'apache/4.20' into 4.22

This commit is contained in:
Wei Zhou 2025-11-07 17:19:53 +01:00
commit 50fe265017
No known key found for this signature in database
GPG Key ID: 1503DFE7C8226103
5 changed files with 28 additions and 32 deletions

View File

@ -101,7 +101,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
ReservationDao reservationDao; ReservationDao reservationDao;
private static final String LIST_PODS_HAVING_VMS_FOR_ACCOUNT = private static final String LIST_PODS_HAVING_VMS_FOR_ACCOUNT =
"SELECT pod_id FROM cloud.vm_instance WHERE data_center_id = ? AND account_id = ? AND pod_id IS NOT NULL AND (state = 'Running' OR state = 'Stopped') " "SELECT pod_id FROM cloud.vm_instance WHERE data_center_id = ? AND account_id = ? AND pod_id IS NOT NULL AND state IN ('Starting', 'Running', 'Stopped') "
+ "GROUP BY pod_id HAVING count(id) > 0 ORDER BY count(id) DESC"; + "GROUP BY pod_id HAVING count(id) > 0 ORDER BY count(id) DESC";
private static final String VM_DETAILS = "select vm_instance.id, " private static final String VM_DETAILS = "select vm_instance.id, "

View File

@ -105,7 +105,8 @@ public class VeeamClient {
private static final String REPOSITORY_REFERENCE = "RepositoryReference"; private static final String REPOSITORY_REFERENCE = "RepositoryReference";
private static final String RESTORE_POINT_REFERENCE = "RestorePointReference"; private static final String RESTORE_POINT_REFERENCE = "RestorePointReference";
private static final String BACKUP_FILE_REFERENCE = "BackupFileReference"; private static final String BACKUP_FILE_REFERENCE = "BackupFileReference";
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
private static final ObjectMapper OBJECT_MAPPER = new XmlMapper();
private String veeamServerIp; private String veeamServerIp;
private final Integer veeamServerVersion; private final Integer veeamServerVersion;
@ -124,6 +125,8 @@ public class VeeamClient {
this.taskPollInterval = taskPollInterval; this.taskPollInterval = taskPollInterval;
this.taskPollMaxRetry = taskPollMaxRetry; this.taskPollMaxRetry = taskPollMaxRetry;
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final RequestConfig config = RequestConfig.custom() final RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000) .setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000) .setConnectionRequestTimeout(timeout * 1000)
@ -233,8 +236,7 @@ public class VeeamClient {
private HttpResponse post(final String path, final Object obj) throws IOException { private HttpResponse post(final String path, final Object obj) throws IOException {
String xml = null; String xml = null;
if (obj != null) { if (obj != null) {
XmlMapper xmlMapper = new XmlMapper(); xml = OBJECT_MAPPER.writer()
xml = xmlMapper.writer()
.with(ToXmlGenerator.Feature.WRITE_XML_DECLARATION) .with(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
.writeValueAsString(obj); .writeValueAsString(obj);
// Remove invalid/empty xmlns // Remove invalid/empty xmlns
@ -277,8 +279,7 @@ public class VeeamClient {
try { try {
final HttpResponse response = get("/hierarchyRoots"); final HttpResponse response = get("/hierarchyRoots");
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); final EntityReferences references = OBJECT_MAPPER.readValue(response.getEntity().getContent(), EntityReferences.class);
final EntityReferences references = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
for (final Ref ref : references.getRefs()) { for (final Ref ref : references.getRefs()) {
if (ref.getName().equals(vmwareDcName) && ref.getType().equals(HIERARCHY_ROOT_REFERENCE)) { if (ref.getName().equals(vmwareDcName) && ref.getType().equals(HIERARCHY_ROOT_REFERENCE)) {
return ref.getUid(); return ref.getUid();
@ -297,8 +298,7 @@ public class VeeamClient {
try { try {
final HttpResponse response = get(String.format("/lookup?host=%s&type=Vm&name=%s", hierarchyId, vmName)); final HttpResponse response = get(String.format("/lookup?host=%s&type=Vm&name=%s", hierarchyId, vmName));
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); final HierarchyItems items = OBJECT_MAPPER.readValue(response.getEntity().getContent(), HierarchyItems.class);
final HierarchyItems items = objectMapper.readValue(response.getEntity().getContent(), HierarchyItems.class);
if (items == null || items.getItems() == null || items.getItems().isEmpty()) { if (items == null || items.getItems() == null || items.getItems().isEmpty()) {
throw new CloudRuntimeException("Could not find VM " + vmName + " in Veeam, please ask administrator to check Veeam B&R manager"); throw new CloudRuntimeException("Could not find VM " + vmName + " in Veeam, please ask administrator to check Veeam B&R manager");
} }
@ -316,14 +316,12 @@ public class VeeamClient {
private Task parseTaskResponse(HttpResponse response) throws IOException { private Task parseTaskResponse(HttpResponse response) throws IOException {
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); return OBJECT_MAPPER.readValue(response.getEntity().getContent(), Task.class);
return objectMapper.readValue(response.getEntity().getContent(), Task.class);
} }
protected RestoreSession parseRestoreSessionResponse(HttpResponse response) throws IOException { protected RestoreSession parseRestoreSessionResponse(HttpResponse response) throws IOException {
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); return OBJECT_MAPPER.readValue(response.getEntity().getContent(), RestoreSession.class);
return objectMapper.readValue(response.getEntity().getContent(), RestoreSession.class);
} }
private boolean checkTaskStatus(final HttpResponse response) throws IOException { private boolean checkTaskStatus(final HttpResponse response) throws IOException {
@ -410,8 +408,7 @@ public class VeeamClient {
String repositoryName = getRepositoryNameFromJob(backupName); String repositoryName = getRepositoryNameFromJob(backupName);
final HttpResponse response = get(String.format("/backupServers/%s/repositories", backupServerId)); final HttpResponse response = get(String.format("/backupServers/%s/repositories", backupServerId));
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); final EntityReferences references = OBJECT_MAPPER.readValue(response.getEntity().getContent(), EntityReferences.class);
final EntityReferences references = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
for (final Ref ref : references.getRefs()) { for (final Ref ref : references.getRefs()) {
if (ref.getType().equals(REPOSITORY_REFERENCE) && ref.getName().equals(repositoryName)) { if (ref.getType().equals(REPOSITORY_REFERENCE) && ref.getName().equals(repositoryName)) {
return ref; return ref;
@ -447,8 +444,7 @@ public class VeeamClient {
try { try {
final HttpResponse response = get("/backups"); final HttpResponse response = get("/backups");
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); final EntityReferences entityReferences = OBJECT_MAPPER.readValue(response.getEntity().getContent(), EntityReferences.class);
final EntityReferences entityReferences = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
for (final Ref ref : entityReferences.getRefs()) { for (final Ref ref : entityReferences.getRefs()) {
logger.debug("Veeam Backup found, name: " + ref.getName() + ", uid: " + ref.getUid() + ", type: " + ref.getType()); logger.debug("Veeam Backup found, name: " + ref.getName() + ", uid: " + ref.getUid() + ", type: " + ref.getType());
} }
@ -463,8 +459,7 @@ public class VeeamClient {
try { try {
final HttpResponse response = get("/jobs"); final HttpResponse response = get("/jobs");
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); final EntityReferences entityReferences = OBJECT_MAPPER.readValue(response.getEntity().getContent(), EntityReferences.class);
final EntityReferences entityReferences = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
final List<BackupOffering> policies = new ArrayList<>(); final List<BackupOffering> policies = new ArrayList<>();
if (entityReferences == null || entityReferences.getRefs() == null) { if (entityReferences == null || entityReferences.getRefs() == null) {
return policies; return policies;
@ -486,9 +481,7 @@ public class VeeamClient {
final HttpResponse response = get(String.format("/jobs/%s?format=Entity", final HttpResponse response = get(String.format("/jobs/%s?format=Entity",
jobId.replace("urn:veeam:Job:", ""))); jobId.replace("urn:veeam:Job:", "")));
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); return OBJECT_MAPPER.readValue(response.getEntity().getContent(), Job.class);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper.readValue(response.getEntity().getContent(), Job.class);
} catch (final IOException e) { } catch (final IOException e) {
logger.error("Failed to list Veeam jobs due to:", e); logger.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e); checkResponseTimeOut(e);
@ -568,9 +561,7 @@ public class VeeamClient {
final String veeamVmRefId = lookupVM(hierarchyId, vmwareInstanceName); final String veeamVmRefId = lookupVM(hierarchyId, vmwareInstanceName);
final HttpResponse response = get(String.format("/jobs/%s/includes", jobId)); final HttpResponse response = get(String.format("/jobs/%s/includes", jobId));
checkResponseOK(response); checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper(); final ObjectsInJob jobObjects = OBJECT_MAPPER.readValue(response.getEntity().getContent(), ObjectsInJob.class);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final ObjectsInJob jobObjects = objectMapper.readValue(response.getEntity().getContent(), ObjectsInJob.class);
if (jobObjects == null || jobObjects.getObjects() == null) { if (jobObjects == null || jobObjects.getObjects() == null) {
logger.warn("No objects found in the Veeam job " + jobId); logger.warn("No objects found in the Veeam job " + jobId);
return false; return false;
@ -710,8 +701,7 @@ public class VeeamClient {
protected Map<String, Backup.Metric> processHttpResponseForBackupMetrics(final InputStream content) { protected Map<String, Backup.Metric> processHttpResponseForBackupMetrics(final InputStream content) {
Map<String, Backup.Metric> metrics = new HashMap<>(); Map<String, Backup.Metric> metrics = new HashMap<>();
try { try {
final ObjectMapper objectMapper = new XmlMapper(); final BackupFiles backupFiles = OBJECT_MAPPER.readValue(content, BackupFiles.class);
final BackupFiles backupFiles = objectMapper.readValue(content, BackupFiles.class);
if (backupFiles == null || CollectionUtils.isEmpty(backupFiles.getBackupFiles())) { if (backupFiles == null || CollectionUtils.isEmpty(backupFiles.getBackupFiles())) {
throw new CloudRuntimeException("Could not get backup metrics via Veeam B&R API"); throw new CloudRuntimeException("Could not get backup metrics via Veeam B&R API");
} }
@ -855,8 +845,7 @@ public class VeeamClient {
public List<Backup.RestorePoint> processHttpResponseForVmRestorePoints(InputStream content, String vmwareDcName, String vmInternalName, Map<String, Backup.Metric> metricsMap) { public List<Backup.RestorePoint> processHttpResponseForVmRestorePoints(InputStream content, String vmwareDcName, String vmInternalName, Map<String, Backup.Metric> metricsMap) {
List<Backup.RestorePoint> vmRestorePointList = new ArrayList<>(); List<Backup.RestorePoint> vmRestorePointList = new ArrayList<>();
try { try {
final ObjectMapper objectMapper = new XmlMapper(); final VmRestorePoints vmRestorePoints = OBJECT_MAPPER.readValue(content, VmRestorePoints.class);
final VmRestorePoints vmRestorePoints = objectMapper.readValue(content, VmRestorePoints.class);
final String hierarchyId = findDCHierarchy(vmwareDcName); final String hierarchyId = findDCHierarchy(vmwareDcName);
final String hierarchyUuid = StringUtils.substringAfterLast(hierarchyId, ":"); final String hierarchyUuid = StringUtils.substringAfterLast(hierarchyId, ":");
if (vmRestorePoints == null) { if (vmRestorePoints == null) {
@ -907,7 +896,7 @@ public class VeeamClient {
} }
private Date formatDate(String date) throws ParseException { private Date formatDate(String date) throws ParseException {
return dateFormat.parse(StringUtils.substring(date, 0, 19)); return DATE_FORMAT.parse(StringUtils.substring(date, 0, 19));
} }
public Pair<Boolean, String> restoreVMToDifferentLocation(String restorePointId, String restoreLocation, String hostIp, String dataStoreUuid) { public Pair<Boolean, String> restoreVMToDifferentLocation(String restorePointId, String restoreLocation, String hostIp, String dataStoreUuid) {

View File

@ -483,7 +483,9 @@ public class VeeamClientTest {
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xmlns=\"http://www.veeam.com/ent/v1.0\">\n" + " xmlns=\"http://www.veeam.com/ent/v1.0\">\n" +
" <VmRestorePoint Href=\"https://10.0.3.142:9398/api/vmRestorePoints/f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977?format=Entity\" Type=\"VmRestorePoint\" Name=\"i-2-4-VM@2023-11-03 16:26:12.209913\" UID=\"urn:veeam:VmRestorePoint:f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977\" VmDisplayName=\"i-2-4-VM\">\n" + " <VmRestorePoint Href=\"https://10.0.3.142:9398/api/vmRestorePoints/f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977?format=Entity\"" +
" Type=\"VmRestorePoint\" Name=\"i-2-4-VM@2023-11-03 16:26:12.209913\" UID=\"urn:veeam:VmRestorePoint:f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977\"" +
" VmDisplayName=\"i-2-4-VM\" SqlInfo=\"SqlInfo\">\n" +
" <Links>\n" + " <Links>\n" +
" <Link Href=\"https://10.0.3.142:9398/api/vmRestorePoints/f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977?action=restore\" Rel=\"Restore\" />\n" + " <Link Href=\"https://10.0.3.142:9398/api/vmRestorePoints/f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977?action=restore\" Rel=\"Restore\" />\n" +
" <Link Href=\"https://10.0.3.142:9398/api/backupServers/18cc2a81-1ff0-42cd-8389-62f2bbcc6b7f\" Name=\"10.0.3.142\" Type=\"BackupServerReference\" Rel=\"Up\" />\n" + " <Link Href=\"https://10.0.3.142:9398/api/backupServers/18cc2a81-1ff0-42cd-8389-62f2bbcc6b7f\" Name=\"10.0.3.142\" Type=\"BackupServerReference\" Rel=\"Up\" />\n" +

View File

@ -695,7 +695,12 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
updateTemplateRef(templateId, poolId, templatePath, templateSize); updateTemplateRef(templateId, poolId, templatePath, templateSize);
return templateId; return templateId;
} else { } else {
return volumeVO.getTemplateId(); Long templateId = volumeVO.getTemplateId();
if (templateId == null && volumeVO.getInstanceId() != null) {
VMInstanceVO vmInstanceVO = vmDao.findByIdIncludingRemoved(volumeVO.getInstanceId());
return vmInstanceVO.getTemplateId();
}
return templateId;
} }
} }
} }

View File

@ -61,7 +61,7 @@ public interface KubernetesClusterService extends PluggableService, Configurable
"cloud.kubernetes.cluster.network.offering", "cloud.kubernetes.cluster.network.offering",
"DefaultNetworkOfferingforKubernetesService", "DefaultNetworkOfferingforKubernetesService",
"Name of the network offering that will be used to create isolated network in which Kubernetes cluster VMs will be launched", "Name of the network offering that will be used to create isolated network in which Kubernetes cluster VMs will be launched",
false, true,
KubernetesServiceEnabled.key()); KubernetesServiceEnabled.key());
static final ConfigKey<Long> KubernetesClusterStartTimeout = new ConfigKey<Long>("Advanced", Long.class, static final ConfigKey<Long> KubernetesClusterStartTimeout = new ConfigKey<Long>("Advanced", Long.class,
"cloud.kubernetes.cluster.start.timeout", "cloud.kubernetes.cluster.start.timeout",