diff --git a/compute/src/main/java/org/zstack/compute/vm/UpdateVmInstanceMetadataGC.java b/compute/src/main/java/org/zstack/compute/vm/UpdateVmInstanceMetadataGC.java new file mode 100644 index 00000000000..eaf4b3dbe42 --- /dev/null +++ b/compute/src/main/java/org/zstack/compute/vm/UpdateVmInstanceMetadataGC.java @@ -0,0 +1,76 @@ +package org.zstack.compute.vm; + +import org.springframework.beans.factory.annotation.Autowired; +import org.zstack.core.cloudbus.CloudBusCallBack; +import org.zstack.core.gc.GC; +import org.zstack.core.gc.GCCompletion; +import org.zstack.core.gc.TimeBasedGarbageCollector; +import org.zstack.core.thread.ChainTask; +import org.zstack.core.thread.SyncTaskChain; +import org.zstack.core.thread.ThreadFacade; +import org.zstack.header.core.progress.ChainInfo; +import org.zstack.header.message.MessageReply; +import org.zstack.header.vm.UpdateVmInstanceMetadataMsg; +import org.zstack.header.volume.VolumeConstant; +import org.zstack.header.volume.VolumeVO; + +public class UpdateVmInstanceMetadataGC extends TimeBasedGarbageCollector { + @GC + public String vmInstanceUuid; + + @GC + public boolean detachBeforeDeleting; + + @GC + public String deletionPolicy; + + @Autowired + protected ThreadFacade thdf; + + @Override + protected void triggerNow(GCCompletion completion) { + if (!dbf.isExist(vmInstanceUuid, VolumeVO.class)) { + completion.cancel(); + return; + } + + + // 获取 更新元数据的队列 + // 检测到 有任务排在队列中,取消当前任务 + String queueName = String.format("update-vm-%s-metadata", vmInstanceUuid); + ChainInfo chainInfo = thdf.getChainTaskInfo(queueName); + if (!chainInfo.getPendingTask().isEmpty()) { + completion.cancel(); + return; + } + + thdf.chainSubmit(new ChainTask(completion) { + @Override + public String getSyncSignature() { + return queueName; + } + + @Override + public void run(final SyncTaskChain chain) { + UpdateVmInstanceMetadataMsg msg = new UpdateVmInstanceMetadataMsg(); + msg.setUuid(vmInstanceUuid); + bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, vmInstanceUuid); + bus.send(msg, new CloudBusCallBack(completion) { + @Override + public void run(MessageReply reply) { + if (!reply.isSuccess()) { + completion.fail(reply.getError()); + } else { + completion.success(); + } + } + }); + } + + @Override + public String getName() { + return queueName; + } + }); + } +} diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java index e31bc001218..e423bc3e2fc 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java @@ -13,6 +13,8 @@ import org.zstack.core.cascade.CascadeFacade; import org.zstack.core.cloudbus.*; import org.zstack.core.componentloader.PluginRegistry; +import org.zstack.core.config.GlobalConfig; +import org.zstack.core.config.GlobalConfigDefinition; import org.zstack.core.db.*; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.core.defer.Defer; @@ -45,6 +47,17 @@ import org.zstack.header.message.*; import org.zstack.header.network.l3.*; import org.zstack.header.storage.primary.*; +import org.zstack.header.storage.snapshot.VolumeSnapshotInventory; +import org.zstack.header.storage.snapshot.VolumeSnapshotVO; +import org.zstack.header.storage.snapshot.VolumeSnapshotVO_; +import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupRefVO; +import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupRefVO_; +import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupVO; +import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupVO_; +import org.zstack.header.tag.SystemTagVO; +import org.zstack.header.tag.SystemTagVO_; +import org.zstack.header.tag.TagDefinition; +import org.zstack.header.tag.TagType; import org.zstack.header.vm.*; import org.zstack.header.vm.ChangeVmMetaDataMsg.AtomicHostUuid; import org.zstack.header.vm.ChangeVmMetaDataMsg.AtomicVmState; @@ -66,15 +79,9 @@ import org.zstack.network.l3.L3NetworkManager; import org.zstack.network.service.DnsUtils; import org.zstack.network.service.NetworkServiceManager; -import org.zstack.resourceconfig.ResourceConfig; -import org.zstack.resourceconfig.ResourceConfigFacade; -import org.zstack.tag.SystemTagCreator; -import org.zstack.tag.SystemTagUtils; -import org.zstack.tag.TagManager; -import org.zstack.utils.CollectionUtils; -import org.zstack.utils.ExceptionDSL; -import org.zstack.utils.ObjectUtils; -import org.zstack.utils.Utils; +import org.zstack.resourceconfig.*; +import org.zstack.tag.*; +import org.zstack.utils.*; import org.zstack.utils.function.ForEachFunction; import org.zstack.utils.function.Function; import org.zstack.utils.gson.JSONObjectUtil; @@ -87,6 +94,7 @@ import javax.persistence.PersistenceException; import javax.persistence.Tuple; import javax.persistence.TypedQuery; +import java.lang.reflect.Field; import java.sql.Timestamp; import java.time.LocalDateTime; import java.util.*; @@ -4860,49 +4868,49 @@ public void handle(ErrorCode errCode, Map data) { }).start(); } - private void handle(final APIRecoverVmInstanceMsg msg) { - thdf.chainSubmit(new ChainTask(msg) { - @Override - public String getSyncSignature() { - return syncThreadName; - } - - @Override - public void run(final SyncTaskChain chain) { - final APIRecoverVmInstanceEvent evt = new APIRecoverVmInstanceEvent(msg.getId()); - refreshVO(); - - ErrorCode error = validateOperationByState(msg, self.getState(), SysErrors.OPERATION_ERROR); - if (error != null) { - evt.setError(error); - bus.publish(evt); - chain.next(); - return; - } - - recoverVm(new Completion(msg, chain) { - @Override - public void success() { - evt.setInventory(getSelfInventory()); - bus.publish(evt); - chain.next(); - } - - @Override - public void fail(ErrorCode errorCode) { - evt.setError(errorCode); - bus.publish(evt); - chain.next(); - } - }); - } - - @Override - public String getName() { - return "recover-vm"; - } - }); - } +// private void handle(final APIRecoverVmInstanceMsg msg) { +// thdf.chainSubmit(new ChainTask(msg) { +// @Override +// public String getSyncSignature() { +// return syncThreadName; +// } +// +// @Override +// public void run(final SyncTaskChain chain) { +// final APIRecoverVmInstanceEvent evt = new APIRecoverVmInstanceEvent(msg.getId()); +// refreshVO(); +// +// ErrorCode error = validateOperationByState(msg, self.getState(), SysErrors.OPERATION_ERROR); +// if (error != null) { +// evt.setError(error); +// bus.publish(evt); +// chain.next(); +// return; +// } +// +// recoverVm(new Completion(msg, chain) { +// @Override +// public void success() { +// evt.setInventory(getSelfInventory()); +// bus.publish(evt); +// chain.next(); +// } +// +// @Override +// public void fail(ErrorCode errorCode) { +// evt.setError(errorCode); +// bus.publish(evt); +// chain.next(); +// } +// }); +// } +// +// @Override +// public String getName() { +// return "recover-vm"; +// } +// }); +// } private void handle(final APIExpungeVmInstanceMsg msg) { final APIExpungeVmInstanceEvent evt = new APIExpungeVmInstanceEvent(msg.getId()); @@ -9369,5 +9377,306 @@ public void run(MessageReply reply) { } }); } + + private void handle(final APIRecoverVmInstanceMsg msg) { + List vms = Q.New(VmInstanceVO.class).list(); + String json = buildVmInstanceMetadata(vms.get(0).getUuid()); + + VmMetadata vmMetadata = JSONObjectUtil.toObject(json, VmMetadata.class); + + VmInstanceVO vmInstanceString = JSONObjectUtil.toObject(vmMetadata.vmInstanceVO, VmInstanceVO.class); + VmInstanceVO vm = new VmInstanceVO(); + + List vmSystemTags = vmMetadata.vmSystemTags; + List vmResourceConfigs = vmMetadata.vmResourceConfigs; + + try { + List systemTags = getResourceSystemTag(VmInstanceVO.class.getSimpleName()); + List resourceConfigs = getResourceConfig(VmInstanceVO.class.getSimpleName()); + + List tagVOS = new ArrayList<>(); + vmSystemTags.forEach(tag -> { + List info = asList(tag.split("_")); + String t = info.get(0); + Boolean inherent = Boolean.valueOf(info.get(1)); + String type = info.get(2); + systemTags.forEach(it -> { + if (!it.isMatch(t)) { + return; + } + SystemTagVO vo = new SystemTagVO(); + vo.setTag(t); + vo.setType(TagType.valueOf(type)); + vo.setInherent(inherent); + vo.setResourceType(VmInstanceVO.class.getSimpleName()); + vo.setResourceUuid(vm.getUuid()); + tagVOS.add(vo); + }); + }); + + List configVOS = new ArrayList<>(); + vmResourceConfigs.forEach(tag -> { + List info = asList(tag.split("_")); + String identity = info.get(0); + String value = info.get(1); + resourceConfigs.forEach(it -> { + if (it.getIdentity() == identity) { + return; + } + ResourceConfigVO vo = new ResourceConfigVO(); + vo.setCategory(identity); + vo.setName(identity); + vo.setValue(value); + vo.setResourceType(VmInstanceVO.class.getSimpleName()); + vo.setResourceUuid(vm.getUuid()); + configVOS.add(vo); + }); + }); + } catch (IllegalAccessException | InstantiationException e) { + throw new RuntimeException(e); + } + + List volumesString = vmMetadata.volumeVOs; + List volumes = new ArrayList<>(); + volumesString.forEach(v -> volumes.add(JSONObjectUtil.toObject(v, VolumeVO.class))); + volumes.forEach(v -> { + VolumeVO volume = new VolumeVO(); + }); + + Map> volumeSnapshots = vmMetadata.volumeSnapshots; + Set snapshotTreeUuid = new HashSet<>(); + volumeSnapshots.forEach((volumeUuid, snapshots) -> { + snapshots.forEach(snapshot -> { + VolumeSnapshotInventory inv = JSONObjectUtil.toObject(snapshot, VolumeSnapshotInventory.class); + VolumeSnapshotVO vo = new VolumeSnapshotVO(); + snapshotTreeUuid.add(inv.toString()); + }); + }); + + List volumeSnapshotGroupVO = vmMetadata.volumeSnapshotGroupVO; + volumeSnapshotGroupVO.forEach(group -> { + VolumeSnapshotGroupVO inv = JSONObjectUtil.toObject(group, VolumeSnapshotGroupVO.class); + VolumeSnapshotGroupVO newGroup = new VolumeSnapshotGroupVO(); +// newGroup = new VolumeSnapshotGroupVO(); +// newGroup.setUuid(Platform.getUuid()); +// newGroup.setName(String.format("revert-vm-point-%s-%s", vmUuid, TimeUtils.getCurrentTimeStamp("yyyyMMddHHmmss"))); +// newGroup.setDescription(String.format("save snapshot for revert vm [uuid:%s]", vmUuid)); +// newGroup.setSnapshotCount(snapshots.size()); +// newGroup.setVmInstanceUuid(vmUuid); +// newGroup.setAccountUuid(msg.getSession().getAccountUuid()); + }); + + List volumeSnapshotGroupRefVO = vmMetadata.volumeSnapshotGroupRefVO; + volumeSnapshotGroupRefVO.forEach(group -> { + VolumeSnapshotGroupRefVO inv = JSONObjectUtil.toObject(group, VolumeSnapshotGroupRefVO.class); + +// VolumeSnapshotGroupRefVO ref = new VolumeSnapshotGroupRefVO(); +// ref.setVolumeUuid(inv.getVolumeUuid()); +// ref.setVolumeName(vols.get(inv.getVolumeUuid()).getName()); +// ref.setVolumeType(inv.getVolumeType()); +// ref.setVolumeSnapshotGroupUuid(group.getUuid()); +// ref.setVolumeSnapshotUuid(inv.getUuid()); +// ref.setVolumeSnapshotName(inv.getName()); +// ref.setVolumeSnapshotInstallPath(inv.getPrimaryStorageInstallPath()); +// ref.setDeviceId(vols.get(inv.getVolumeUuid()).getDeviceId()); +// ref.setVolumeLastAttachDate(vols.get(inv.getVolumeUuid()).getLastAttachDate()); + }); + } + + private String buildVmInstanceMetadata(String vmInstanceUuid) { + VmMetadata vmMetadata = new VmMetadata(); + + // 找出vm + // 找出volume和快照 + // 找出网卡 + VmInstanceVO vm = Q.New(VmInstanceVO.class).eq(VmInstanceVO_.uuid, vmInstanceUuid).find(); + + List systemTags = new ArrayList<>(); + List tuples = Q.New(SystemTag.class).eq(SystemTagVO_.resourceUuid, vm.getUuid()) + .select(SystemTagVO_.tag, SystemTagVO_.inherent, SystemTagVO_.type).listValues(); + tuples.forEach(t -> { + String tag = String.format("%s_%s_%s", t.get(0, String.class), t.get(1, Boolean.class), t.get(2, String.class)); + systemTags.add(tag); + }); + vmMetadata.vmSystemTags = systemTags; + + + List resourceConfigs = new ArrayList<>(); + tuples = Q.New(ResourceConfigVO.class).eq(ResourceConfigVO_.resourceUuid, vm.getUuid()) + .select(ResourceConfigVO_.category, ResourceConfigVO_.name, ResourceConfigVO_.value).listValues(); + + tuples.forEach(t -> { + String config = String.format("%s.%s_%s", t.get(0, String.class), t.get(1, String.class), t.get(2, String.class)); + resourceConfigs.add(config); + }); + vmMetadata.vmResourceConfigs = resourceConfigs; + + // 挂载的 + List volumes1 = Q.New(VolumeVO.class).eq(VolumeVO_.vmInstanceUuid, vmInstanceUuid).list(); + // 被卸载的 + List volumes2 = Q.New(VolumeVO.class).eq(VolumeVO_.vmInstanceUuid, null).eq(VolumeVO_.lastVmInstanceUuid, vmInstanceUuid).list(); + + List volumes = new ArrayList<>(); + volumes.addAll(volumes1); + volumes.addAll(volumes2); + + List nics = Q.New(VmNicVO.class).eq(VolumeVO_.vmInstanceUuid, vmInstanceUuid).list(); + + List volumeUuids = new ArrayList<>(); + List snapshot = Q.New(VolumeSnapshotVO.class).in(VolumeSnapshotVO_.volumeUuid, volumeUuids).list(); + + List group = Q.New(VolumeSnapshotGroupVO.class).eq(VolumeSnapshotGroupVO_.vmInstanceUuid, vmInstanceUuid).list(); + List groupUuids = new ArrayList<>(); + List groupRef = Q.New(VolumeSnapshotGroupRefVO.class).in(VolumeSnapshotGroupRefVO_.volumeSnapshotGroupUuid, groupUuids).list(); + + vmMetadata.vmInstanceVO = JSONObjectUtil.toJsonString(vm); + volumes.forEach(volumeVO -> vmMetadata.volumeVOs.add(JSONObjectUtil.toJsonString(volumeVO))); + nics.forEach(nic -> vmMetadata.vmNicVOs.add(JSONObjectUtil.toJsonString(nic))); + + Map> volumeSnapshots = new HashMap<>(); + snapshot.forEach(s -> { + if (volumeSnapshots.containsKey(s.getVolumeUuid())) { + volumeSnapshots.get(s.getVolumeUuid()).add(JSONObjectUtil.toJsonString(VolumeSnapshotInventory.valueOf(s))); + } else { + volumeSnapshots.put(s.getVolumeUuid(), new ArrayList<>()); + volumeSnapshots.get(s.getVolumeUuid()).add(JSONObjectUtil.toJsonString(VolumeSnapshotInventory.valueOf(s))); + } + }); + vmMetadata.volumeSnapshots = volumeSnapshots; + vmMetadata.volumeSnapshotGroupVO = group.stream().map(JSONObjectUtil::toJsonString).collect(Collectors.toList()); + vmMetadata.volumeSnapshotGroupRefVO = groupRef.stream().map(JSONObjectUtil::toJsonString).collect(Collectors.toList()); + + // 其他组件的metadata + CollectionUtils.safeForEach(pluginRgty.getExtensionList(UpdateVmInstanceMetadataExtensionPoint.class), + new ForEachFunction() { + @Override + public void run(UpdateVmInstanceMetadataExtensionPoint ext) { + logger.debug(String.format("execute before add acl ip entry extension point %s", ext)); + ext.buildVmInstanceMetadata(VmInstanceInventory.valueOf(vm), vmMetadata); + } + }); + + + return JSONObjectUtil.toJsonString(vmMetadata); + //{ + // "vmInstanceVO" : "{\"vmNics\":[{\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"l3NetworkUuid\":\"81c8aafb064d4ba2944227da9555c5f0\",\"mac\":\"fa:b2:1a:b5:3a:00\",\"hypervisorType\":\"KVM\",\"deviceId\":0,\"internalName\":\"vnic3.0\",\"driverType\":\"virtio\",\"type\":\"VNIC\",\"state\":\"enable\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"usedIps\":[],\"uuid\":\"07fdf6d90be1460f9b7ad949cc39c893\",\"resourceType\":\"VmNicVO\",\"concreteResourceType\":\"org.zstack.header.vm.VmNicVO\"}],\"allVolumes\":[{\"name\":\"DATA-for-vm3\",\"description\":\"DataVolume-56583eb6f40e40d1a28f23b7d34b4f5b\",\"primaryStorageUuid\":\"95e0442313234b7d890be67ab232af3f\",\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"diskOfferingUuid\":\"d2f0438b52a142a981ebfb62cc8dc11a\",\"installPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/dataVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-60c5546c30de4f09afaa243ae951dc63/60c5546c30de4f09afaa243ae951dc63.qcow2\",\"type\":\"Data\",\"status\":\"Ready\",\"size\":10737418240,\"actualSize\":0,\"deviceId\":1,\"format\":\"qcow2\",\"state\":\"Enabled\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastAttachDate\":\"Jan 18, 2026 10:34:40 PM\",\"isShareable\":false,\"shadow\":{\"name\":\"DATA-for-vm3\",\"description\":\"DataVolume-56583eb6f40e40d1a28f23b7d34b4f5b\",\"primaryStorageUuid\":\"95e0442313234b7d890be67ab232af3f\",\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"diskOfferingUuid\":\"d2f0438b52a142a981ebfb62cc8dc11a\",\"installPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/dataVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-60c5546c30de4f09afaa243ae951dc63/60c5546c30de4f09afaa243ae951dc63.qcow2\",\"type\":\"Data\",\"status\":\"Ready\",\"size\":10737418240,\"actualSize\":0,\"deviceId\":1,\"format\":\"qcow2\",\"state\":\"Enabled\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastAttachDate\":\"Jan 18, 2026 10:34:40 PM\",\"isShareable\":false},\"uuid\":\"60c5546c30de4f09afaa243ae951dc63\",\"resourceName\":\"DATA-for-vm3\",\"resourceType\":\"VolumeVO\",\"concreteResourceType\":\"org.zstack.header.volume.VolumeVO\"},{\"name\":\"ROOT-for-vm3\",\"description\":\"Root volume for VM[uuid:56583eb6f40e40d1a28f23b7d34b4f5b]\",\"primaryStorageUuid\":\"95e0442313234b7d890be67ab232af3f\",\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"rootImageUuid\":\"ed16ac328672441a93d15dfb51fa1033\",\"installPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-c28b1bd97d8247bbbf60b8c86276dceb/c28b1bd97d8247bbbf60b8c86276dceb.qcow2\",\"type\":\"Root\",\"status\":\"Ready\",\"size\":0,\"actualSize\":0,\"deviceId\":0,\"format\":\"qcow2\",\"state\":\"Enabled\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastAttachDate\":\"Jan 18, 2026 10:34:40 PM\",\"isShareable\":false,\"shadow\":{\"name\":\"ROOT-for-vm3\",\"description\":\"Root volume for VM[uuid:56583eb6f40e40d1a28f23b7d34b4f5b]\",\"primaryStorageUuid\":\"95e0442313234b7d890be67ab232af3f\",\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"rootImageUuid\":\"ed16ac328672441a93d15dfb51fa1033\",\"installPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-c28b1bd97d8247bbbf60b8c86276dceb/c28b1bd97d8247bbbf60b8c86276dceb.qcow2\",\"type\":\"Root\",\"status\":\"Ready\",\"size\":0,\"actualSize\":0,\"deviceId\":0,\"format\":\"qcow2\",\"state\":\"Enabled\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastAttachDate\":\"Jan 18, 2026 10:34:40 PM\",\"isShareable\":false},\"uuid\":\"c28b1bd97d8247bbbf60b8c86276dceb\",\"resourceName\":\"ROOT-for-vm3\",\"resourceType\":\"VolumeVO\",\"concreteResourceType\":\"org.zstack.header.volume.VolumeVO\"}],\"vmCdRoms\":[{\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"deviceId\":0,\"name\":\"vm-56583eb6f40e40d1a28f23b7d34b4f5b-cdRom\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"uuid\":\"e087bbf2d5bc4eea8cf04fc5c27db3d1\",\"resourceName\":\"vm-56583eb6f40e40d1a28f23b7d34b4f5b-cdRom\",\"resourceType\":\"VmCdRomVO\",\"concreteResourceType\":\"org.zstack.header.vm.cdrom.VmCdRomVO\"}],\"name\":\"vm3\",\"zoneUuid\":\"edad4e425c6e4b9c9f62e22bc26cfe2e\",\"clusterUuid\":\"c19ac94e90004d72a85fa59269f539ec\",\"imageUuid\":\"ed16ac328672441a93d15dfb51fa1033\",\"hostUuid\":\"3495ce7c625f4b5bbbf3dd10d2387474\",\"internalId\":3,\"lastHostUuid\":\"3495ce7c625f4b5bbbf3dd10d2387474\",\"instanceOfferingUuid\":\"b219364de4d840349938c2ca238eb1ee\",\"rootVolumeUuid\":\"c28b1bd97d8247bbbf60b8c86276dceb\",\"defaultL3NetworkUuid\":\"81c8aafb064d4ba2944227da9555c5f0\",\"type\":\"UserVm\",\"hypervisorType\":\"KVM\",\"cpuNum\":4,\"cpuSpeed\":0,\"memorySize\":4294967296,\"reservedMemorySize\":0,\"platform\":\"Linux\",\"architecture\":\"x86_64\",\"allocatorStrategy\":\"LeastVmPreferredHostAllocatorStrategy\",\"guestOsType\":\"CentOS\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:41 PM\",\"state\":\"Running\",\"uuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"resourceName\":\"vm3\",\"resourceType\":\"VmInstanceVO\",\"concreteResourceType\":\"org.zstack.header.vm.VmInstanceVO\"}", + // "volumeVO" : "{\"name\":\"ROOT-for-vm2\",\"description\":\"Root volume for VM[uuid:7f9d54d410d4415ea744b9b85ccdc84d]\",\"primaryStorageUuid\":\"ad0e38a8249e4b129e5538fe5dc1c59e\",\"vmInstanceUuid\":\"7f9d54d410d4415ea744b9b85ccdc84d\",\"rootImageUuid\":\"e5875b4855f2466cbef440358318d7dd\",\"installPath\":\"/zstack_smp/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-34e8e378948948fcb273cf29a4c16831/34e8e378948948fcb273cf29a4c16831.qcow2\",\"type\":\"Root\",\"status\":\"Ready\",\"size\":0,\"actualSize\":0,\"deviceId\":0,\"format\":\"qcow2\",\"state\":\"Enabled\",\"createDate\":\"Jan 18, 2026 10:34:39 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:39 PM\",\"lastAttachDate\":\"Jan 18, 2026 10:34:39 PM\",\"isShareable\":false,\"shadow\":{\"name\":\"ROOT-for-vm2\",\"description\":\"Root volume for VM[uuid:7f9d54d410d4415ea744b9b85ccdc84d]\",\"primaryStorageUuid\":\"ad0e38a8249e4b129e5538fe5dc1c59e\",\"vmInstanceUuid\":\"7f9d54d410d4415ea744b9b85ccdc84d\",\"rootImageUuid\":\"e5875b4855f2466cbef440358318d7dd\",\"installPath\":\"/zstack_smp/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-34e8e378948948fcb273cf29a4c16831/34e8e378948948fcb273cf29a4c16831.qcow2\",\"type\":\"Root\",\"status\":\"Ready\",\"size\":0,\"actualSize\":0,\"deviceId\":0,\"format\":\"qcow2\",\"state\":\"Enabled\",\"createDate\":\"Jan 18, 2026 10:34:39 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:39 PM\",\"lastAttachDate\":\"Jan 18, 2026 10:34:39 PM\",\"isShareable\":false},\"uuid\":\"34e8e378948948fcb273cf29a4c16831\",\"resourceName\":\"ROOT-for-vm2\",\"resourceType\":\"VolumeVO\",\"concreteResourceType\":\"org.zstack.header.volume.VolumeVO\"}", + // "vmNicVO" : "{\"vmInstanceUuid\":\"56583eb6f40e40d1a28f23b7d34b4f5b\",\"l3NetworkUuid\":\"81c8aafb064d4ba2944227da9555c5f0\",\"mac\":\"fa:b2:1a:b5:3a:00\",\"hypervisorType\":\"KVM\",\"deviceId\":0,\"internalName\":\"vnic3.0\",\"driverType\":\"virtio\",\"type\":\"VNIC\",\"state\":\"enable\",\"createDate\":\"Jan 18, 2026 10:34:40 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:40 PM\",\"usedIps\":[],\"uuid\":\"07fdf6d90be1460f9b7ad949cc39c893\",\"resourceType\":\"VmNicVO\",\"concreteResourceType\":\"org.zstack.header.vm.VmNicVO\"}", + // "volumeSnapshots" : { + // "82b1c604f3fc44e1b863efc993e88223" : [ "{\"uuid\":\"3214fb7d25154a07956b65da51ef64d2\",\"name\":\"test-snap-ROOT-for-vm1\",\"type\":\"Hypervisor\",\"volumeUuid\":\"82b1c604f3fc44e1b863efc993e88223\",\"treeUuid\":\"f427df56f5dc4c7592a310b5c128520b\",\"primaryStorageUuid\":\"95e0442313234b7d890be67ab232af3f\",\"primaryStorageInstallPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/82b1c604f3fc44e1b863efc993e88223.qcow2\",\"volumeType\":\"Root\",\"format\":\"qcow2\",\"latest\":false,\"size\":0,\"distance\":1,\"state\":\"Enabled\",\"status\":\"Ready\",\"createDate\":\"Jan 18, 2026 10:34:42 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:43 PM\",\"backupStorageRefs\":[],\"groupUuid\":\"36e0512b36984d40b781efe561e8fdd6\"}", "{\"uuid\":\"bdd615cb76de4a1b9ef26fc3525799a2\",\"name\":\"test-snap-ROOT-for-vm1\",\"type\":\"Hypervisor\",\"volumeUuid\":\"82b1c604f3fc44e1b863efc993e88223\",\"treeUuid\":\"f427df56f5dc4c7592a310b5c128520b\",\"parentUuid\":\"3214fb7d25154a07956b65da51ef64d2\",\"primaryStorageUuid\":\"95e0442313234b7d890be67ab232af3f\",\"primaryStorageInstallPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/snapshots/d0abc4fad2e34b5a9d70c628a38178ec.qcow2\",\"volumeType\":\"Root\",\"format\":\"qcow2\",\"latest\":true,\"size\":0,\"distance\":2,\"state\":\"Enabled\",\"status\":\"Ready\",\"createDate\":\"Jan 18, 2026 10:34:43 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:43 PM\",\"backupStorageRefs\":[],\"groupUuid\":\"1c9321907b9d458fae5753e84e77f689\"}" ] + // }, + // "volumeSnapshotGroupVO" : [ "{\"snapshotCount\":1,\"name\":\"test-snap\",\"vmInstanceUuid\":\"e045e8df65804beab29b6744e0a8fbf1\",\"createDate\":\"Jan 18, 2026 10:34:43 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:43 PM\",\"volumeSnapshotRefs\":[{\"volumeSnapshotUuid\":\"bdd615cb76de4a1b9ef26fc3525799a2\",\"volumeSnapshotGroupUuid\":\"1c9321907b9d458fae5753e84e77f689\",\"snapshotDeleted\":false,\"deviceId\":0,\"volumeUuid\":\"82b1c604f3fc44e1b863efc993e88223\",\"volumeName\":\"ROOT-for-vm1\",\"volumeType\":\"Root\",\"volumeSnapshotInstallPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/snapshots/d0abc4fad2e34b5a9d70c628a38178ec.qcow2\",\"volumeSnapshotName\":\"test-snap-ROOT-for-vm1\",\"createDate\":\"Jan 18, 2026 10:34:43 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:43 PM\",\"volumeLastAttachDate\":\"Jan 18, 2026 10:34:38 PM\"}],\"uuid\":\"1c9321907b9d458fae5753e84e77f689\",\"resourceName\":\"test-snap\",\"resourceType\":\"VolumeSnapshotGroupVO\",\"concreteResourceType\":\"org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupVO\"}", "{\"snapshotCount\":1,\"name\":\"test-snap\",\"vmInstanceUuid\":\"e045e8df65804beab29b6744e0a8fbf1\",\"createDate\":\"Jan 18, 2026 10:34:42 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:42 PM\",\"volumeSnapshotRefs\":[{\"volumeSnapshotUuid\":\"3214fb7d25154a07956b65da51ef64d2\",\"volumeSnapshotGroupUuid\":\"36e0512b36984d40b781efe561e8fdd6\",\"snapshotDeleted\":false,\"deviceId\":0,\"volumeUuid\":\"82b1c604f3fc44e1b863efc993e88223\",\"volumeName\":\"ROOT-for-vm1\",\"volumeType\":\"Root\",\"volumeSnapshotInstallPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/82b1c604f3fc44e1b863efc993e88223.qcow2\",\"volumeSnapshotName\":\"test-snap-ROOT-for-vm1\",\"createDate\":\"Jan 18, 2026 10:34:42 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:42 PM\",\"volumeLastAttachDate\":\"Jan 18, 2026 10:34:38 PM\"}],\"uuid\":\"36e0512b36984d40b781efe561e8fdd6\",\"resourceName\":\"test-snap\",\"resourceType\":\"VolumeSnapshotGroupVO\",\"concreteResourceType\":\"org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupVO\"}" ], + // "volumeSnapshotGroupRefVO" : [ "{\"volumeSnapshotUuid\":\"3214fb7d25154a07956b65da51ef64d2\",\"volumeSnapshotGroupUuid\":\"36e0512b36984d40b781efe561e8fdd6\",\"snapshotDeleted\":false,\"deviceId\":0,\"volumeUuid\":\"82b1c604f3fc44e1b863efc993e88223\",\"volumeName\":\"ROOT-for-vm1\",\"volumeType\":\"Root\",\"volumeSnapshotInstallPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/82b1c604f3fc44e1b863efc993e88223.qcow2\",\"volumeSnapshotName\":\"test-snap-ROOT-for-vm1\",\"createDate\":\"Jan 18, 2026 10:34:42 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:42 PM\",\"volumeLastAttachDate\":\"Jan 18, 2026 10:34:38 PM\"}", "{\"volumeSnapshotUuid\":\"bdd615cb76de4a1b9ef26fc3525799a2\",\"volumeSnapshotGroupUuid\":\"1c9321907b9d458fae5753e84e77f689\",\"snapshotDeleted\":false,\"deviceId\":0,\"volumeUuid\":\"82b1c604f3fc44e1b863efc993e88223\",\"volumeName\":\"ROOT-for-vm1\",\"volumeType\":\"Root\",\"volumeSnapshotInstallPath\":\"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/snapshots/d0abc4fad2e34b5a9d70c628a38178ec.qcow2\",\"volumeSnapshotName\":\"test-snap-ROOT-for-vm1\",\"createDate\":\"Jan 18, 2026 10:34:43 PM\",\"lastOpDate\":\"Jan 18, 2026 10:34:43 PM\",\"volumeLastAttachDate\":\"Jan 18, 2026 10:34:38 PM\"}" ] + //} + + // VmMetadata vmMetadata1 = JSONObjectUtil.toObject(json, VmMetadata.class); + // 结果 = {VmInstanceBase$VmMetadata@51572} + // vmInstanceVO = "{"vmNics":[{"vmInstanceUuid":"56583eb6f40e40d1a28f23b7d34b4f5b","l3NetworkUuid":"81c8aafb064d4ba2944227da9555c5f0","mac":"fa:b2:1a:b5:3a:00","hypervisorType":"KVM","deviceId":0,"internalName":"vnic3.0","driverType":"virtio","type":"VNIC","state":"enable","createDate":"Jan 18, 2026 10:34:40 PM","lastOpDate":"Jan 18, 2026 10:34:40 PM","usedIps":[],"uuid":"07fdf6d90be1460f9b7ad949cc39c893","resourceType":"VmNicVO","concreteResourceType":"org.zstack.header.vm.VmNicVO"}],"allVolumes":[{"name":"DATA-for-vm3","description":"DataVolume-56583eb6f40e40d1a28f23b7d34b4f5b","primaryStorageUuid":"95e0442313234b7d890be67ab232af3f","vmInstanceUuid":"56583eb6f40e40d1a28f23b7d34b4f5b","diskOfferingUuid":"d2f0438b52a142a981ebfb62cc8dc11a","installPath":"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/dataVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-60c5546c30de4f09afaa243ae951dc63/60c5546c30de4f09afaa243ae951dc63.qcow2","type":"Data","status":"Ready","size":10737418240,"actualSiz" + // vmConfigs = null + // volumeVO = "{"name":"ROOT-for-vm2","description":"Root volume for VM[uuid:7f9d54d410d4415ea744b9b85ccdc84d]","primaryStorageUuid":"ad0e38a8249e4b129e5538fe5dc1c59e","vmInstanceUuid":"7f9d54d410d4415ea744b9b85ccdc84d","rootImageUuid":"e5875b4855f2466cbef440358318d7dd","installPath":"/zstack_smp/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-34e8e378948948fcb273cf29a4c16831/34e8e378948948fcb273cf29a4c16831.qcow2","type":"Root","status":"Ready","size":0,"actualSize":0,"deviceId":0,"format":"qcow2","state":"Enabled","createDate":"Jan 18, 2026 10:34:39 PM","lastOpDate":"Jan 18, 2026 10:34:39 PM","lastAttachDate":"Jan 18, 2026 10:34:39 PM","isShareable":false,"shadow":{"name":"ROOT-for-vm2","description":"Root volume for VM[uuid:7f9d54d410d4415ea744b9b85ccdc84d]","primaryStorageUuid":"ad0e38a8249e4b129e5538fe5dc1c59e","vmInstanceUuid":"7f9d54d410d4415ea744b9b85ccdc84d","rootImageUuid":"e5875b4855f2466cbef440358318d7dd","installPath":"/zstack_smp/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/v" + // volumeConfigs = null + // vmNicVO = "{"vmInstanceUuid":"56583eb6f40e40d1a28f23b7d34b4f5b","l3NetworkUuid":"81c8aafb064d4ba2944227da9555c5f0","mac":"fa:b2:1a:b5:3a:00","hypervisorType":"KVM","deviceId":0,"internalName":"vnic3.0","driverType":"virtio","type":"VNIC","state":"enable","createDate":"Jan 18, 2026 10:34:40 PM","lastOpDate":"Jan 18, 2026 10:34:40 PM","usedIps":[],"uuid":"07fdf6d90be1460f9b7ad949cc39c893","resourceType":"VmNicVO","concreteResourceType":"org.zstack.header.vm.VmNicVO"}" + // vmNicConfigs = null + // volumeSnapshots = {LinkedTreeMap@51576} size = 1 + // "82b1c604f3fc44e1b863efc993e88223" -> {ArrayList@51587} size = 2 + // volumeSnapshotGroupVO = {ArrayList@51577} size = 2 + // 0 = "{"snapshotCount":1,"name":"test-snap","vmInstanceUuid":"e045e8df65804beab29b6744e0a8fbf1","createDate":"Jan 18, 2026 10:34:43 PM","lastOpDate":"Jan 18, 2026 10:34:43 PM","volumeSnapshotRefs":[{"volumeSnapshotUuid":"bdd615cb76de4a1b9ef26fc3525799a2","volumeSnapshotGroupUuid":"1c9321907b9d458fae5753e84e77f689","snapshotDeleted":false,"deviceId":0,"volumeUuid":"82b1c604f3fc44e1b863efc993e88223","volumeName":"ROOT-for-vm1","volumeType":"Root","volumeSnapshotInstallPath":"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/snapshots/d0abc4fad2e34b5a9d70c628a38178ec.qcow2","volumeSnapshotName":"test-snap-ROOT-for-vm1","createDate":"Jan 18, 2026 10:34:43 PM","lastOpDate":"Jan 18, 2026 10:34:43 PM","volumeLastAttachDate":"Jan 18, 2026 10:34:38 PM"}],"uuid":"1c9321907b9d458fae5753e84e77f689","resourceName":"test-snap","resourceType":"VolumeSnapshotGroupVO","concreteResourceType":"org.zstack.he" + // 1 = "{"snapshotCount":1,"name":"test-snap","vmInstanceUuid":"e045e8df65804beab29b6744e0a8fbf1","createDate":"Jan 18, 2026 10:34:42 PM","lastOpDate":"Jan 18, 2026 10:34:42 PM","volumeSnapshotRefs":[{"volumeSnapshotUuid":"3214fb7d25154a07956b65da51ef64d2","volumeSnapshotGroupUuid":"36e0512b36984d40b781efe561e8fdd6","snapshotDeleted":false,"deviceId":0,"volumeUuid":"82b1c604f3fc44e1b863efc993e88223","volumeName":"ROOT-for-vm1","volumeType":"Root","volumeSnapshotInstallPath":"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/82b1c604f3fc44e1b863efc993e88223.qcow2","volumeSnapshotName":"test-snap-ROOT-for-vm1","createDate":"Jan 18, 2026 10:34:42 PM","lastOpDate":"Jan 18, 2026 10:34:42 PM","volumeLastAttachDate":"Jan 18, 2026 10:34:38 PM"}],"uuid":"36e0512b36984d40b781efe561e8fdd6","resourceName":"test-snap","resourceType":"VolumeSnapshotGroupVO","concreteResourceType":"org.zstack.header.stora" + // volumeSnapshotGroupRefVO = {ArrayList@51578} size = 2 + // 0 = "{"volumeSnapshotUuid":"3214fb7d25154a07956b65da51ef64d2","volumeSnapshotGroupUuid":"36e0512b36984d40b781efe561e8fdd6","snapshotDeleted":false,"deviceId":0,"volumeUuid":"82b1c604f3fc44e1b863efc993e88223","volumeName":"ROOT-for-vm1","volumeType":"Root","volumeSnapshotInstallPath":"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/82b1c604f3fc44e1b863efc993e88223.qcow2","volumeSnapshotName":"test-snap-ROOT-for-vm1","createDate":"Jan 18, 2026 10:34:42 PM","lastOpDate":"Jan 18, 2026 10:34:42 PM","volumeLastAttachDate":"Jan 18, 2026 10:34:38 PM"}" + // 1 = "{"volumeSnapshotUuid":"bdd615cb76de4a1b9ef26fc3525799a2","volumeSnapshotGroupUuid":"1c9321907b9d458fae5753e84e77f689","snapshotDeleted":false,"deviceId":0,"volumeUuid":"82b1c604f3fc44e1b863efc993e88223","volumeName":"ROOT-for-vm1","volumeType":"Root","volumeSnapshotInstallPath":"/opt/zstack/nfsprimarystorage/prim-95e0442313234b7d890be67ab232af3f/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-82b1c604f3fc44e1b863efc993e88223/snapshots/d0abc4fad2e34b5a9d70c628a38178ec.qcow2","volumeSnapshotName":"test-snap-ROOT-for-vm1","createDate":"Jan 18, 2026 10:34:43 PM","lastOpDate":"Jan 18, 2026 10:34:43 PM","volumeLastAttachDate":"Jan 18, 2026 10:34:38 PM"}" + // volumeSnapshotReferenceVO = null + // volumeSnapshotReferenceTreeVO = null + } + + private List getResourceSystemTag(String resourceType) throws IllegalAccessException, InstantiationException { + List systemTags = new ArrayList<>(); + + Set> classes = BeanUtils.reflections.getTypesAnnotatedWith(TagDefinition.class); + for (Class clazz : classes) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (!SystemTag.class.isAssignableFrom(field.getType())) { + continue; + } + + SystemTag systemTag = (SystemTag) field.get(clazz.newInstance()); + + if (resourceType.equals(systemTag.getResourceClass().getName())) { + systemTags.add(systemTag); + } + } + } + return systemTags; + } + + private List getResourceConfig(String resourceType) throws IllegalAccessException, InstantiationException { + List globalConfigs = new ArrayList<>(); + + Set> classes = BeanUtils.reflections.getTypesAnnotatedWith(GlobalConfigDefinition.class); + for (Class clazz : classes) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (!GlobalConfig.class.isAssignableFrom(field.getType())) { + continue; + } + GlobalConfig globalConfig = (GlobalConfig) field.get(clazz.newInstance()); + + BindResourceConfig bindResourceConfig = field.getAnnotation(BindResourceConfig.class); + if (bindResourceConfig == null) { + continue; + } + + List bindResourceConfigs = Arrays.stream(bindResourceConfig.value()).map(Class::getName).collect(Collectors.toList()); + + if (bindResourceConfigs.contains(resourceType)) { + globalConfigs.add(globalConfig); + } + } + } + + return globalConfigs; + } + + private void handle(UpdateVmInstanceMetadataMsg msg) { + thdf.chainSubmit(new ChainTask(msg) { + @Override + public String getSyncSignature() { + return syncThreadName; + } + + @Override + public void run(SyncTaskChain chain) { + UpdateVmInstanceMetadataReply reply = new UpdateVmInstanceMetadataReply(); + + UpdateVmInstanceMetadataOnHypervisorMsg umsg = new UpdateVmInstanceMetadataOnHypervisorMsg(); + umsg.setVmInstanceMetadata(buildVmInstanceMetadata(msg.getUuid())); + if (self.getHostUuid() != null) { + umsg.setHostUuid(self.getHostUuid()); + } else if (self.getLastHostUuid() != null) { + umsg.setHostUuid(self.getLastHostUuid()); + } + + bus.makeTargetServiceIdByResourceUuid(umsg, HostConstant.SERVICE_ID, umsg.getHostUuid()); + bus.send(umsg, new CloudBusCallBack(msg) { + @Override + public void run(MessageReply innerReply) { + if (!innerReply.isSuccess()) { + reply.setError(Platform.operr("failed to update vm[uuid=%s] on hypervisor.", self.getUuid()) + .withCause(innerReply.getError())); + return; + } + + + } + }); + } + + @Override + public String getName() { + return "update-vm-info"; + } + }); + } } diff --git a/header/src/main/java/org/zstack/header/vm/APIRegVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIRegVmInstanceMsg.java new file mode 100644 index 00000000000..d7271b74a45 --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/APIRegVmInstanceMsg.java @@ -0,0 +1,42 @@ +package org.zstack.header.vm; + +import org.springframework.http.HttpMethod; +import org.zstack.header.cluster.ClusterVO; +import org.zstack.header.host.HostVO; +import org.zstack.header.message.APIMessage; +import org.zstack.header.message.APIParam; +import org.zstack.header.network.l3.L3NetworkVO; +import org.zstack.header.rest.RestRequest; + +import java.util.List; + +/** + * Created by frank on 11/12/2015. + */ +@RestRequest( + path = "/vm-instances/{uuid}/actions", + isAction = true, + method = HttpMethod.PUT, + responseClass = APIRecoverVmInstanceEvent.class +) +public class APIRegVmInstanceMsg extends APIMessage { + @APIParam(resourceType = ClusterVO.class) + private String clusterUuid; + @APIParam(resourceType = HostVO.class) + private String hostUuid; + + + + private String defaultL3NetworkUuid; + + @APIParam(resourceType = L3NetworkVO.class, required = false) + private List l3NetworkUuids; + + @APIParam(required = false) + private String vmNicParams; + + public static APIRegVmInstanceMsg __example__() { + APIRegVmInstanceMsg msg = new APIRegVmInstanceMsg(); + return msg; + } +} diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataExtensionPoint.java b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataExtensionPoint.java new file mode 100644 index 00000000000..cb320a9d750 --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataExtensionPoint.java @@ -0,0 +1,8 @@ +package org.zstack.header.vm; + +/** + * Created by LiangHanYu on 2022/4/13 13:24 + */ +public interface UpdateVmInstanceMetadataExtensionPoint { + void buildVmInstanceMetadata(VmInstanceInventory vmInstanceInventory, VmMetadata vmMetadata); +} diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataMsg.java new file mode 100644 index 00000000000..bba392b322a --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataMsg.java @@ -0,0 +1,20 @@ +package org.zstack.header.vm; + +import org.zstack.header.message.NeedReplyMessage; + +public class UpdateVmInstanceMetadataMsg extends NeedReplyMessage implements VmInstanceMessage { + private String uuid; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String getVmInstanceUuid() { + return uuid; + } +} diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataOnHypervisorMsg.java b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataOnHypervisorMsg.java new file mode 100644 index 00000000000..a2888f6e6a6 --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataOnHypervisorMsg.java @@ -0,0 +1,26 @@ +package org.zstack.header.vm; + +import org.zstack.header.host.HostMessage; +import org.zstack.header.message.NeedReplyMessage; + +public class UpdateVmInstanceMetadataOnHypervisorMsg extends NeedReplyMessage implements HostMessage { + private String vmInstanceMetadata; + private String hostUuid; + + public String getVmInstanceMetadata() { + return vmInstanceMetadata; + } + + public void setVmInstanceMetadata(String vmInstanceMetadata) { + this.vmInstanceMetadata = vmInstanceMetadata; + } + + @Override + public String getHostUuid() { + return hostUuid; + } + + public void setHostUuid(String hostUuid) { + this.hostUuid = hostUuid; + } +} diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataOnHypervisorReply.java b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataOnHypervisorReply.java new file mode 100644 index 00000000000..c1cebeaa27b --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataOnHypervisorReply.java @@ -0,0 +1,27 @@ +package org.zstack.header.vm; + +import org.zstack.header.message.MessageReply; + +/** + * Created by xing5 on 2016/4/27. + */ +public class UpdateVmInstanceMetadataOnHypervisorReply extends MessageReply { + private long actualSize; + private long size; + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public long getActualSize() { + return actualSize; + } + + public void setActualSize(long actualSize) { + this.actualSize = actualSize; + } +} diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataReply.java b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataReply.java new file mode 100644 index 00000000000..3da2e0f6cbb --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/UpdateVmInstanceMetadataReply.java @@ -0,0 +1,27 @@ +package org.zstack.header.vm; + +import org.zstack.header.message.MessageReply; + +/** + * Created by xing5 on 2016/4/27. + */ +public class UpdateVmInstanceMetadataReply extends MessageReply { + private long actualSize; + private long size; + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public long getActualSize() { + return actualSize; + } + + public void setActualSize(long actualSize) { + this.actualSize = actualSize; + } +} diff --git a/header/src/main/java/org/zstack/header/vm/VmMetadata.java b/header/src/main/java/org/zstack/header/vm/VmMetadata.java new file mode 100644 index 00000000000..55b5799ac81 --- /dev/null +++ b/header/src/main/java/org/zstack/header/vm/VmMetadata.java @@ -0,0 +1,51 @@ +package org.zstack.header.vm; + +import java.util.List; +import java.util.Map; + +public class VmMetadata { + public String vmInstanceVO; + // key = vmUuid + // value = SystemTag + public List vmSystemTags; + // key = vmUuid + // value = ResourceConfig + public List vmResourceConfigs; + + public List volumeVOs; + // key = volumeUuid + // value = SystemTag + public Map> volumeSystemTags; + // key = volumeUuid + // value = ResourceConfig + public Map> volumeResourceConfigs; + + public List vmNicVOs; + // key = nicUuid + // value = SystemTag + public Map> vmNicSystemTags; + // key = nicUuid + // value = ResourceConfig + public Map> vmNicResourceConfigs; + + // key = volumeUuid + // value = List + public Map> volumeSnapshots; + // 构建快照树 + + // VolumeSnapshotGroupVO.toString + public List volumeSnapshotGroupVO; + // VolumeSnapshotGroupRefVO.toString + public List volumeSnapshotGroupRefVO; + + // key = volumeUuid + // value = VolumeSnapshotReferenceVO.toString + public Map volumeSnapshotReferenceVO; + // key = volumeUuid + // value = VolumeSnapshotReferenceTreeVO.toString + public Map volumeSnapshotReferenceTreeVO; + + // key = volumeUuid vmUuid + // value = vo + public Map EncryptedResourceKeyRefVO; +} diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java index 92e76ede2c5..882b1a3b322 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java @@ -4716,4 +4716,11 @@ public void setMemoryUsage(long memoryUsage) { this.memoryUsage = memoryUsage; } } + + public static class UpdateVmInstanceMetadataCmd extends AgentCommand { + public String vmInstanceMetadata; + } + + public static class UpdateVmInstanceMetadataRsp extends AgentResponse { + } } diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java index 7cd78c36c93..a3f3a2e4fe0 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java @@ -135,6 +135,8 @@ public interface KVMConstant { String HOST_PROCESS_PHYSICAL_MEMORY_USAGE_ALARM_PATH = "/host/process/physicalMemory/usage/alarm"; String HOST_KVMAGENT_STATUS_PATH = "/host/kvmagent/status"; + String KVM_HOST_UPDATE_VM_INSTANCE_METADATA_PATH = "/host/vm/metadata/update"; + String KVM_AGENT_OWNER = "kvm"; String ALI_REPO = "ali"; diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java index 23d7b1cfe47..c76c510a9f4 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java @@ -230,6 +230,7 @@ public class KVMHost extends HostBase implements Host { private String fileDownloadPath; private String fileUploadPath; private String fileDownloadProgressPath; + private String updateVmInstanceMetadataPath; public KVMHost(KVMHostVO self, KVMHostContext context) { super(self); @@ -480,6 +481,10 @@ public KVMHost(KVMHostVO self, KVMHostContext context) { ub = UriComponentsBuilder.fromHttpUrl(baseUrl); ub.path(KVMConstant.KVM_HOST_FILE_DOWNLOAD_PROGRESS_PATH); fileDownloadProgressPath = ub.build().toString(); + + ub = UriComponentsBuilder.fromHttpUrl(baseUrl); + ub.path(KVMConstant.KVM_HOST_UPDATE_VM_INSTANCE_METADATA_PATH); + updateVmInstanceMetadataPath = ub.build().toString(); } static { @@ -4145,6 +4150,33 @@ public void handle(ErrorCode errorCode, Map data) { }).start(); } + private void handle(UpdateVmInstanceMetadataOnHypervisorMsg msg) { + UpdateVmInstanceMetadataReply reply = new UpdateVmInstanceMetadataReply(); + + // before + // sblk 激活 + + UpdateVmInstanceMetadataCmd cmd = new UpdateVmInstanceMetadataCmd(); + cmd.vmInstanceMetadata = msg.getVmInstanceMetadata(); + new Http<>(updateVmInstanceMetadataPath, cmd, UpdateVmInstanceMetadataRsp.class).call(new ReturnValueCompletion(msg) { + @Override + public void success(UpdateVmInstanceMetadataRsp ret) { + if (!ret.isSuccess()) { + reply.setError(operr("operation error, because:%s", ret.getError())); + } + bus.reply(msg, reply); + } + + @Override + public void fail(ErrorCode errorCode) { + reply.setError(errorCode); + bus.reply(msg, reply); + } + }); + + // after + } + private void handle(final UpdateSpiceChannelConfigMsg msg) { UpdateSpiceChannelConfigReply reply = new UpdateSpiceChannelConfigReply(); UpdateSpiceChannelConfigCmd cmd = new UpdateSpiceChannelConfigCmd();