Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
140 commits
Select commit Hold shift + click to select a range
3547791
<fix>[migration]: fix failed to start vm after ceph to ceph offline m…
Dec 22, 2025
a648c38
<fix>[utils]: add ORG_ZSTACK_AI_10134 error code for GPU count valida…
AlanJager Feb 19, 2026
800d01d
<fix>[tag]: add resourceType field to TagPatternVO
AlanJager Feb 19, 2026
6804eca
<fix>[tag]: complete resourceType scoping for TagPatternVO
AlanJager Feb 24, 2026
7e34564
<chore>[sdk]: Update sdk
AlanJager Feb 25, 2026
944c7a8
<fix>[storage]: honor force flag to clean image cache for existing im…
AlanJager Mar 1, 2026
a5906f0
<fix>[accesskey]: support AccessKey type distinction
liang-hanyu Mar 5, 2026
931d8d9
<fix>[securityGroup]: relax priority constraints in SG rule API
AlanJager Mar 8, 2026
3a6ad0f
Merge branch 'fix-82022@@2' into '5.5.12'
Mar 9, 2026
1bba30b
<fix>[db]: change VARCHAR(4096) to MEDIUMTEXT in Json_getKeyValue fun…
AlanJager Mar 9, 2026
16db51f
<feature>[core]: support configure external service
littleya Jan 18, 2026
241090b
<feature>[longjob]: standardize LongJob progress detail format
AlanJager Mar 10, 2026
12a4db3
<fix>[lb]: intercept httpCompressAlgos::disable tag
AlanJager Mar 8, 2026
d2020c5
Merge branch 'fix/ZSTAC-79628' into '5.5.12'
Mar 10, 2026
4d3faa3
Merge branch 'feature-external-service-configuration@@2' into '5.5.12'
Mar 10, 2026
a83ae8b
Merge branch 'fix-ZSTAC-80468@@2' into '5.5.12'
Mar 11, 2026
708fc5e
<feature>[errorcode]: fix i18n gaps in copy ctor and SDK
AlanJager Mar 10, 2026
7b302df
<fix>[sharedblock]: convert memory snapshot install path from absolut…
Nov 11, 2025
1912469
Merge branch 'fix/ZSTAC-82980' into '5.5.12'
Mar 11, 2026
f94eff0
<fix>[core]: handle malformed Accept-Language header in LocaleUtils
AlanJager Mar 11, 2026
bc4090b
Merge branch 'fix-ZSTAC-79756@@2' into '5.5.12'
Mar 11, 2026
8117a99
Merge branch 'feature/errorcode-localized-message' into '5.5.12'
Mar 11, 2026
0bfbf45
<fix>[zwatch]: VPC Router CPU alarm use external monitoring
Feb 4, 2026
2e7d673
<fix>[pciDevice]: add Kunlunxin to SDK GpuVendor enum
AlanJager Mar 11, 2026
c7e7de8
<fix>[test]: fix SG test cases: relax priority consecutive constraint…
AlanJager Mar 11, 2026
7e2fe2e
Merge branch 'fix/ZSTAC-80991@@2' into '5.5.12'
Mar 11, 2026
b8d643d
Merge branch 'ZSTAC-79949@@2' into '5.5.12'
Mar 12, 2026
67acc0a
<feature>[core]: support resnotify webhook infrastructure
PandaWuu Mar 12, 2026
681a301
Merge branch 'fix/ZSTAC-82350@@2' into '5.5.12'
Mar 12, 2026
d30e086
<fix>[i18n]: fix error code 10049/10050 translations
PandaWuu Mar 12, 2026
648fc77
<feature>[sdk]: add Kunlunxin to GpuVendor enum for P800 GPU support
AlanJager Mar 10, 2026
855acac
Merge branch 'bugfix/ZSTAC-72656' into '5.5.12'
Mar 12, 2026
f5459df
<feature>[core]: add resnotify webhook SDK and test support
PandaWuu Mar 12, 2026
7acb58e
Merge branch 'fix/ZSTAC-81706' into '5.5.12'
Mar 13, 2026
c3ed9d0
Merge branch 'fix/ZSTAC-82259-gpu-vendor@@2' into '5.5.12'
Mar 13, 2026
44c191f
Merge branch 'feature/ZSTAC-80472@@2' into '5.5.12'
Mar 13, 2026
cb554df
<fix>[sdk]: update SDK files for LongJobProgressDetail
AlanJager Mar 11, 2026
2318947
<feature>[dpu-bm2]: support dpu baremetal2 instance
Jan 13, 2026
ecc93eb
<fix>[iscsi]: use platform compact hostId instead of storage bdc id f…
AlanJager Mar 5, 2026
c1f6673
Merge branch 'fix/ZSTAC-79067@@2' into '5.5.12'
Mar 13, 2026
26df079
Merge branch 'fix/ZSTAC-82318' into '5.5.12'
Mar 13, 2026
e00e19c
Merge branch 'feature-dpu-baremetal@@2' into '5.5.12'
Mar 14, 2026
62cd882
<fix>[conf]: bump version to 5.5.12
liang-hanyu Mar 16, 2026
0f4c337
Merge branch 'bump-version-5.5.12' into '5.5.12'
Mar 16, 2026
aaf4e34
<feature>[errorcode]: simplify i18n — guarantee message is never null
AlanJager Mar 16, 2026
1d8a059
<fix>[ai]: add targetQueueKey column for eval task queuing
AlanJager Mar 9, 2026
34366a1
<fix>[conf]: use absolute path for ansible version check during upgrade
MaJin1996 Mar 16, 2026
327b1cc
Merge branch 'fix/ZSTAC-82619' into '5.5.12'
MaJin1996 Mar 16, 2026
39a9a84
<feature>[longjob]: standardize progress detail fields to be unit-agn…
AlanJager Mar 16, 2026
dc67d72
<fix>[header]: fix __example__ method names for LongJobProgressDetail
AlanJager Mar 16, 2026
ed8c99b
<fix>[conf]: retry rm -rf virtualenv to avoid race with zstack_servic…
MaJin1996 Mar 16, 2026
d27439a
<fix>[vmScheduling]: change GET scheduling APIs from POST to GET meth…
AlanJager Mar 16, 2026
b154bc1
Merge branch 'fix/ZSTAC-82318-phase2' into '5.5.12'
Mar 16, 2026
3b4d09e
Merge branch 'fix/ZSTAC-68709-eval-queue@@2' into '5.5.12'
Mar 17, 2026
1dc68d2
<fix>[errorcode]: revert sendReplyResponse to use JSONObjectUtil seri…
AlanJager Mar 17, 2026
5ffa56e
<fix>[network]: set nic ip out of l3 cidr scope
ruansteve Feb 5, 2026
44aec19
<fix>[l2network]: validate physicalInterface for LinuxBridge
ruansteve Mar 17, 2026
262e92a
Merge branch 'fix/ZSTAC-81797@@2' into '5.5.12'
Mar 17, 2026
80b93d6
Merge branch 'fix/ZSTAC-82619' into '5.5.12'
Mar 17, 2026
d993609
Merge branch 'shixin-ZSTAC-83150@@2' into '5.5.12'
Mar 17, 2026
76044ca
<fix>[docs]: move to zstack/docs
ruansteve Mar 17, 2026
f32fb96
<fix>[errorcode]: address review — null-safe message fallback and avo…
AlanJager Mar 17, 2026
8f31252
Merge branch 'fix/ZSTAC-71075@@2' into '5.5.12'
Mar 17, 2026
d0ccc44
Merge branch 'feature/errorcode-i18n-simplify' into '5.5.12'
Mar 18, 2026
3feb9e9
<feature>[kvm]: add libvirt TLS config
huhu0316 Mar 11, 2026
69ae62a
Merge branch 'shixin-ZSTAC-81969' into '5.5.12'
Mar 18, 2026
e0a8246
Merge branch 'shixin-ZSTAC-83300' into '5.5.12'
Mar 18, 2026
f15be32
Merge branch 'ZSTAC-81343@@2' into '5.5.12'
PandaWuu Mar 18, 2026
7b6ceea
<fix>[core,kvm]: fix SSH session leak in CallBackNetworkChecker and K…
MaJin1996 Mar 19, 2026
9349cab
<fix>[compute]: cancel backup longjobs before migration
AlanJager Mar 19, 2026
b42842c
Merge branch 'fix/ZSTAC-83305' into '5.5.12'
MaJin1996 Mar 19, 2026
ec18635
<feature>[zwatch]: add OVN instance default alarms
Mar 16, 2026
046d023
<fix>[compute]: fix user define param error
ruansteve Mar 18, 2026
2b7d21c
Merge branch 'shixin-ZSTAC-83321' into '5.5.12'
Mar 20, 2026
5fb0b34
Merge branch 'ZSTAC-73154-2@@2' into '5.5.12'
Mar 20, 2026
831fdf4
<fix>[test]: fix TagPatternResourceTypeCase CI failure
AlanJager Mar 23, 2026
d9f0d4d
<fix>[storage]: return defensive copy from getPreferBackupStorageTypes
MaJin1996 Mar 24, 2026
98da047
Merge branch 'fix/ZSTAC-74908@@2' into '5.5.12'
Mar 24, 2026
6d177d4
<fix>[schema]: move TagPatternVO.resourceType migration to V5.5.12
AlanJager Mar 24, 2026
06621e2
Merge branch 'fix/ZSTAC-74908@@3' into '5.5.12'
AlanJager Mar 24, 2026
8f58fad
Merge branch 'fix/ZSTAC-80789' into '5.5.12'
MaJin1996 Mar 24, 2026
48e5b3e
<fix>[sdk]: add force field to SetIAM2ProjectContainerClusterAction
Mar 26, 2026
c4c23a6
Merge branch 'fix/ZSTAC-82195-migrate-cancel-backup@@2' into '5.5.12'
Mar 27, 2026
fd33719
Merge branch 'fix-ZSTAC-80406-lost-project@@2' into '5.5.12'
Mar 30, 2026
993afb1
<feature>[dpu-bm2]: support dpu bm2 instance
Mar 23, 2026
fa71055
<fix>[conf]: MySQL timeout is not defined
qiuqiuqiuyu Mar 30, 2026
226b20b
Merge branch 'feature-dpu-baremetal@@2' into '5.5.12'
Mar 30, 2026
78389bb
<fix>[compute]: handle empty string dstHostUuid in host allocator
PandaWuu Mar 30, 2026
47efb85
Merge branch 'bugfix/ZSTAC-83733@@2' into '5.5.12'
Mar 31, 2026
ee3f541
<fix>[plugin-premium]: Reparing GPU/VM page keeps loading when shutti…
Dec 17, 2025
3c8bc53
<feature>[pci-device]: add SDK for UpdateVmInstancePciDeviceSpecRef API
AlanJager Mar 31, 2026
ee4b6be
<fix>[compute]: fix VM clone quota check fail
Mar 27, 2026
1f6e0b3
Merge branch 'ZSTAC-83499' into '5.5.12'
Mar 31, 2026
62e8c17
Merge branch 'fix-ZSTAC-80202-zaku-loading@@2' into '5.5.12'
Apr 1, 2026
7ea5aad
<fix>[kvm]: pass guestOsType to kvmagent for SMBIOS auto-configuration
gladtoseeu Apr 1, 2026
4f895c3
<fix>[testlib]: make Python SDK template compatible with Python 3
MaJin1996 Apr 2, 2026
3bcfed2
Merge branch 'fix/pysdk-python3-compat' into '5.5.12'
MaJin1996 Apr 2, 2026
61174c8
fix(kvm): disable PMU on aarch64 for Kunpeng-920 panic
gladtoseeu Mar 30, 2026
12e7494
<fix>[pci-device]: update SDK for UpdateVmInstancePciDeviceSpecRef API
AlanJager Apr 2, 2026
d2941ba
Merge branch 'fix/ZSTAC-71156@@2' into '5.5.12'
Apr 2, 2026
7bf9cdf
Merge branch 'fix/5.5.12/ZSTAC-76375@@3' into '5.5.12'
Apr 3, 2026
17a0ec8
<fix>[testlib]: fix multiple bugs in Python SDK template
MaJin1996 Apr 2, 2026
87171ab
<fix>[identity]: restrict APIQueryAccountMsg to admin-only in RBAC
gladtoseeu Apr 3, 2026
067496b
Merge branch 'fix/ZSTAC-83960' into '5.5.12'
Apr 3, 2026
e2e0f8f
Merge branch 'fix/ZSTAC-81735@@2' into '5.5.12'
Apr 3, 2026
39bd705
<fix>[testlib]: add updateVmInstancePciDeviceSpecRef to ApiHelper
AlanJager Apr 3, 2026
933931f
Merge branch 'huangtian-ZSTAC-83646@@2' into '5.5.12'
Apr 7, 2026
61f5657
<feature>[build]: auto-detect worktree .m2
MaJin1996 Apr 7, 2026
179dfbf
<fix>[kvm]: prevent metadata deletion when DVD returns empty
PandaWuu Mar 31, 2026
1469927
Merge branch 'fix/runMavenProfile-m2-isolation' into '5.5.12'
Apr 7, 2026
73ca9d8
Merge branch 'fix/ZSTAC-71156@@2' into '5.5.12'
Apr 8, 2026
4cad7ec
Merge branch 'fix/pysdk-poll-url-rewrite' into '5.5.12'
MaJin1996 Apr 9, 2026
8472bf2
<feature>[sdk]: add requestCpu and add errCode
Mar 9, 2026
c85fab3
<fix>[kvm]: update TLS certs via kvmagent on host reconnect
huhu0316 Apr 7, 2026
218124f
Merge branch 'ZSTAC-83696@@2' into '5.5.12'
Apr 10, 2026
2b60783
Merge branch 'feat/ZSTAC-80103@@2' into '5.5.12'
Apr 10, 2026
eebc543
<feature>[build]: add .m2 to gitignore
MaJin1996 Apr 10, 2026
ce1ed60
Merge branch 'fix/runMavenProfile-m2-isolation' into '5.5.12'
MaJin1996 Apr 10, 2026
a04cd58
<feature>[vpc]: support snat log with LogServer
bustezero Feb 3, 2026
bb1df03
Merge branch 'bugfix/ZSTAC-83682@@2' into '5.5.12'
Apr 13, 2026
fc3df1f
<feature>[sdk]: support dgpu
Apr 3, 2026
8ca173f
Revert "Merge branch 'fix/ZSTAC-79709' into '5.5.12'"
PandaWuu Apr 13, 2026
31c9680
<feature>[thread]: support coalesce queue for batch dhcp
MaJin1996 Apr 13, 2026
291e145
Merge branch 'fix/ZSTAC-83039' into '5.5.12'
MaJin1996 Apr 13, 2026
cc67dc0
Merge branch 'revert-e1dee9ff' into '5.5.12'
PandaWuu Apr 14, 2026
659c296
<fix>[kvm]: use SSH cert check + ansible deploy instead of kvmagent H…
huhu0316 Apr 13, 2026
fd5cea1
Merge branch 'feature-snat-log-5.5.12-final@@2' into '5.5.12'
ruansteve Apr 14, 2026
bcb77ba
<fix>[kvm]: normalize osVersion when matching DVD metadata
PandaWuu Apr 14, 2026
a76c54d
Merge branch '5.5.16@@2' into '5.5.12'
Apr 14, 2026
41d127f
Merge branch 'ZSTAC-83696@@2' into '5.5.12'
Apr 14, 2026
22f714f
<fix>[thread]: remove redundant try-catch in CoalesceQueue and fix nu…
MaJin1996 Apr 14, 2026
19b3546
<fix>[sdk]: add shareType field to GPU query APIs
Mar 20, 2026
99ae62e
<fix>[conf]: bump version to 5.5.16
liang-hanyu Apr 15, 2026
241c626
Merge branch 'fix-84259' into '5.5.16'
Apr 15, 2026
d9efb52
Merge branch 'fix/ZSTAC-83039' into '5.5.16'
MaJin1996 Apr 15, 2026
10bae7a
Merge branch 'fix/ZSTAC-82599@@2' into '5.5.16'
Apr 15, 2026
2042399
Merge branch 'bugfix/ZSTAC-83682-reopen@@2' into '5.5.16'
Apr 16, 2026
1f69b47
<feature>[kvm]: user vm mount model
Mar 26, 2026
d913f84
<fix>[conf]: add errorcode and sql
Mar 29, 2026
ade3fb7
<fix>[conf]: Add ORG_ZSTACK_AI_10158 error code"
Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ envDSLTree
test/zstack-integration-test-result/
premium/test-premium/zstack-api.log
**/bin/
CLAUDE.md
.claude/*
.m2/
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
MAJOR=5
MINOR=5
UPDATE=6
UPDATE=16
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.zstack.compute.allocator;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
Expand Down Expand Up @@ -81,30 +82,44 @@ public void allocate() {
List<String> clusterUuids = (List<String>) spec.getExtraData().get(HostAllocatorConstant.LocationSelector.cluster);
String hostUuid = (String) spec.getExtraData().get(HostAllocatorConstant.LocationSelector.host);

if (zoneUuid == null && CollectionUtils.isEmpty(clusterUuids) && hostUuid == null && spec.getHypervisorType() == null) {
String hypervisorType = spec.getHypervisorType();

// normalize empty strings to null — treat empty string as "not specified"
zoneUuid = StringUtils.isEmpty(zoneUuid) ? null : zoneUuid;
hostUuid = StringUtils.isEmpty(hostUuid) ? null : hostUuid;
hypervisorType = StringUtils.isEmpty(hypervisorType) ? null : hypervisorType;
if (!CollectionUtils.isEmpty(clusterUuids)) {
clusterUuids = new ArrayList<>(clusterUuids);
clusterUuids.removeIf(s -> s == null || s.isEmpty());
if (clusterUuids.isEmpty()) {
clusterUuids = null;
}
}

if (zoneUuid == null && CollectionUtils.isEmpty(clusterUuids) && hostUuid == null && hypervisorType == null) {
next(candidates);
return;
}

if (amITheFirstFlow()) {
candidates = allocate(zoneUuid, clusterUuids, hostUuid, spec.getHypervisorType());
candidates = allocate(zoneUuid, clusterUuids, hostUuid, hypervisorType);
} else {
candidates = allocate(candidates, zoneUuid, clusterUuids, hostUuid, spec.getHypervisorType());
candidates = allocate(candidates, zoneUuid, clusterUuids, hostUuid, hypervisorType);
}

if (candidates.isEmpty()) {
StringBuilder args = new StringBuilder();
if (zoneUuid != null) {
args.append(String.format("zoneUuid=%s", zoneUuid)).append(" ");
}
if (!clusterUuids.isEmpty()) {
if (!CollectionUtils.isEmpty(clusterUuids)) {
args.append(String.format("clusterUuid in %s", clusterUuids)).append(" ");
}
if (hostUuid != null) {
args.append(String.format("hostUuid=%s", hostUuid)).append(" ");
}
if (spec.getHypervisorType() != null) {
args.append(String.format("hypervisorType=%s", spec.getHypervisorType())).append(" ");
if (hypervisorType != null) {
args.append(String.format("hypervisorType=%s", hypervisorType)).append(" ");
}
fail(Platform.operr(ORG_ZSTACK_COMPUTE_ALLOCATOR_10036, "No host with %s found", args));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.compute.vm.VmQuotaOperator;
import org.zstack.header.allocator.AbstractHostAllocatorFlow;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.identity.AccountConstant;
import org.zstack.identity.Account;
import org.zstack.identity.QuotaUtil;
Expand Down Expand Up @@ -51,6 +53,12 @@ public void allocate() {
}

throwExceptionIfIAmTheFirstFlow();
// skip checkquota if the operator is admin
String currentAccountUuid = spec.getAccountUuid();
if (currentAccountUuid != null && AccountConstant.isAdminPermission(currentAccountUuid)) {
next(candidates);
return;
}

final String vmInstanceUuid = spec.getVmInstance().getUuid();
final String accountUuid = Account.getAccountUuidOfResource(vmInstanceUuid);
Expand All @@ -60,21 +68,27 @@ public void allocate() {
}

if (!spec.isFullAllocate()) {
new VmQuotaOperator().checkVmCupAndMemoryCapacity(accountUuid,
ErrorCode error = new VmQuotaOperator().checkVmCupAndMemoryCapacityWithResult(accountUuid,
accountUuid,
spec.getCpuCapacity(),
spec.getMemoryCapacity(),
new QuotaUtil().makeQuotaPairs(accountUuid));
if (error != null) {
throw new OperationFailureException(error);
}

next(candidates);
return;
}

new VmQuotaOperator().checkVmInstanceQuota(
ErrorCode error = new VmQuotaOperator().checkVmInstanceQuotaWithResult(
accountUuid,
accountUuid,
vmInstanceUuid,
new QuotaUtil().makeQuotaPairs(accountUuid));
if (error != null) {
throw new OperationFailureException(error);
}
next(candidates);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ public class HostManagerImpl extends AbstractService implements HostManager, Man
private Future reportHostCapacityTask;
private Future refreshHostPowerStatusTask;

private static final List<String> SKIP_ARCH_CHECK_HYPERVISOR_TYPES = Arrays.asList("baremetal2", "baremetal2Dpu");

static {
allowedMessageAfterSoftDeletion.add(HostDeletionMsg.class);
}
Expand Down Expand Up @@ -472,7 +474,7 @@ public void run(MessageReply reply) {
@Override
public boolean skip(Map data) {
// no need to check baremetal2 gateway architecture with the cluster architecture
return vo.getHypervisorType().equals("baremetal2");
return SKIP_ARCH_CHECK_HYPERVISOR_TYPES.contains(cluster.getHypervisorType());
}

@Override
Expand Down
157 changes: 150 additions & 7 deletions compute/src/main/java/org/zstack/compute/vm/MigrateVmLongJob.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
package org.zstack.compute.vm;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.Platform;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.thread.ThreadFacade;
import org.zstack.header.Constants;
import org.zstack.header.core.Completion;
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.longjob.LongJobErrors;
import org.zstack.header.longjob.LongJobFor;
import org.zstack.header.longjob.LongJobVO;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.longjob.*;
import org.zstack.header.message.APIEvent;
import org.zstack.header.message.MessageReply;
import org.zstack.header.vm.*;
import org.zstack.header.longjob.LongJob;
import org.zstack.longjob.LongJobUtils;
import org.zstack.header.volume.GetVolumeTaskMsg;
import org.zstack.header.volume.GetVolumeTaskReply;
import org.zstack.header.volume.VolumeConstant;
import org.zstack.header.volume.VolumeVO;
import org.zstack.header.volume.VolumeVO_;
import org.zstack.utils.gson.JSONObjectUtil;

import static org.zstack.core.Platform.err;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static org.zstack.core.Platform.operr;


Expand All @@ -31,16 +38,152 @@
@LongJobFor(APIMigrateVmMsg.class)
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class MigrateVmLongJob implements LongJob {
private static final Logger logger = LogManager.getLogger(MigrateVmLongJob.class);
private static final int WAIT_CHAIN_TASK_EXIT_MAX_RETRIES = 30;
private static final long WAIT_CHAIN_TASK_EXIT_INTERVAL_SECS = 1;

@Autowired
protected CloudBus bus;
@Autowired
protected DatabaseFacade dbf;
@Autowired
private ThreadFacade thdf;

protected String auditResourceUuid;

@Override
public void start(LongJobVO job, ReturnValueCompletion<APIEvent> completion) {
MigrateVmInnerMsg msg = JSONObjectUtil.toObject(job.getJobData(), MigrateVmInnerMsg.class);

List<String> backupTaskLongJobUuids = getBackupTaskLongJobUuids(job.getJobData());
if (backupTaskLongJobUuids != null && !backupTaskLongJobUuids.isEmpty()) {
logger.info(String.format("migrate vm[uuid:%s] longjob has %d backup longjobs to cancel first",
msg.getVmInstanceUuid(), backupTaskLongJobUuids.size()));
cancelBackupLongJobsThenMigrate(backupTaskLongJobUuids, msg, completion);
} else {
doMigrate(msg, completion);
}
}

private List<String> getBackupTaskLongJobUuids(String jobData) {
Map<String, Object> raw = JSONObjectUtil.toObject(jobData, LinkedHashMap.class);
Object uuids = raw == null ? null : raw.get("backupTaskLongJobUuids");
if (!(uuids instanceof List<?>)) {
return null;
}

List<String> result = new ArrayList<>();
for (Object item : (List<?>) uuids) {
if (item == null) {
continue;
}
String uuid = String.valueOf(item).trim();
if (!uuid.isEmpty()) {
result.add(uuid);
}
}
return result.isEmpty() ? null : result;
}

private void cancelBackupLongJobsThenMigrate(List<String> backupTaskLongJobUuids,
MigrateVmInnerMsg msg,
ReturnValueCompletion<APIEvent> completion) {
cancelBackupLongJobs(backupTaskLongJobUuids.iterator(), new Completion(completion) {
@Override
public void success() {
waitForVolumeChainTasksExit(msg.getVmInstanceUuid(), WAIT_CHAIN_TASK_EXIT_MAX_RETRIES,
new Completion(completion) {
@Override
public void success() {
doMigrate(msg, completion);
}

@Override
public void fail(ErrorCode errorCode) {
completion.fail(errorCode);
}
});
}

@Override
public void fail(ErrorCode errorCode) {
logger.warn(String.format("failed to cancel backup longjobs for vm[uuid:%s], " +
"attempting migration anyway: %s", msg.getVmInstanceUuid(), errorCode));
doMigrate(msg, completion);
}
});
}

private void cancelBackupLongJobs(Iterator<String> it, Completion completion) {
if (!it.hasNext()) {
completion.success();
return;
}

String longJobUuid = it.next();
CancelLongJobMsg cmsg = new CancelLongJobMsg();
cmsg.setUuid(longJobUuid);
bus.makeLocalServiceId(cmsg, LongJobConstants.SERVICE_ID);
bus.send(cmsg, new CloudBusCallBack(completion) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
logger.warn(String.format("failed to cancel backup longjob[uuid:%s]: %s",
longJobUuid, reply.getError()));
}
cancelBackupLongJobs(it, completion);
}
});
}

private void waitForVolumeChainTasksExit(String vmUuid, int retriesLeft, Completion completion) {
List<String> volUuids = Q.New(VolumeVO.class)
.eq(VolumeVO_.vmInstanceUuid, vmUuid)
.select(VolumeVO_.uuid)
.listValues();

if (volUuids.isEmpty()) {
completion.success();
return;
}

GetVolumeTaskMsg gmsg = new GetVolumeTaskMsg();
gmsg.setVolumeUuids(volUuids);
bus.makeLocalServiceId(gmsg, VolumeConstant.SERVICE_ID);
bus.send(gmsg, new CloudBusCallBack(completion) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
completion.fail(reply.getError());
return;
}

GetVolumeTaskReply gr = reply.castReply();
boolean hasRunningTasks = gr.getResults().values().stream()
.anyMatch(info -> !info.getRunningTask().isEmpty());

if (!hasRunningTasks) {
completion.success();
return;
}

if (retriesLeft <= 0) {
completion.fail(operr(
"timeout waiting for volume backup chain tasks to exit for vm[uuid:%s]", vmUuid));
return;
}

logger.debug(String.format(
"volumes of vm[uuid:%s] still have running tasks, retry in %ds (retries left: %d)",
vmUuid, WAIT_CHAIN_TASK_EXIT_INTERVAL_SECS, retriesLeft));
thdf.submitTimeoutTask(
() -> waitForVolumeChainTasksExit(vmUuid, retriesLeft - 1, completion),
TimeUnit.SECONDS, WAIT_CHAIN_TASK_EXIT_INTERVAL_SECS);
}
});
}

private void doMigrate(MigrateVmInnerMsg msg, ReturnValueCompletion<APIEvent> completion) {
bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, msg.getVmInstanceUuid());
bus.send(msg, new CloudBusCallBack(completion) {
@Override
Expand Down
Loading