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'