From b8f8321f0f9eb41c66bcedf91527c13a14431928 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Thu, 4 Apr 2024 17:16:44 +0530 Subject: [PATCH 1/2] Allow listing of inactive offerings (#8821) --- .../admin/offering/UpdateDiskOfferingCmd.java | 12 +++ .../offering/UpdateServiceOfferingCmd.java | 15 ++++ .../user/offering/ListDiskOfferingsCmd.java | 21 +++++ .../offering/ListServiceOfferingsCmd.java | 22 ++++- .../api/response/DiskOfferingResponse.java | 12 +++ .../api/response/ServiceOfferingResponse.java | 12 +++ .../db/views/cloud.disk_offering_view.sql | 2 - .../db/views/cloud.service_offering_view.sql | 5 +- .../com/cloud/api/query/QueryManagerImpl.java | 21 ++++- .../query/dao/DiskOfferingJoinDaoImpl.java | 1 + .../query/dao/ServiceOfferingJoinDaoImpl.java | 1 + .../api/query/vo/ServiceOfferingJoinVO.java | 11 +++ .../ConfigurationManagerImpl.java | 23 +++++- .../ConfigurationManagerTest.java | 16 ++-- ui/public/locales/en.json | 19 +++-- ui/src/config/section/offering.js | 81 ++++++++++++++++--- ui/src/views/AutogenView.vue | 9 ++- 17 files changed, 242 insertions(+), 41 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java index 1d5898ea4a0..424ee1609ad 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.admin.offering; import java.util.ArrayList; import java.util.List; +import com.cloud.offering.DiskOffering.State; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; @@ -27,6 +28,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; +import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -123,6 +125,9 @@ public class UpdateDiskOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.CACHE_MODE, type = CommandType.STRING, description = "the cache mode to use for this disk offering", since = "4.15") private String cacheMode; + @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "state of the disk offering") + private String diskOfferingState; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -262,6 +267,13 @@ public class UpdateDiskOfferingCmd extends BaseCmd { public Long getIopsWriteRateMaxLength() { return iopsWriteRateMaxLength; } + public State getState() { + State state = EnumUtils.getEnumIgnoreCase(State.class, diskOfferingState); + if (StringUtils.isNotBlank(diskOfferingState) && state == null) { + throw new InvalidParameterValueException("Invalid state value: " + diskOfferingState); + } + return state; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java index d86564a60c6..2f3dba4d9c5 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.admin.offering; import java.util.ArrayList; import java.util.List; +import com.cloud.offering.ServiceOffering.State; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; @@ -27,6 +28,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -84,6 +86,11 @@ public class UpdateServiceOfferingCmd extends BaseCmd { since = "4.16") private String hostTags; + @Parameter(name = ApiConstants.STATE, + type = CommandType.STRING, + description = "state of the service offering") + private String serviceOfferingState; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -172,6 +179,14 @@ public class UpdateServiceOfferingCmd extends BaseCmd { return hostTags; } + public State getState() { + State state = EnumUtils.getEnumIgnoreCase(State.class, serviceOfferingState); + if (StringUtils.isNotBlank(serviceOfferingState) && state == null) { + throw new InvalidParameterValueException("Invalid state value: " + serviceOfferingState); + } + return state; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java index e7284d515a2..6f32b58b733 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java @@ -16,10 +16,13 @@ // under the License. package org.apache.cloudstack.api.command.user.offering; +import com.cloud.offering.DiskOffering.State; import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -29,6 +32,8 @@ import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.ListResponse; +import static com.cloud.offering.DiskOffering.State.Active; + @APICommand(name = "listDiskOfferings", description = "Lists all available disk offerings.", responseObject = DiskOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class ListDiskOfferingsCmd extends BaseListProjectAndAccountResourcesCmd { @@ -67,6 +72,11 @@ public class ListDiskOfferingsCmd extends BaseListProjectAndAccountResourcesCmd since = "4.19") private String storageType; + @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, + description = "Filter by state of the disk offering. Defaults to 'Active'. If set to 'all' shows both Active & Inactive offerings.", + since = "4.19") + private String diskOfferingState; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -95,6 +105,17 @@ public class ListDiskOfferingsCmd extends BaseListProjectAndAccountResourcesCmd return storageType; } + public State getState() { + if (StringUtils.isBlank(diskOfferingState)) { + return Active; + } + State state = EnumUtils.getEnumIgnoreCase(State.class, diskOfferingState); + if (!diskOfferingState.equalsIgnoreCase("all") && state == null) { + throw new IllegalArgumentException("Invalid state value: " + diskOfferingState); + } + return state; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java index a9a699ed3ef..246984aaada 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java @@ -16,18 +16,22 @@ // under the License. package org.apache.cloudstack.api.command.user.offering; +import com.cloud.offering.ServiceOffering.State; import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.UserVmResponse; +import static com.cloud.offering.ServiceOffering.State.Active; + @APICommand(name = "listServiceOfferings", description = "Lists all available service offerings.", responseObject = ServiceOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesCmd { @@ -95,6 +99,11 @@ public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesC since = "4.19") private String storageType; + @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, + description = "Filter by state of the service offering. Defaults to 'Active'. If set to 'all' shows both Active & Inactive offerings.", + since = "4.19") + private String serviceOfferingState; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -141,6 +150,17 @@ public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesC return storageType; } + public State getState() { + if (StringUtils.isBlank(serviceOfferingState)) { + return Active; + } + State state = EnumUtils.getEnumIgnoreCase(State.class, serviceOfferingState); + if (!serviceOfferingState.equalsIgnoreCase("all") && state == null) { + throw new IllegalArgumentException("Invalid state value: " + serviceOfferingState); + } + return state; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java index b8244aebc60..5b4434fbd8d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java @@ -53,6 +53,10 @@ public class DiskOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "the name of the disk offering") private String name; + @SerializedName(ApiConstants.STATE) + @Param(description = "state of the disk offering") + private String state; + @SerializedName(ApiConstants.DISPLAY_TEXT) @Param(description = "an alternate display text of the disk offering.") private String displayText; @@ -226,6 +230,14 @@ public class DiskOfferingResponse extends BaseResponseWithAnnotations { this.name = name; } + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + public String getDisplayText() { return displayText; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index 53767adf17d..c7740c19214 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -37,6 +37,10 @@ public class ServiceOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "the name of the service offering") private String name; + @SerializedName("state") + @Param(description = "state of the service offering") + private String state; + @SerializedName("displaytext") @Param(description = "an alternate display text of the service offering.") private String displayText; @@ -249,6 +253,14 @@ public class ServiceOfferingResponse extends BaseResponseWithAnnotations { this.name = name; } + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + public Boolean getIsSystem() { return isSystem; } diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.disk_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.disk_offering_view.sql index 10dd3c2f9de..dffaec575ce 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.disk_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.disk_offering_view.sql @@ -76,7 +76,5 @@ FROM LEFT JOIN `cloud`.`disk_offering_details` AS `vsphere_storage_policy` ON `vsphere_storage_policy`.`offering_id` = `disk_offering`.`id` AND `vsphere_storage_policy`.`name` = 'storagepolicy' -WHERE - `disk_offering`.`state`='Active' GROUP BY `disk_offering`.`id`; diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.service_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.service_offering_view.sql index da5172e39cc..c894429adf8 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.service_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.service_offering_view.sql @@ -24,6 +24,7 @@ SELECT `service_offering`.`id` AS `id`, `service_offering`.`uuid` AS `uuid`, `service_offering`.`name` AS `name`, + `service_offering`.`state` AS `state`, `service_offering`.`display_text` AS `display_text`, `disk_offering`.`provisioning_type` AS `provisioning_type`, `service_offering`.`created` AS `created`, @@ -84,7 +85,7 @@ SELECT FROM `cloud`.`service_offering` INNER JOIN - `cloud`.`disk_offering` ON service_offering.disk_offering_id = disk_offering.id AND `disk_offering`.`state`='Active' + `cloud`.`disk_offering` ON service_offering.disk_offering_id = disk_offering.id LEFT JOIN `cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `service_offering`.`id` AND `domain_details`.`name`='domainid' LEFT JOIN @@ -108,7 +109,5 @@ FROM LEFT JOIN `cloud`.`service_offering_details` AS `vsphere_storage_policy` ON `vsphere_storage_policy`.`service_offering_id` = `service_offering`.`id` AND `vsphere_storage_policy`.`name` = 'storagepolicy' -WHERE - `service_offering`.`state`='Active' GROUP BY `service_offering`.`id`; diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index db462373eed..d72e4760f57 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -3332,6 +3332,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Long storagePoolId = cmd.getStoragePoolId(); Boolean encrypt = cmd.getEncrypt(); String storageType = cmd.getStorageType(); + DiskOffering.State state = cmd.getState(); Filter searchFilter = new Filter(DiskOfferingVO.class, "sortKey", SortKeyAscending.value(), cmd.getStartIndex(), cmd.getPageSizeVal()); searchFilter.addOrderBy(DiskOfferingVO.class, "id", true); @@ -3339,7 +3340,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q diskOfferingSearch.select(null, Func.DISTINCT, diskOfferingSearch.entity().getId()); // select distinct diskOfferingSearch.and("computeOnly", diskOfferingSearch.entity().isComputeOnly(), Op.EQ); - diskOfferingSearch.and("activeState", diskOfferingSearch.entity().getState(), Op.EQ); + + if (state != null) { + diskOfferingSearch.and("state", diskOfferingSearch.entity().getState(), Op.EQ); + } // Keeping this logic consistent with domain specific zones // if a domainId is provided, we just return the disk offering @@ -3452,7 +3456,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q SearchCriteria sc = diskOfferingSearch.create(); sc.setParameters("computeOnly", false); - sc.setParameters("activeState", DiskOffering.State.Active); + + if (state != null) { + sc.setParameters("state", state); + } if (keyword != null) { sc.setParameters("keywordDisplayText", "%" + keyword + "%"); @@ -3595,6 +3602,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Integer cpuSpeed = cmd.getCpuSpeed(); Boolean encryptRoot = cmd.getEncryptRoot(); String storageType = cmd.getStorageType(); + ServiceOffering.State state = cmd.getState(); final Account owner = accountMgr.finalizeOwner(caller, accountName, domainId, projectId); @@ -3629,7 +3637,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q SearchBuilder serviceOfferingSearch = _srvOfferingDao.createSearchBuilder(); serviceOfferingSearch.select(null, Func.DISTINCT, serviceOfferingSearch.entity().getId()); // select distinct - serviceOfferingSearch.and("activeState", serviceOfferingSearch.entity().getState(), Op.EQ); + + if (state != null) { + serviceOfferingSearch.and("state", serviceOfferingSearch.entity().getState(), Op.EQ); + } if (vmId != null) { currentVmOffering = _srvOfferingDao.findByIdIncludingRemoved(vmInstance.getId(), vmInstance.getServiceOfferingId()); @@ -3908,7 +3919,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q } SearchCriteria sc = serviceOfferingSearch.create(); - sc.setParameters("activeState", ServiceOffering.State.Active); + if (state != null) { + sc.setParameters("state", state); + } if (vmId != null) { if (!currentVmOffering.isDynamic()) { diff --git a/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java index 5341b3b56d7..14fc56cefc9 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java @@ -105,6 +105,7 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase zoneIds = cmd.getZoneIds(); String storageTags = cmd.getStorageTags(); String hostTags = cmd.getHostTags(); + ServiceOffering.State state = cmd.getState(); if (userId == null) { userId = Long.valueOf(User.UID_SYSTEM); @@ -3540,7 +3541,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException(String.format("Unable to update service offering: %s by id user: %s because it is not root-admin or domain-admin", offeringHandle.getUuid(), user.getUuid())); } - final boolean updateNeeded = name != null || displayText != null || sortKey != null || storageTags != null || hostTags != null; + final boolean updateNeeded = name != null || displayText != null || sortKey != null || storageTags != null || hostTags != null || state != null; final boolean detailsUpdateNeeded = !filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds); if (!updateNeeded && !detailsUpdateNeeded) { return _serviceOfferingDao.findById(id); @@ -3560,8 +3561,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati offering.setSortKey(sortKey); } + if (state != null) { + offering.setState(state); + } + DiskOfferingVO diskOffering = _diskOfferingDao.findById(offeringHandle.getDiskOfferingId()); updateOfferingTagsIfIsNotNull(storageTags, diskOffering); + + if (diskOffering.isComputeOnly() && state != null) { + diskOffering.setState(state == ServiceOffering.State.Active ? DiskOffering.State.Active : DiskOffering.State.Inactive); + } + _diskOfferingDao.update(diskOffering.getId(), diskOffering); updateServiceOfferingHostTagsIfNotNull(hostTags, offering); @@ -3916,6 +3926,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Long iopsWriteRateMax = cmd.getIopsWriteRateMax(); Long iopsWriteRateMaxLength = cmd.getIopsWriteRateMaxLength(); String cacheMode = cmd.getCacheMode(); + DiskOffering.State state = cmd.getState(); // Check if diskOffering exists final DiskOffering diskOfferingHandle = _entityMgr.findById(DiskOffering.class, diskOfferingId); @@ -3969,7 +3980,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException(String.format("Unable to update disk offering: %s by id user: %s because it is not root-admin or domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); } - boolean updateNeeded = shouldUpdateDiskOffering(name, displayText, sortKey, displayDiskOffering, tags, cacheMode) || + boolean updateNeeded = shouldUpdateDiskOffering(name, displayText, sortKey, displayDiskOffering, tags, cacheMode, state) || shouldUpdateIopsRateParameters(iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength) || shouldUpdateBytesRateParameters(bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength); @@ -3997,6 +4008,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati diskOffering.setCacheMode(DiskOffering.DiskCacheMode.valueOf(cacheMode.toUpperCase())); } + if (state != null) { + diskOffering.setState(state); + } + if (updateNeeded && !_diskOfferingDao.update(diskOfferingId, diskOffering)) { return null; } @@ -4217,8 +4232,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati * Check if it needs to update any parameter when updateDiskoffering is called * Verify if name or displayText are not blank, tags is not null, sortkey and displayDiskOffering is not null */ - protected boolean shouldUpdateDiskOffering(String name, String displayText, Integer sortKey, Boolean displayDiskOffering, String tags, String cacheMode) { - return !StringUtils.isAllBlank(name, displayText, cacheMode) || tags != null || sortKey != null || displayDiskOffering != null; + protected boolean shouldUpdateDiskOffering(String name, String displayText, Integer sortKey, Boolean displayDiskOffering, String tags, String cacheMode, DiskOffering.State state) { + return !StringUtils.isAllBlank(name, displayText, cacheMode) || tags != null || sortKey != null || displayDiskOffering != null || state != null; } protected boolean shouldUpdateBytesRateParameters(Long bytesReadRate, Long bytesReadRateMax, Long bytesReadRateMaxLength, Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength) { diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java index c2d748ee587..4b9441dd2ea 100644 --- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java +++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java @@ -56,6 +56,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.offering.DiskOffering; import com.cloud.projects.ProjectManager; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.StoragePoolTagVO; @@ -1074,17 +1075,18 @@ public class ConfigurationManagerTest { @Test public void shouldUpdateDiskOfferingTests(){ - Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(Mockito.anyString(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyBoolean(), Mockito.anyString(), Mockito.anyString())); - Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(Mockito.anyString(), nullable(String.class), nullable(Integer.class), nullable(Boolean.class), nullable(String.class), nullable(String.class))); - Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), Mockito.anyString(), nullable(Integer.class), nullable(Boolean.class), nullable(String.class), nullable(String.class))); - Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), Mockito.anyInt(), nullable(Boolean.class), nullable(String.class), nullable(String.class))); - Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), nullable(int.class), Mockito.anyBoolean(), nullable(String.class), nullable(String.class))); - Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), nullable(int.class), nullable(Boolean.class), Mockito.anyString(), Mockito.anyString())); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(Mockito.anyString(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyBoolean(), Mockito.anyString(), Mockito.anyString(), Mockito.any(DiskOffering.State.class))); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(Mockito.anyString(), nullable(String.class), nullable(Integer.class), nullable(Boolean.class), nullable(String.class), nullable(String.class), nullable(DiskOffering.State.class))); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), nullable(Integer.class), nullable(Boolean.class), nullable(String.class), nullable(String.class), Mockito.any(DiskOffering.State.class))); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), Mockito.anyString(), nullable(Integer.class), nullable(Boolean.class), nullable(String.class), nullable(String.class), nullable(DiskOffering.State.class))); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), Mockito.anyInt(), nullable(Boolean.class), nullable(String.class), nullable(String.class), nullable(DiskOffering.State.class))); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), nullable(int.class), Mockito.anyBoolean(), nullable(String.class), nullable(String.class), nullable(DiskOffering.State.class))); + Assert.assertTrue(configurationMgr.shouldUpdateDiskOffering(nullable(String.class), nullable(String.class), nullable(int.class), nullable(Boolean.class), Mockito.anyString(), Mockito.anyString(), nullable(DiskOffering.State.class))); } @Test public void shouldUpdateDiskOfferingTestFalse(){ - Assert.assertFalse(configurationMgr.shouldUpdateDiskOffering(null, null, null, null, null, null)); + Assert.assertFalse(configurationMgr.shouldUpdateDiskOffering(null, null, null, null, null, null, null)); } @Test diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 245e9efc23f..be9d4e72056 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -71,7 +71,6 @@ "label.action.delete.account": "Delete Account", "label.action.delete.backup.offering": "Delete backup offering", "label.action.delete.cluster": "Delete cluster", -"label.action.delete.disk.offering": "Delete disk offering", "label.action.delete.domain": "Delete domain", "label.action.delete.egress.firewall": "Delete egress firewall rule", "label.action.delete.firewall": "Delete firewall rule", @@ -91,9 +90,7 @@ "label.action.delete.primary.storage": "Delete primary storage", "label.action.delete.secondary.storage": "Delete secondary storage", "label.action.delete.security.group": "Delete security group", -"label.action.delete.service.offering": "Delete service offering", "label.action.delete.snapshot": "Delete Snapshot", -"label.action.delete.system.service.offering": "Delete system service offering", "label.action.delete.template": "Delete Template", "label.action.delete.tungsten.router.table": "Remove Tungsten Fabric route table from Network", "label.action.delete.user": "Delete User", @@ -106,9 +103,12 @@ "label.action.detach.iso": "Detach ISO", "label.action.disable.account": "Disable Account", "label.action.disable.cluster": "Disable cluster", +"label.action.disable.disk.offering": "Disable disk offering", "label.action.disable.physical.network": "Disable physical Network", "label.action.disable.pod": "Disable pod", "label.action.disable.static.nat": "Disable static NAT", +"label.action.disable.service.offering": "Disable service offering", +"label.action.disable.system.service.offering": "Disable system service offering", "label.action.disable.user": "Disable User", "label.action.disable.zone": "Disable zone", "label.action.download.iso": "Download ISO", @@ -124,9 +124,12 @@ "label.action.verify.two.factor.authentication": "Verified Two factor authentication", "label.action.enable.account": "Enable Account", "label.action.enable.cluster": "Enable cluster", +"label.action.enable.disk.offering": "Enable disk offering", "label.action.enable.maintenance.mode": "Enable maintenance mode", "label.action.enable.physical.network": "Enable physical Network", "label.action.enable.pod": "Enable pod", +"label.action.enable.service.offering": "Enable service offering", +"label.action.enable.system.service.offering": "Enable system service offering", "label.action.enable.static.nat": "Enable static NAT", "label.action.enable.user": "Enable User", "label.action.enable.zone": "Enable zone", @@ -1021,6 +1024,7 @@ "label.import.instance": "Import Instance", "label.import.offering": "Import offering", "label.import.role": "Import role", +"label.inactive": "Inactive", "label.in.progress": "in progress", "label.in.progress.for": "in progress for", "label.info": "Info", @@ -2396,7 +2400,6 @@ "message.action.delete.autoscale.vmgroup": "Please confirm that you want to delete this autoscale Instance group.", "message.action.delete.backup.offering": "Please confirm that you want to delete this backup offering?", "message.action.delete.cluster": "Please confirm that you want to delete this cluster.", -"message.action.delete.disk.offering": "Please confirm that you want to delete this disk offering.", "message.action.delete.domain": "Please confirm that you want to delete this domain.", "message.action.delete.external.firewall": "Please confirm that you would like to remove this external firewall. Warning: If you are planning to add back the same external firewall, you must reset usage data on the device.", "message.action.delete.external.load.balancer": "Please confirm that you would like to remove this external load balancer. Warning: If you are planning to add back the same external load balancer, you must reset usage data on the device.", @@ -2415,9 +2418,7 @@ "message.action.delete.pod": "Please confirm that you want to delete this pod.", "message.action.delete.secondary.storage": "Please confirm that you want to delete this secondary storage.", "message.action.delete.security.group": "Please confirm that you want to delete this security group.", -"message.action.delete.service.offering": "Please confirm that you want to delete this service offering.", "message.action.delete.snapshot": "Please confirm that you want to delete this Snapshot.", -"message.action.delete.system.service.offering": "Please confirm that you want to delete this system service offering.", "message.action.delete.template": "Please confirm that you want to delete this Template.", "message.action.delete.tungsten.router.table": "Please confirm that you want to remove Route Table from this Network?", "message.action.delete.volume": "Please confirm that you want to delete this volume. Note: this will not delete any Snapshots of this volume.", @@ -2430,6 +2431,9 @@ "message.action.disable.2FA.user.auth": "Please confirm that you want to disable User two factor authentication.", "message.action.about.mandate.and.disable.2FA.user.auth": "Two factor authentication is mandated for the User, if this is disabled now User will need to setup two factor authentication again during next login.

Please confirm that you want to disable.", "message.action.disable.cluster": "Please confirm that you want to disable this cluster.", +"message.action.disable.disk.offering": "Please confirm that you want to disable this disk offering.", +"message.action.disable.service.offering": "Please confirm that you want to disable this service offering.", +"message.action.disable.system.service.offering": "Please confirm that you want to disable this system service offering.", "message.action.disable.physical.network": "Please confirm that you want to disable this physical Network.", "message.action.disable.pod": "Please confirm that you want to disable this pod.", "message.action.disable.static.nat": "Please confirm that you want to disable static NAT.", @@ -2437,6 +2441,9 @@ "message.action.download.iso": "Please confirm that you want to download this ISO.", "message.action.download.template": "Please confirm that you want to download this Template.", "message.action.enable.cluster": "Please confirm that you want to enable this cluster.", +"message.action.enable.disk.offering": "Please confirm that you want to enable this disk offering.", +"message.action.enable.service.offering": "Please confirm that you want to enable this service offering.", +"message.action.enable.system.service.offering": "Please confirm that you want to enable this system service offering.", "message.action.enable.physical.network": "Please confirm that you want to enable this physical Network.", "message.action.enable.pod": "Please confirm that you want to enable this pod.", "message.action.enable.zone": "Please confirm that you want to enable this zone.", diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index 27e7d32073a..3f040924242 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -36,7 +36,8 @@ export default { } return params }, - columns: ['name', 'displaytext', 'cpunumber', 'cpuspeed', 'memory', 'domain', 'zone', 'order'], + filters: ['active', 'inactive'], + columns: ['name', 'displaytext', 'state', 'cpunumber', 'cpuspeed', 'memory', 'domain', 'zone', 'order'], details: () => { var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'storagetags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness', 'encryptroot'] if (store.getters.apis.createServiceOffering && @@ -89,15 +90,33 @@ export default { dataView: true, popup: true, component: shallowRef(defineAsyncComponent(() => import('@/views/offering/UpdateOfferingAccess.vue'))) + }, + { + api: 'updateServiceOffering', + icon: 'play-circle-outlined', + label: 'label.action.enable.service.offering', + message: 'message.action.enable.service.offering', + dataView: true, + args: ['state'], + mapping: { + state: { + value: (record) => { return 'Active' } + } + }, + groupAction: true, + popup: true, + show: (record) => { return record.state !== 'Active' }, + groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Active' } }) } }, { api: 'deleteServiceOffering', - icon: 'delete-outlined', - label: 'label.action.delete.service.offering', - message: 'message.action.delete.service.offering', + icon: 'pause-circle-outlined', + label: 'label.action.disable.service.offering', + message: 'message.action.disable.service.offering', docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering', dataView: true, groupAction: true, popup: true, + show: (record) => { return record.state === 'Active' }, groupMap: (selection) => { return selection.map(x => { return { id: x } }) } }] }, @@ -108,7 +127,8 @@ export default { docHelp: 'adminguide/service_offerings.html#system-service-offerings', permission: ['listServiceOfferings', 'listInfrastructure'], params: { issystem: 'true', isrecursive: 'true' }, - columns: ['name', 'systemvmtype', 'cpunumber', 'cpuspeed', 'memory', 'storagetype', 'order'], + columns: ['name', 'state', 'systemvmtype', 'cpunumber', 'cpuspeed', 'memory', 'storagetype', 'order'], + filters: ['active', 'inactive'], details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'storagetags', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness'], actions: [{ api: 'createServiceOffering', @@ -127,16 +147,34 @@ export default { params: { issystem: 'true' }, docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering', args: ['name', 'displaytext', 'storagetags', 'hosttags'] + }, { + api: 'updateServiceOffering', + icon: 'play-circle-outlined', + label: 'label.action.enable.system.service.offering', + message: 'message.action.enable.system.service.offering', + dataView: true, + params: { issystem: 'true' }, + args: ['state'], + mapping: { + state: { + value: (record) => { return 'Active' } + } + }, + groupAction: true, + popup: true, + show: (record) => { return record.state !== 'Active' }, + groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Active' } }) } }, { api: 'deleteServiceOffering', - icon: 'delete-outlined', - label: 'label.action.delete.system.service.offering', - message: 'message.action.delete.system.service.offering', + icon: 'pause-circle-outlined', + label: 'label.action.disable.system.service.offering', + message: 'message.action.disable.system.service.offering', docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering', dataView: true, params: { issystem: 'true' }, groupAction: true, popup: true, + show: (record) => { return record.state === 'Active' }, groupMap: (selection) => { return selection.map(x => { return { id: x } }) } }] }, @@ -153,7 +191,8 @@ export default { } return params }, - columns: ['name', 'displaytext', 'disksize', 'domain', 'zone', 'order'], + columns: ['name', 'displaytext', 'state', 'disksize', 'domain', 'zone', 'order'], + filters: ['active', 'inactive'], details: () => { var fields = ['name', 'id', 'displaytext', 'disksize', 'provisioningtype', 'storagetype', 'iscustomized', 'disksizestrictness', 'iscustomizediops', 'diskIopsReadRate', 'diskIopsWriteRate', 'diskBytesReadRate', 'diskBytesWriteRate', 'miniops', 'maxiops', 'tags', 'domain', 'zone', 'created', 'encrypt'] if (store.getters.apis.createDiskOffering && @@ -202,15 +241,33 @@ export default { dataView: true, popup: true, component: shallowRef(defineAsyncComponent(() => import('@/views/offering/UpdateOfferingAccess.vue'))) + }, { + api: 'updateDiskOffering', + icon: 'play-circle-outlined', + label: 'label.action.enable.disk.offering', + message: 'message.action.enable.disk.offering', + dataView: true, + params: { issystem: 'true' }, + args: ['state'], + mapping: { + state: { + value: (record) => { return 'Active' } + } + }, + groupAction: true, + popup: true, + show: (record) => { return record.state !== 'Active' }, + groupMap: (selection) => { return selection.map(x => { return { id: x, state: 'Active' } }) } }, { api: 'deleteDiskOffering', - icon: 'delete-outlined', - label: 'label.action.delete.disk.offering', - message: 'message.action.delete.disk.offering', + icon: 'pause-circle-outlined', + label: 'label.action.disable.disk.offering', + message: 'message.action.disable.disk.offering', docHelp: 'adminguide/service_offerings.html#modifying-or-deleting-a-service-offering', dataView: true, groupAction: true, popup: true, + show: (record) => { return record.state === 'Active' }, groupMap: (selection) => { return selection.map(x => { return { id: x } }) } }] }, diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 77ee73d700c..be6c0f24cd1 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -51,7 +51,7 @@ @@ -690,7 +690,7 @@ export default { if (['volume'].includes(routeName)) { return 'user' } - if (['event'].includes(routeName)) { + if (['event', 'computeoffering', 'systemoffering', 'diskoffering'].includes(routeName)) { return 'active' } return 'self' @@ -769,6 +769,9 @@ export default { 'isofilter' in params && this.routeName === 'iso') { params.isofilter = 'all' } + if (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) && ['computeoffering', 'systemoffering', 'diskoffering'].includes(this.routeName) && this.$route.params.id) { + params.state = 'all' + } if (Object.keys(this.$route.query).length > 0) { if ('page' in this.$route.query) { this.page = Number(this.$route.query.page) @@ -1757,6 +1760,8 @@ export default { } else { query.clustertype = filter === 'cloud.managed' ? 'CloudManaged' : 'ExternalManaged' } + } else if (['computeoffering', 'systemoffering', 'diskoffering'].includes(this.$route.name)) { + query.state = filter } query.filter = filter query.page = '1' From c25264bada3b84118b4b20720426625bf6e4b1c0 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Thu, 4 Apr 2024 17:21:56 +0530 Subject: [PATCH 2/2] UI Fixes: allow filtering on alertype in UI & add events tab (#8630) --- .../apache/cloudstack/alert/AlertService.java | 4 ++ .../acl/project/CreateProjectRoleCmd.java | 10 ++++ .../CreateProjectRolePermissionCmd.java | 11 ++++ .../acl/project/DeleteProjectRoleCmd.java | 11 ++++ .../DeleteProjectRolePermissionCmd.java | 11 ++++ .../acl/project/UpdateProjectRoleCmd.java | 11 ++++ .../UpdateProjectRolePermissionCmd.java | 11 ++++ .../ChangeOutOfBandManagementPasswordCmd.java | 11 ++++ .../ConfigureOutOfBandManagementCmd.java | 11 ++++ ...sableOutOfBandManagementForClusterCmd.java | 11 ++++ .../DisableOutOfBandManagementForHostCmd.java | 11 ++++ .../DisableOutOfBandManagementForZoneCmd.java | 11 ++++ ...nableOutOfBandManagementForClusterCmd.java | 11 ++++ .../EnableOutOfBandManagementForHostCmd.java | 11 ++++ .../EnableOutOfBandManagementForZoneCmd.java | 11 ++++ ...ssueOutOfBandManagementPowerActionCmd.java | 5 ++ .../admin/resource/ListAlertTypesCmd.java | 54 +++++++++++++++++ .../user/vmsnapshot/CreateVMSnapshotCmd.java | 6 ++ .../api/response/AlertTypeResponse.java | 55 +++++++++++++++++ .../cloud/server/ManagementServerImpl.java | 2 + ui/src/components/view/SearchView.vue | 44 +++++++++++++- ui/src/config/section/compute.js | 18 ++++++ ui/src/config/section/infra.js | 1 + ui/src/config/section/infra/hosts.js | 5 ++ ui/src/config/section/infra/ilbvms.js | 11 ++++ ui/src/config/section/network.js | 11 ++++ ui/src/config/section/offering.js | 60 +++++++++++++++++++ ui/src/config/section/role.js | 7 +++ ui/src/config/section/user.js | 2 +- ui/src/views/network/PublicIpResource.vue | 12 ++++ 30 files changed, 448 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java index 50e48526d26..1250284b5c2 100644 --- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java @@ -91,6 +91,10 @@ public interface AlertService { return null; } + public static Set getAlertTypes() { + return defaultAlertTypes; + } + @Override public String toString() { return String.valueOf(this.getType()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java index c03e6112ea7..ed17a876b24 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.api.command.admin.acl.project; import org.apache.cloudstack.acl.ProjectRole; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -70,4 +71,13 @@ public class CreateProjectRoleCmd extends ProjectRoleCmd { return Account.ACCOUNT_ID_SYSTEM; } + @Override + public Long getApiResourceId() { + return getProjectId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Project; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java index 9b6c2e633fc..d39c2312aa9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java @@ -22,6 +22,7 @@ import org.apache.cloudstack.acl.ProjectRolePermission; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.Parameter; @@ -96,4 +97,14 @@ public class CreateProjectRolePermissionCmd extends BaseRolePermissionCmd { response.setObjectName("projectrolepermission"); setResponseObject(response); } + + @Override + public Long getApiResourceId() { + return getProjectId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Project; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRoleCmd.java index 4bb460c63f7..9f8d8248958 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRoleCmd.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.acl.ProjectRole; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -79,4 +80,14 @@ public class DeleteProjectRoleCmd extends BaseCmd { public long getEntityOwnerId() { return CallContext.current().getCallingAccountId(); } + + @Override + public Long getApiResourceId() { + return getProjectId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Project; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRolePermissionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRolePermissionCmd.java index 8b83253c869..ac68278535e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRolePermissionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/DeleteProjectRolePermissionCmd.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.acl.ProjectRolePermission; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -80,4 +81,14 @@ public class DeleteProjectRolePermissionCmd extends BaseCmd { public long getEntityOwnerId() { return CallContext.current().getCallingAccountId(); } + + @Override + public Long getApiResourceId() { + return getProjectId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Project; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRoleCmd.java index 202daa3d49c..3bc8b3d6186 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRoleCmd.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.acl.ProjectRole; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -76,4 +77,14 @@ public class UpdateProjectRoleCmd extends ProjectRoleCmd { public long getEntityOwnerId() { return 0; } + + @Override + public Long getApiResourceId() { + return getProjectId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Project; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java index d27235e5aae..dd59310c66a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.acl.ProjectRolePermission; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -154,4 +155,14 @@ public class UpdateProjectRolePermissionCmd extends BaseCmd { public long getEntityOwnerId() { return CallContext.current().getCallingAccountId(); } + + @Override + public Long getApiResourceId() { + return getProjectId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Project; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java index dad6506729a..e2c31d6cf07 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java @@ -26,6 +26,7 @@ import com.cloud.host.Host; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -102,4 +103,14 @@ public class ChangeOutOfBandManagementPasswordCmd extends BaseAsyncCmd { public String getEventDescription() { return "change out-of-band management password for host: " + getHostId(); } + + @Override + public Long getApiResourceId() { + return getHostId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Host; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java index 699e2855185..157d3c627db 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java @@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableMap; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -112,4 +113,14 @@ public class ConfigureOutOfBandManagementCmd extends BaseCmd { builder.put(option, value); } } + + @Override + public Long getApiResourceId() { + return getHostId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Host; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java index 604aae66889..445e7b92665 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java @@ -27,6 +27,7 @@ import com.cloud.org.Cluster; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -94,4 +95,14 @@ public class DisableOutOfBandManagementForClusterCmd extends BaseAsyncCmd { public String getEventDescription() { return "disable out-of-band management password for cluster: " + getClusterId(); } + + @Override + public Long getApiResourceId() { + return getClusterId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Cluster; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java index 51c0fbcc3db..7e4444e93fb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java @@ -27,6 +27,7 @@ import com.cloud.host.Host; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -95,4 +96,14 @@ public class DisableOutOfBandManagementForHostCmd extends BaseAsyncCmd { public String getEventDescription() { return "disable out-of-band management password for host: " + getHostId(); } + + @Override + public Long getApiResourceId() { + return getHostId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Host; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java index 4c3e92cf05d..2028f8fc2a0 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java @@ -27,6 +27,7 @@ import com.cloud.exception.ResourceUnavailableException; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -94,4 +95,14 @@ public class DisableOutOfBandManagementForZoneCmd extends BaseAsyncCmd { public String getEventDescription() { return "disable out-of-band management password for zone: " + getZoneId(); } + + @Override + public Long getApiResourceId() { + return getZoneId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Zone; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java index a69f27fb3ac..549743b3172 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java @@ -27,6 +27,7 @@ import com.cloud.org.Cluster; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -94,4 +95,14 @@ public class EnableOutOfBandManagementForClusterCmd extends BaseAsyncCmd { public String getEventDescription() { return "enable out-of-band management password for cluster: " + getClusterId(); } + + @Override + public Long getApiResourceId() { + return getClusterId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Cluster; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java index 5e32c8943bf..834181a5e1c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java @@ -27,6 +27,7 @@ import com.cloud.host.Host; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -95,4 +96,14 @@ public class EnableOutOfBandManagementForHostCmd extends BaseAsyncCmd { public String getEventDescription() { return "enable out-of-band management password for host: " + getHostId(); } + + @Override + public Long getApiResourceId() { + return getHostId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Host; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java index 4eea4d50fe0..de4c4d801de 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java @@ -27,6 +27,7 @@ import com.cloud.exception.ResourceUnavailableException; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -94,4 +95,14 @@ public class EnableOutOfBandManagementForZoneCmd extends BaseAsyncCmd { public String getEventDescription() { return "enable out-of-band management password for zone: " + getZoneId(); } + + @Override + public Long getApiResourceId() { + return getZoneId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.Zone; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java index d10664f0a25..97a813c9d47 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java @@ -114,4 +114,9 @@ public class IssueOutOfBandManagementPowerActionCmd extends BaseAsyncCmd { public ApiCommandResourceType getApiResourceType() { return ApiCommandResourceType.Host; } + + @Override + public Long getApiResourceId() { + return getHostId(); + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java new file mode 100644 index 00000000000..e7bfbdbc625 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/resource/ListAlertTypesCmd.java @@ -0,0 +1,54 @@ +// 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.api.command.admin.resource; + +import com.cloud.user.Account; +import org.apache.cloudstack.alert.AlertService; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.response.AlertResponse; +import org.apache.cloudstack.api.response.AlertTypeResponse; +import org.apache.cloudstack.api.response.ListResponse; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@APICommand(name = "listAlertTypes", description = "Lists all alerts types", responseObject = AlertResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class ListAlertTypesCmd extends BaseCmd { + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Set result = AlertService.AlertType.getAlertTypes(); + ListResponse response = new ListResponse<>(); + List typeResponseList = new ArrayList<>(); + for (AlertService.AlertType alertType : result) { + AlertTypeResponse alertResponse = new AlertTypeResponse(alertType.getType(), alertType.getName()); + alertResponse.setObjectName("alerttype"); + typeResponseList.add(alertResponse); + } + response.setResponses(typeResponseList, result.size()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java index 2c0ea6bc4ae..e83c6b4009d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java @@ -138,4 +138,10 @@ public class CreateVMSnapshotCmd extends BaseAsyncCreateCmd { public ApiCommandResourceType getApiResourceType() { return ApiCommandResourceType.VmSnapshot; } + + @Override + public Long getApiResourceId() { + return getEntityId(); + } + } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java new file mode 100644 index 00000000000..3f91cde0178 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/AlertTypeResponse.java @@ -0,0 +1,55 @@ +// 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.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +public class AlertTypeResponse extends BaseResponse { + + @SerializedName("alerttypeid") + @Param(description = "alert type") + private short alertType; + + @SerializedName(ApiConstants.NAME) + @Param(description = "description of alert type") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public short getUsageType() { + return alertType; + } + + public void setUsageType(short alertType) { + this.alertType = alertType; + } + + public AlertTypeResponse(short alertType, String name) { + this.alertType = alertType; + this.name = name; + setObjectName("alerttype"); + } +} diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 5cd5b92054b..9b635cea5f3 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -185,6 +185,7 @@ import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.CleanVMReservationsCmd; import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.ListAlertTypesCmd; import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd; import org.apache.cloudstack.api.command.admin.resource.StartRollingMaintenanceCmd; @@ -3468,6 +3469,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(RemoveRegionCmd.class); cmdList.add(UpdateRegionCmd.class); cmdList.add(ListAlertsCmd.class); + cmdList.add(ListAlertTypesCmd.class); cmdList.add(ListCapacityCmd.class); cmdList.add(UpdatePodManagementNetworkIpRangeCmd.class); cmdList.add(UploadCustomCertificateCmd.class); diff --git a/ui/src/components/view/SearchView.vue b/ui/src/components/view/SearchView.vue index 9e65cdb36eb..7a2154ad426 100644 --- a/ui/src/components/view/SearchView.vue +++ b/ui/src/components/view/SearchView.vue @@ -186,7 +186,8 @@ export default { inputKey: null, inputValue: null, fieldValues: {}, - isFiltered: false + isFiltered: false, + alertTypes: [] } }, created () { @@ -347,6 +348,7 @@ export default { }, async fetchDynamicFieldData (arrayField, searchKeyword) { const promises = [] + let typeIndex = -1 let zoneIndex = -1 let domainIndex = -1 let imageStoreIndex = -1 @@ -355,6 +357,14 @@ export default { let clusterIndex = -1 let groupIndex = -1 + if (arrayField.includes('type')) { + if (this.$route.path === '/alert') { + typeIndex = this.fields.findIndex(item => item.name === 'type') + this.fields[typeIndex].loading = true + promises.push(await this.fetchAlertTypes()) + } + } + if (arrayField.includes('zoneid')) { zoneIndex = this.fields.findIndex(item => item.name === 'zoneid') this.fields[zoneIndex].loading = true @@ -398,6 +408,12 @@ export default { } Promise.all(promises).then(response => { + if (typeIndex > -1) { + const types = response.filter(item => item.type === 'type') + if (types && types.length > 0) { + this.fields[typeIndex].opts = this.sortArray(types[0].data) + } + } if (zoneIndex > -1) { const zones = response.filter(item => item.type === 'zoneid') if (zones && zones.length > 0) { @@ -441,6 +457,9 @@ export default { } } }).finally(() => { + if (typeIndex > -1) { + this.fields[typeIndex].loading = false + } if (zoneIndex > -1) { this.fields[zoneIndex].loading = false } @@ -585,6 +604,29 @@ export default { }) }) }, + fetchAlertTypes () { + if (this.alertTypes.length > 0) { + return new Promise((resolve, reject) => { + resolve({ + type: 'type', + data: this.alertTypes + }) + }) + } else { + return new Promise((resolve, reject) => { + api('listAlertTypes').then(json => { + const alerttypes = json.listalerttypesresponse.alerttype.map(a => { return { id: a.alerttypeid, name: a.name } }) + this.alertTypes = alerttypes + resolve({ + type: 'type', + data: alerttypes + }) + }).catch(error => { + reject(error.response.headers['x-description']) + }) + }) + } + }, fetchGuestNetworkTypes () { const types = [] if (this.apiName.indexOf('listNetworks') > -1) { diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index bd18535f380..9390d2a7d62 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -483,6 +483,12 @@ export default { name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) }, + { + name: 'events', + resourceType: 'VmSnapshot', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }, { name: 'comments', component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))) @@ -990,6 +996,18 @@ export default { title: 'label.instances', param: 'affinitygroupid' }], + tabs: [ + { + name: 'details', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'AffinityGroup', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + } + ], actions: [ { api: 'createAffinityGroup', diff --git a/ui/src/config/section/infra.js b/ui/src/config/section/infra.js index 0b3b1e7ae4f..5b3b38a68e5 100644 --- a/ui/src/config/section/infra.js +++ b/ui/src/config/section/infra.js @@ -79,6 +79,7 @@ export default { permission: ['listAlerts'], columns: ['name', 'description', 'type', 'sent'], details: ['name', 'id', 'type', 'sent', 'description'], + searchFilters: ['type'], actions: [ { api: 'archiveAlerts', diff --git a/ui/src/config/section/infra/hosts.js b/ui/src/config/section/infra/hosts.js index 803e6160de3..d92f4af21e6 100644 --- a/ui/src/config/section/infra/hosts.js +++ b/ui/src/config/section/infra/hosts.js @@ -44,6 +44,11 @@ export default { tabs: [{ name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, { + name: 'events', + resourceType: 'Host', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } }, { name: 'comments', component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))) diff --git a/ui/src/config/section/infra/ilbvms.js b/ui/src/config/section/infra/ilbvms.js index fa20d6990e9..5ab9b3edfc0 100644 --- a/ui/src/config/section/infra/ilbvms.js +++ b/ui/src/config/section/infra/ilbvms.js @@ -16,6 +16,8 @@ // under the License. import { shallowRef, defineAsyncComponent } from 'vue' +import store from '@/store' + export default { name: 'ilbvm', title: 'label.internal.lb', @@ -25,6 +27,15 @@ export default { params: { projectid: '-1' }, columns: ['name', 'state', 'publicip', 'guestnetworkname', 'vpcname', 'version', 'softwareversion', 'hostname', 'account', 'zonename', 'requiresupgrade'], details: ['name', 'id', 'version', 'softwareversion', 'requiresupgrade', 'guestnetworkname', 'vpcname', 'publicip', 'guestipaddress', 'linklocalip', 'serviceofferingname', 'networkdomain', 'isredundantrouter', 'redundantstate', 'hostname', 'account', 'zonename', 'created', 'hostcontrolstate'], + tabs: [{ + name: 'details', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, { + name: 'events', + resourceType: 'InternalLbVm', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }], actions: [ { api: 'startInternalLoadBalancerVM', diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index cd7dfbc828f..3d5241feb59 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -1046,6 +1046,11 @@ export default { name: 'loadbalancerinstance', component: shallowRef(defineAsyncComponent(() => import('@/views/network/InternalLBAssignedVmTab.vue'))), show: () => true + }, { + name: 'events', + resourceType: 'LoadBalancerRule', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } }], actions: [ { @@ -1162,6 +1167,12 @@ export default { name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) }, + { + name: 'events', + resourceType: 'VpnCustomerGateway', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }, { name: 'comments', component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))) diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index 3f040924242..3e99f602d91 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -56,6 +56,12 @@ export default { name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) }, + { + name: 'events', + resourceType: 'ServiceOffering', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }, { name: 'comments', component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))), @@ -130,6 +136,24 @@ export default { columns: ['name', 'state', 'systemvmtype', 'cpunumber', 'cpuspeed', 'memory', 'storagetype', 'order'], filters: ['active', 'inactive'], details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'storagetags', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness'], + resourceType: 'ServiceOffering', + tabs: [ + { + name: 'details', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'ServiceOffering', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }, + { + name: 'comments', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))), + show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) } + } + ], actions: [{ api: 'createServiceOffering', icon: 'plus-outlined', @@ -207,6 +231,12 @@ export default { name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) }, + { + name: 'events', + resourceType: 'DiskOffering', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }, { name: 'comments', component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))), @@ -284,6 +314,18 @@ export default { title: 'label.instances', param: 'backupofferingid' }], + tabs: [ + { + name: 'details', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'BackupOffering', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + } + ], actions: [{ api: 'importBackupOffering', icon: 'plus-outlined', @@ -326,6 +368,12 @@ export default { name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) }, + { + name: 'events', + resourceType: 'NetworkOffering', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + }, { name: 'comments', component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))), @@ -418,6 +466,18 @@ export default { title: 'label.vpc', param: 'vpcofferingid' }], + tabs: [ + { + name: 'details', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'VpcOffering', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } + } + ], actions: [{ api: 'createVPCOffering', icon: 'plus-outlined', diff --git a/ui/src/config/section/role.js b/ui/src/config/section/role.js index d903ea0fae8..3823d633b18 100644 --- a/ui/src/config/section/role.js +++ b/ui/src/config/section/role.js @@ -16,6 +16,8 @@ // under the License. import { shallowRef, defineAsyncComponent } from 'vue' +import store from '@/store' + export default { name: 'role', title: 'label.roles', @@ -30,6 +32,11 @@ export default { }, { name: 'rules', component: shallowRef(defineAsyncComponent(() => import('@/views/iam/RolePermissionTab.vue'))) + }, { + name: 'events', + resourceType: 'Role', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in store.getters.apis } }], actions: [ { diff --git a/ui/src/config/section/user.js b/ui/src/config/section/user.js index eef9ea3f939..d4f4d700db7 100644 --- a/ui/src/config/section/user.js +++ b/ui/src/config/section/user.js @@ -25,7 +25,7 @@ export default { docHelp: 'adminguide/accounts.html#users', hidden: true, permission: ['listUsers'], - columns: ['username', 'state', 'firstname', 'lastname', 'email', 'account'], + columns: ['username', 'state', 'firstname', 'lastname', 'email', 'account', 'domain'], details: ['username', 'id', 'firstname', 'lastname', 'email', 'usersource', 'timezone', 'rolename', 'roletype', 'is2faenabled', 'account', 'domain', 'created'], tabs: [ { diff --git a/ui/src/views/network/PublicIpResource.vue b/ui/src/views/network/PublicIpResource.vue index fdbd96a761a..18bc003b499 100644 --- a/ui/src/views/network/PublicIpResource.vue +++ b/ui/src/views/network/PublicIpResource.vue @@ -66,10 +66,22 @@ export default { tabs: [{ name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'IpAddress', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in this.$store.getters.apis } }], defaultTabs: [{ name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'IpAddress', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in this.$store.getters.apis } }], activeTab: '' }