From fd46e61032f15c3bdc906b445a7f2ee607488240 Mon Sep 17 00:00:00 2001 From: Harikrishna Date: Tue, 2 Sep 2025 18:02:30 +0530 Subject: [PATCH 01/15] Added events for snapshots, vmsnapshots, internalLB operations (#11230) * Added events for snapshots, vmsnapshots, internalLB operations * Update server/src/main/java/com/cloud/resource/ResourceManagerImpl.java Co-authored-by: Suresh Kumar Anaparti * small fix * Unit test - ArgumentMatchers change Co-authored-by: dahn * Unit test - ArgumentMatchers change Co-authored-by: dahn --------- Co-authored-by: Suresh Kumar Anaparti Co-authored-by: dahn --- .../CreateSnapshotFromVMSnapshotCmd.java | 5 +++++ .../lb/InternalLoadBalancerVMManagerImpl.java | 4 ++++ .../internallbvmmgr/InternalLBVMServiceTest.java | 16 ++++++++++++++-- .../com/cloud/resource/ResourceManagerImpl.java | 7 ++++++- .../storage/snapshot/SnapshotManagerImpl.java | 2 ++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java index 7b89e87202d..d33a3ba224c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java @@ -210,4 +210,9 @@ public class CreateSnapshotFromVMSnapshotCmd extends BaseAsyncCreateCmd { } return null; } + + @Override + public Long getApiResourceId() { + return getEntityId(); + } } diff --git a/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java b/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java index a53f27188aa..70c29a64c1c 100644 --- a/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java +++ b/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java @@ -26,6 +26,8 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -540,6 +542,7 @@ public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements In } @Override + @ActionEvent(eventType = EventTypes.EVENT_INTERNAL_LB_VM_STOP, eventDescription = "stopping internal LB VM", async = true) public VirtualRouter stopInternalLbVm(final long vmId, final boolean forced, final Account caller, final long callerUserId) throws ConcurrentOperationException, ResourceUnavailableException { final DomainRouterVO internalLbVm = _internalLbVmDao.findById(vmId); if (internalLbVm == null || internalLbVm.getRole() != Role.INTERNAL_LB_VM) { @@ -928,6 +931,7 @@ public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements In } @Override + @ActionEvent(eventType = EventTypes.EVENT_INTERNAL_LB_VM_START, eventDescription = "starting internal LB VM", async = true) public VirtualRouter startInternalLbVm(final long internalLbVmId, final Account caller, final long callerUserId) throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { diff --git a/plugins/network-elements/internal-loadbalancer/src/test/java/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java b/plugins/network-elements/internal-loadbalancer/src/test/java/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java index 9141190df1f..fd44dcd981c 100644 --- a/plugins/network-elements/internal-loadbalancer/src/test/java/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java +++ b/plugins/network-elements/internal-loadbalancer/src/test/java/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java @@ -16,6 +16,9 @@ // under the License. package org.apache.cloudstack.internallbvmmgr; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; import java.lang.reflect.Field; @@ -24,13 +27,15 @@ import java.util.List; import javax.inject.Inject; +import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Matchers; +import org.mockito.BDDMockito; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -82,6 +87,8 @@ public class InternalLBVMServiceTest extends TestCase { @Inject AccountDao _accountDao; + private MockedStatic actionEventUtilsMocked; + long validVmId = 1L; long nonExistingVmId = 2L; long nonInternalLbVmId = 3L; @@ -105,7 +112,7 @@ public class InternalLBVMServiceTest extends TestCase { Mockito.when(_accountMgr.getSystemUser()).thenReturn(new UserVO(1)); Mockito.when(_accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); - Mockito.when(_accountDao.findByIdIncludingRemoved(Matchers.anyLong())).thenReturn(new AccountVO(2)); + Mockito.when(_accountDao.findByIdIncludingRemoved(anyLong())).thenReturn(new AccountVO(2)); CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); final DomainRouterVO validVm = @@ -120,11 +127,16 @@ public class InternalLBVMServiceTest extends TestCase { Mockito.when(_domainRouterDao.findById(validVmId)).thenReturn(validVm); Mockito.when(_domainRouterDao.findById(nonExistingVmId)).thenReturn(null); Mockito.when(_domainRouterDao.findById(nonInternalLbVmId)).thenReturn(nonInternalLbVm); + + actionEventUtilsMocked = Mockito.mockStatic(ActionEventUtils.class); + BDDMockito.given(ActionEventUtils.onStartedActionEvent(anyLong(), anyLong(), anyString(), anyString(), anyLong(), anyString(), anyBoolean(), anyLong())) + .willReturn(1L); } @Override @After public void tearDown() { + actionEventUtilsMocked.close(); CallContext.unregister(); } diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index e0cefc7b4bf..96fe734ed89 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1251,6 +1251,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_MAINTENANCE_CANCEL, eventDescription = "cancel maintenance for host", async = true) public Host cancelMaintenance(final CancelMaintenanceCmd cmd) { final Long hostId = cmd.getId(); @@ -1274,6 +1276,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_HOST_RECONNECT, eventDescription = "reconnecting host", async = true) public Host reconnectHost(ReconnectHostCmd cmd) throws AgentUnavailableException { Long hostId = cmd.getId(); @@ -1344,7 +1348,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, throw new CloudRuntimeException(err + e.getMessage()); } - ActionEventUtils.onStartedActionEvent(CallContext.current().getCallingUserId(), CallContext.current().getCallingAccountId(), EventTypes.EVENT_MAINTENANCE_PREPARE, "starting maintenance for host " + hostId, hostId, null, true, 0); _agentMgr.pullAgentToMaintenance(hostId); /* TODO: move below to listener */ @@ -1472,6 +1475,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_MAINTENANCE_PREPARE, eventDescription = "prepare maintenance for host", async = true) public Host maintain(final PrepareForMaintenanceCmd cmd) { final Long hostId = cmd.getId(); final HostVO host = _hostDao.findById(hostId); diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java index eed220836a4..4ae34517357 100755 --- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -492,6 +492,8 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement } @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot from VM snapshot", async = true) public Snapshot backupSnapshotFromVmSnapshot(Long snapshotId, Long vmId, Long volumeId, Long vmSnapshotId) { VMInstanceVO vm = _vmDao.findById(vmId); if (vm == null) { From f24b1757a0b920d88470033bdf4bd658717a8d20 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 3 Sep 2025 15:16:10 +0530 Subject: [PATCH 02/15] ui: donot filter edge zones while registering directdownload iso (#10865) Fixes #10766 Signed-off-by: Abhishek Kumar --- ui/src/views/image/RegisterOrUploadIso.vue | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/ui/src/views/image/RegisterOrUploadIso.vue b/ui/src/views/image/RegisterOrUploadIso.vue index 871a8482e99..37ae369727f 100644 --- a/ui/src/views/image/RegisterOrUploadIso.vue +++ b/ui/src/views/image/RegisterOrUploadIso.vue @@ -85,7 +85,7 @@ - + @@ -110,7 +110,7 @@ }" :loading="zoneLoading" :placeholder="apiParams.zoneid.description"> - + @@ -361,17 +361,18 @@ export default { }, created () { this.initForm() - this.zones = [] - if (this.$store.getters.userInfo.roletype === 'Admin' && this.currentForm === 'Create') { - this.zones = [ - { - id: '-1', - name: this.$t('label.all.zone') - } - ] - } + this.initZones() this.fetchData() }, + computed: { + zoneList () { + let filteredZones = this.zones + if (!this.form.directdownload) { + filteredZones = this.zones.filter(zone => zone.type !== 'Edge') + } + return filteredZones + } + }, methods: { initForm () { this.formRef = ref() @@ -390,6 +391,17 @@ export default { ostypeid: [{ required: true, message: this.$t('message.error.select') }] }) }, + initZones () { + this.zones = [] + if (this.$store.getters.userInfo.roletype === 'Admin' && this.currentForm === 'Create') { + this.zones = [ + { + id: '-1', + name: this.$t('label.all.zone') + } + ] + } + }, fetchData () { this.fetchZoneData() this.fetchOsType() @@ -412,11 +424,10 @@ export default { const listZones = json.listzonesresponse.zone if (listZones) { this.zones = this.zones.concat(listZones) - this.zones = this.zones.filter(zone => zone.type !== 'Edge') } }).finally(() => { this.zoneLoading = false - this.form.zoneid = (this.zones[0].id ? this.zones[0].id : '') + this.form.zoneid = this.zoneList?.[0]?.id || '' }) }, fetchOsType () { @@ -467,6 +478,12 @@ export default { this.fileList = newFileList this.form.file = undefined }, + handleDirectDownloadChange () { + if (this.form.zoneid && this.zoneList.find(entry => entry.id === this.form.zoneid)) { + return + } + this.form.zoneid = this.zoneList?.[0]?.id || '' + }, beforeUpload (file) { this.fileList = [file] this.form.file = file @@ -531,7 +548,7 @@ export default { } switch (key) { case 'zoneid': - var zone = this.zones.filter(zone => zone.id === input) + var zone = this.zoneList.filter(zone => zone.id === input) params[key] = zone[0].id break case 'ostypeid': From a4cf47a9b80e4ea96d0b702730b6e3363709d321 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 3 Sep 2025 16:30:26 +0530 Subject: [PATCH 03/15] server: remove extra chars when template status is error string (#11329) Fixes #11324 Signed-off-by: Abhishek Kumar --- .../java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 26a18818dbf..d23e2f6260f 100644 --- a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -180,10 +180,10 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation Date: Wed, 3 Sep 2025 18:35:06 +0530 Subject: [PATCH 04/15] ui: show multiple domains as links in list view (#11536) * ui: show multiple domains as links in list view Currently, when resources are linked to multiple domains and they are shown in the list view, they are not clickable. This PR fixes it. Signed-off-by: Abhishek Kumar * fix Signed-off-by: Abhishek Kumar --------- Signed-off-by: Abhishek Kumar --- ui/src/components/view/ListView.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index eca99dc0346..0109784047a 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -365,7 +365,14 @@