From 41cacb7791bc4574f976a1874ead4e4a1205ed3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Wed, 5 Jun 2024 17:01:38 -0300 Subject: [PATCH 1/6] add dedicated resource response --- .../affinity/AffinityGroupResponse.java | 13 ++++++ .../dedicated/DedicatedResourceResponse.java | 44 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java diff --git a/api/src/main/java/org/apache/cloudstack/affinity/AffinityGroupResponse.java b/api/src/main/java/org/apache/cloudstack/affinity/AffinityGroupResponse.java index 22842b834feb..1e34b16f9918 100644 --- a/api/src/main/java/org/apache/cloudstack/affinity/AffinityGroupResponse.java +++ b/api/src/main/java/org/apache/cloudstack/affinity/AffinityGroupResponse.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import org.apache.cloudstack.api.response.ControlledViewEntityResponse; +import org.apache.cloudstack.dedicated.DedicatedResourceResponse; import com.cloud.serializer.Param; @@ -72,6 +73,10 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledVie @Param(description = "virtual machine IDs associated with this affinity group") private List vmIdList; + @SerializedName("dedicatedresources") + @Param(description = "dedicated resources associated with this affinity group") + private List dedicatedResources; + public AffinityGroupResponse() { } @@ -162,4 +167,12 @@ public void addVMId(String vmId) { this.vmIdList.add(vmId); } + public void addDedicatedResource(DedicatedResourceResponse dedicatedResourceResponse) { + if (this.dedicatedResources == null) { + this.dedicatedResources = new ArrayList<>(); + } + + this.dedicatedResources.add(dedicatedResourceResponse); + } + } diff --git a/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java b/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java new file mode 100644 index 000000000000..d4743faa1b81 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.dedicated; + +import com.cloud.dc.DedicatedResources; +import com.cloud.serializer.Param; + +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.BaseResponse; + +public class DedicatedResourceResponse extends BaseResponse { + @SerializedName("resourceid") + @Param(description = "the ID of the resource") + private String resourceId; + + @SerializedName("resourcename") + @Param(description = "the name of the resource") + private String resourceName; + + @SerializedName("resourcetype") + @Param(description = "the type of the resource") + private DedicatedResources.Type resourceType; + + public DedicatedResourceResponse(String resourceId, String resourceName, DedicatedResources.Type resourceType) { + this.resourceId = resourceId; + this.resourceName = resourceName; + this.resourceType = resourceType; + } +} \ No newline at end of file From 4d8aaf9d594c1fb0db8b7ff9d02bdc47c4ed3c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Wed, 5 Jun 2024 17:13:18 -0300 Subject: [PATCH 2/6] populate dedicatedresources field --- .../java/com/cloud/dc/DedicatedResources.java | 4 ++ .../query/dao/AffinityGroupJoinDaoImpl.java | 61 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/cloud/dc/DedicatedResources.java b/api/src/main/java/com/cloud/dc/DedicatedResources.java index 63188ca0b0e9..23e6cc88a1e0 100644 --- a/api/src/main/java/com/cloud/dc/DedicatedResources.java +++ b/api/src/main/java/com/cloud/dc/DedicatedResources.java @@ -21,6 +21,10 @@ import org.apache.cloudstack.api.InternalIdentity; public interface DedicatedResources extends InfrastructureEntity, InternalIdentity, Identity { + enum Type { + Zone, Pod, Cluster, Host + } + @Override long getId(); diff --git a/server/src/main/java/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java index 2a876ea82265..a5fd2bf11f17 100644 --- a/server/src/main/java/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/AffinityGroupJoinDaoImpl.java @@ -21,21 +21,46 @@ import javax.inject.Inject; - import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.dedicated.DedicatedResourceResponse; import com.cloud.api.ApiResponseHelper; import com.cloud.api.query.vo.AffinityGroupJoinVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DedicatedResourceVO; +import com.cloud.dc.DedicatedResources; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DedicatedResourceDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDao; +import com.cloud.org.Cluster; +import com.cloud.user.AccountManager; public class AffinityGroupJoinDaoImpl extends GenericDaoBase implements AffinityGroupJoinDao { @Inject private ConfigurationDao _configDao; + @Inject + private DedicatedResourceDao dedicatedResourceDao; + @Inject + private DataCenterDao dataCenterDao; + @Inject + private HostPodDao podDao; + @Inject + private ClusterDao clusterDao; + @Inject + private HostDao hostDao; + @Inject + private AccountManager accountManager; private final SearchBuilder agSearch; @@ -64,6 +89,14 @@ public AffinityGroupResponse newAffinityGroupResponse(AffinityGroupJoinVO vag) { ApiResponseHelper.populateOwner(agResponse, vag); + Long callerId = CallContext.current().getCallingAccountId(); + boolean isCallerRootAdmin = accountManager.isRootAdmin(callerId); + boolean containsDedicatedResources = vag.getType().equals("ExplicitDedication"); + if (isCallerRootAdmin && containsDedicatedResources) { + List dedicatedResources = dedicatedResourceDao.listByAffinityGroupId(vag.getId()); + this.populateDedicatedResourcesField(dedicatedResources, agResponse); + } + // update vm information long instanceId = vag.getVmId(); if (instanceId > 0) { @@ -76,6 +109,32 @@ public AffinityGroupResponse newAffinityGroupResponse(AffinityGroupJoinVO vag) { return agResponse; } + private void populateDedicatedResourcesField(List dedicatedResources, AffinityGroupResponse agResponse) { + if (dedicatedResources.isEmpty()) { + return; + } + + for (DedicatedResourceVO resource : dedicatedResources) { + DedicatedResourceResponse dedicatedResourceResponse = null; + + if (resource.getDataCenterId() != null) { + DataCenter dataCenter = dataCenterDao.findById(resource.getDataCenterId()); + dedicatedResourceResponse = new DedicatedResourceResponse(dataCenter.getUuid(), dataCenter.getName(), DedicatedResources.Type.Zone); + } else if (resource.getPodId() != null) { + HostPodVO pod = podDao.findById(resource.getPodId()); + dedicatedResourceResponse = new DedicatedResourceResponse(pod.getUuid(), pod.getName(), DedicatedResources.Type.Pod); + } else if (resource.getClusterId() != null) { + Cluster cluster = clusterDao.findById(resource.getClusterId()); + dedicatedResourceResponse = new DedicatedResourceResponse(cluster.getUuid(), cluster.getName(), DedicatedResources.Type.Cluster); + } else if (resource.getHostId() != null) { + Host host = hostDao.findById(resource.getHostId()); + dedicatedResourceResponse = new DedicatedResourceResponse(host.getUuid(), host.getName(), DedicatedResources.Type.Host); + } + + agResponse.addDedicatedResource(dedicatedResourceResponse); + } + } + @Override public AffinityGroupResponse setAffinityGroupResponse(AffinityGroupResponse vagData, AffinityGroupJoinVO vag) { // update vm information From b09983a64240b76b561529eee34d98df14147cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Wed, 5 Jun 2024 17:22:08 -0300 Subject: [PATCH 3/6] change affinity group name and description when it contains dedicated resources --- .../DedicatedResourceManagerImpl.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java b/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java index 9060eccb64a2..88c91430b32e 100644 --- a/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java +++ b/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java @@ -23,6 +23,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.commons.lang3.StringUtils; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -236,7 +237,7 @@ public List dedicateZone(final Long zoneId, final Long doma @Override public List doInTransaction(TransactionStatus status) { // find or create the affinity group by name under this account/domain - AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal); + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, DedicatedResources.Type.Zone); if (group == null) { logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); @@ -372,10 +373,10 @@ public List dedicatePod(final Long podId, final Long domain @Override public List doInTransaction(TransactionStatus status) { // find or create the affinity group by name under this account/domain - AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal); + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, com.cloud.dc.DedicatedResources.Type.Pod); if (group == null) { - logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); - throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + logger.error("Unable to dedicate pod due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate pod. Please contact Cloud Support."); } DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, podId, null, null, null, null, group.getId()); try { @@ -485,10 +486,10 @@ public List dedicateCluster(final Long clusterId, final Lon @Override public List doInTransaction(TransactionStatus status) { // find or create the affinity group by name under this account/domain - AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal); + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, DedicatedResources.Type.Cluster); if (group == null) { - logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); - throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + logger.error("Unable to dedicate cluster due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate cluster. Please contact Cloud Support."); } DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, null, clusterId, null, null, null, group.getId()); try { @@ -582,10 +583,10 @@ public List dedicateHost(final Long hostId, final Long doma @Override public List doInTransaction(TransactionStatus status) { // find or create the affinity group by name under this account/domain - AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal); + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, com.cloud.dc.DedicatedResources.Type.Host); if (group == null) { - logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); - throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + logger.error("Unable to dedicate host due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate host. Please contact Cloud Support."); } DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, null, null, hostId, null, null, group.getId()); try { @@ -607,7 +608,7 @@ public List doInTransaction(TransactionStatus status) { } - private AffinityGroup findOrCreateDedicatedAffinityGroup(Long domainId, Long accountId) { + private AffinityGroup findOrCreateDedicatedAffinityGroup(Long domainId, Long accountId, DedicatedResources.Type dedicatedResource) { if (domainId == null) { return null; } @@ -624,24 +625,25 @@ private AffinityGroup findOrCreateDedicatedAffinityGroup(Long domainId, Long acc if (group != null) { return group; } - // default to a groupname with account/domain information - affinityGroupName = "DedicatedGrp-" + accountName; + // defaults to a groupName with resourceType and account/domain information + affinityGroupName = String.format("Dedicated%sGrp-%s", dedicatedResource, accountName); } else { // domain level group group = _affinityGroupDao.findDomainLevelGroupByType(domainId, "ExplicitDedication"); if (group != null) { return group; } - // default to a groupname with account/domain information + + // defaults to a groupName with resourceType and account/domain information String domainName = _domainDao.findById(domainId).getName(); - affinityGroupName = "DedicatedGrp-domain-" + domainName; + affinityGroupName = String.format("Dedicated%sGrp-domain-%s", dedicatedResource, domainName); } - group = _affinityGroupService.createAffinityGroup(accountName, null, domainId, affinityGroupName, "ExplicitDedication", "dedicated resources group"); + String description = String.format("Dedicated %s group", StringUtils.lowerCase(dedicatedResource.toString())); + group = _affinityGroupService.createAffinityGroup(accountName, null, domainId, affinityGroupName, "ExplicitDedication", description); return group; - } private List getVmsOnHost(long hostId) { From 74960bd0f6edd35a3f32f35e807c624fbdb6c272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Wed, 5 Jun 2024 17:28:42 -0300 Subject: [PATCH 4/6] display dedicatedresources on UI --- ui/public/locales/en.json | 1 + ui/public/locales/pt_BR.json | 1 + ui/src/components/view/DetailsTab.vue | 20 ++++++++++++++++++++ ui/src/config/section/compute.js | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index b42899fc6313..9e23aa52fc85 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -637,6 +637,7 @@ "label.dedicate.zone": "Dedicate zone", "label.dedicated": "Dedicated", "label.dedicated.vlan.vni.ranges": "Dedicated VLAN/VNI ranges", +"label.dedicatedresources": "Dedicated resources", "label.default": "Default", "label.default.use": "Default use", "label.default.view": "Default view", diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json index 82d527ae4c10..56b726e3fdce 100644 --- a/ui/public/locales/pt_BR.json +++ b/ui/public/locales/pt_BR.json @@ -471,6 +471,7 @@ "label.dedicate.zone": "Zona dedicada", "label.dedicated": "Dedicado", "label.dedicated.vlan.vni.ranges": "Intervalo(s) de VLAN/VNI dedicados", +"label.dedicatedresources": "Recursos dedicados", "label.default": "Padr\u00e3o", "label.default.use": "Uso padr\u00e3o", "label.default.view": "Visualiza\u00e7\u00e3o padr\u00e3o", diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue index 017d304e39b5..5b51da8884c0 100644 --- a/ui/src/components/view/DetailsTab.vue +++ b/ui/src/components/view/DetailsTab.vue @@ -110,6 +110,15 @@
{{ JSON.stringify(JSON.parse(dataResource[item]), null, 4) || dataResource[item] }}
+
+
+
+ + {{ resource.resourcename }} + +
+
+
{{ dataResource[item] }}
@@ -145,6 +154,7 @@ import DedicateData from './DedicateData' import HostInfo from '@/views/infra/HostInfo' import VmwareData from './VmwareData' +import { genericCompare } from '@/utils/sort' export default { name: 'DetailsTab', @@ -371,6 +381,16 @@ export default { }, getDetailTitle (detail) { return `label.${String(this.detailsTitles[detail]).toLowerCase()}` + }, + getResourceLink (type, id) { + return `/${type.toLowerCase()}/${id}` + }, + sortDedicatedResourcesByName (resources) { + resources.sort((resource, otherResource) => { + return genericCompare(resource.resourcename, otherResource.resourcename) + }) + + return resources } } } diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index 4c5a61e3bdcf..94a7464197ce 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -977,7 +977,7 @@ export default { } return fields }, - details: ['name', 'id', 'description', 'type', 'account', 'domain'], + details: ['name', 'id', 'description', 'type', 'account', 'domain', 'dedicatedresources'], related: [{ name: 'vm', title: 'label.instances', From e09debd4243479fa2edc9a1b948fcaf57354fae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Mon, 10 Jun 2024 17:00:49 -0300 Subject: [PATCH 5/6] add end of line to DedicatedResourceResponse class --- .../apache/cloudstack/dedicated/DedicatedResourceResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java b/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java index d4743faa1b81..fc116cbb91e3 100644 --- a/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java +++ b/api/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceResponse.java @@ -41,4 +41,4 @@ public DedicatedResourceResponse(String resourceId, String resourceName, Dedicat this.resourceName = resourceName; this.resourceType = resourceType; } -} \ No newline at end of file +} From de9cc41421a2c9265ac0c8aa401418fe10bab3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Thu, 18 Jul 2024 19:05:35 -0300 Subject: [PATCH 6/6] remove unnecessary fully qualified names --- .../cloudstack/dedicated/DedicatedResourceManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java b/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java index 88c91430b32e..4f1db396b7c4 100644 --- a/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java +++ b/plugins/dedicated-resources/src/main/java/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java @@ -373,7 +373,7 @@ public List dedicatePod(final Long podId, final Long domain @Override public List doInTransaction(TransactionStatus status) { // find or create the affinity group by name under this account/domain - AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, com.cloud.dc.DedicatedResources.Type.Pod); + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, DedicatedResources.Type.Pod); if (group == null) { logger.error("Unable to dedicate pod due to, failed to create dedication affinity group"); throw new CloudRuntimeException("Failed to dedicate pod. Please contact Cloud Support."); @@ -583,7 +583,7 @@ public List dedicateHost(final Long hostId, final Long doma @Override public List doInTransaction(TransactionStatus status) { // find or create the affinity group by name under this account/domain - AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, com.cloud.dc.DedicatedResources.Type.Host); + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountIdFinal, DedicatedResources.Type.Host); if (group == null) { logger.error("Unable to dedicate host due to, failed to create dedication affinity group"); throw new CloudRuntimeException("Failed to dedicate host. Please contact Cloud Support.");