Service offering category feature#12144
Conversation
- Introduced new API commands for creating, updating, and deleting service offering categories. - Added support for associating service offerings with categories. - Updated database schema to include service offering categories. - Enhanced existing service offering commands to handle category IDs.
…e' into service_offering_category_feature
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #12144 +/- ##
============================================
+ Coverage 18.89% 20.13% +1.24%
- Complexity 18226 18476 +250
============================================
Files 6174 5758 -416
Lines 555226 519685 -35541
Branches 67774 60651 -7123
============================================
- Hits 104895 104645 -250
+ Misses 438810 403607 -35203
+ Partials 11521 11433 -88
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch. |
|
Dear @Hanarion, This is a nice feature to have. Are you considering extending it to allow a domain or account to be limited to one (or a specific list) of categories? For example, we distinguish between Core (higher-performance hardware) and Essentials (lower-performance hardware), in a tiered fashion (with different costs, of course). With "Offering Category", we could define which groups of offerings a client (domain/account) is allowed to use. What do you think? |
|
@daviftorres it could be interesting yes. |
Sounds great! |
|
@blueorangutan package |
|
@rajujith a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 15873 |
|
@rajujith thanks for the review. I'll check today in order to fix this issue |
Screen.Recording.2025-12-03.at.10.03.17.AM.mov |
…on/cloudstack into service_offering_category_feature
…breaking functionnality
|
@blueorangutan package |
|
@winterhazel a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 18019 |
|
@blueorangutan test |
|
@DaanHoogland a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests |
|
[SF] Trillian Build Failed (tid-16179) |
|
[SF] Trillian test result (tid-16191)
|
|
@Hanarion , please have a look at the co-pilot comments. a lot of them seem to make sense. |
|
This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
I'll re-review my code in the next 48h and continue applying suggestions from copilot and re-testing the entire feature, i'll keep you updated when i'm finished |
| CREATE TABLE IF NOT EXISTS `cloud`.`service_offering_category` ( | ||
| `id` bigint unsigned NOT NULL auto_increment, | ||
| `name` varchar(255) NOT NULL, | ||
| `uuid` varchar(40), | ||
| `sort_key` int NOT NULL DEFAULT 0, | ||
| PRIMARY KEY (`id`), | ||
| CONSTRAINT `uc_service_offering_category__uuid` UNIQUE (`uuid`) | ||
| ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; | ||
|
|
||
|
|
||
| ALTER TABLE `cloud`.`service_offering` ADD COLUMN `category_id` bigint unsigned NOT NULL DEFAULT 1; | ||
| ALTER TABLE `cloud`.`service_offering` ADD CONSTRAINT `fk_service_offering__category_id` FOREIGN KEY (`category_id`) REFERENCES `cloud`.`service_offering_category` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE; | ||
| INSERT INTO `cloud`.`service_offering_category` (id, name, uuid) VALUES (1, 'Default', UUID()); | ||
|
|
| @Override | ||
| @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering category") | ||
| public ServiceOfferingCategory createServiceOfferingCategory(CreateServiceOfferingCategoryCmd cmd) { |
| @Override | ||
| @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_DELETE, eventDescription = "deleting service offering category") | ||
| public boolean deleteServiceOfferingCategory(DeleteServiceOfferingCategoryCmd cmd) { | ||
| Long categoryId = cmd.getId(); | ||
|
|
||
| ServiceOfferingCategoryVO category = _serviceOfferingCategoryDao.findById(categoryId); | ||
| if (category == null) { | ||
| throw new InvalidParameterValueException("Unable to find service offering category with id " + categoryId); | ||
| } | ||
|
|
||
| // Check if any service offering is using this category | ||
| // For now we'll just check if it's the default category (id=1) | ||
| if (categoryId == 1L) { | ||
| throw new InvalidParameterValueException("Cannot delete the default service offering category"); | ||
| } | ||
|
|
||
| boolean result = _serviceOfferingCategoryDao.remove(categoryId); | ||
| if (result) { | ||
| CallContext.current().setEventDetails("Service offering category id=" + categoryId); | ||
| } | ||
| return result; | ||
| } |
| fetchData () { | ||
| this.fetchDomainData() | ||
| this.fetchZoneData() | ||
| this.fetchGPUCards() | ||
| this.fetchCategories() | ||
| if (isAdmin()) { | ||
| this.fetchStorageTagData() |
| fetchCategories () { | ||
| this.categoryLoading = true | ||
| getAPI('listServiceOfferingCategories', { | ||
| }).then(json => { | ||
| this.categories = json.listserviceofferingcategoriesresponse.serviceofferingcategory || [] | ||
| }).finally(() => { | ||
| this.categoryLoading = false | ||
| }) | ||
| }, |
| vgpuProfiles: [], | ||
| vgpuProfileLoading: false, | ||
| externalDetailsEnabled: false | ||
| externalDetailsEnabled: false, | ||
| categories: [], | ||
| categoryLoading: false |
| fetchData () { | ||
| this.fetchDomainData() | ||
| this.fetchZoneData() | ||
| this.fetchGPUCards() | ||
| this.fetchCategories() | ||
| if (isAdmin()) { | ||
| this.fetchStorageTagData() |
| fetchCategories () { | ||
| this.categoryLoading = true | ||
| getAPI('listServiceOfferingCategories', { | ||
| }).then(json => { | ||
| this.categories = json.listserviceofferingcategoriesresponse.serviceofferingcategory || [] | ||
| }).finally(() => { | ||
| this.categoryLoading = false | ||
| }) | ||
| }, |
|
@blueorangutan package |
|
@DaanHoogland a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 18308 |
|
Fixes the outstanding reviewer/Copilot comments that were not covered by
the earlier "apply copilot suggestions" commit:
- Remove trailing space in ListServiceOfferingsCmd (checkstyle build failure)
- Add dedicated EVENT_SERVICE_OFFERING_CATEGORY_{CREATE,EDIT,DELETE} event
types mapped to ServiceOfferingCategory, and use them for category CRUD
instead of the ServiceOffering event types (audit-trail misclassification)
- Eliminate the N+1 category lookup in ServiceOfferingJoinDaoImpl by joining
service_offering_category into service_offering_view and reading the
category uuid/name directly from the join VO
- Add missing ServiceOfferingDao.listByCategoryId used by the delete
usage-check (the branch did not compile without it)
- Add UNIQUE constraint on service_offering_category.name
- UI: drop dead params.categoryid=null branch in DeployVM; fix double space
in ListView category condition; fix radio-option__icon CSS typo; remove
unused categories/categoryLoading state and fetchCategories() from
AddComputeOffering and CloneComputeOffering
…upport - Add missing label.categoryid translation so the compute offering edit form shows "Category" instead of the raw i18n key. - Fix instance wizard not resetting the offering list when switching the category back to "All": the stale categoryid persisted in the merged search options and was re-sent. Now explicitly cleared. - Wire up the service offering category selector in the VNF appliance deploy wizard, mirroring the standard instance wizard.
| fetchServiceOfferingCategories () { | ||
| this.loading.serviceOfferingCategories = true | ||
| return new Promise((resolve, reject) => { | ||
| getAPI('listServiceOfferingCategories').then(json => { | ||
| const categories = json.listserviceofferingcategoriesresponse.serviceofferingcategory || [] |
| <template #radio-option="{ item }"> | ||
| {{ item.name }} | ||
| </template> |
| @Override | ||
| @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CATEGORY_CREATE, eventDescription = "creating service offering category") | ||
| public ServiceOfferingCategory createServiceOfferingCategory(CreateServiceOfferingCategoryCmd cmd) { | ||
| String name = cmd.getName(); | ||
| Integer sortKey = cmd.getSortKey(); | ||
|
|
Description
When using Cloudstack, when creating instance with a lot of offerings, it could be hard to differentiate between all of the offerings. For that, categories could be useful.
This pull request introduces the concept of "Service Offering Categories" to the API, allowing service offerings to be grouped, managed, and queried by category. It adds a new interface for categories, updates the API to support creating, updating, deleting, and listing categories, and enables associating service offerings with a category. The changes also extend existing API commands and responses to work with categories.
Service Offering Category API Support:
CreateServiceOfferingCategoryCmd,DeleteServiceOfferingCategoryCmd,UpdateServiceOfferingCategoryCmd, andListServiceOfferingCategoriesCmd, enabling full CRUD operations and listing for categories.ConfigurationServiceinterface to include methods for creating, deleting, and updating service offering categories.ServiceOfferingCategorythat defines category properties and behaviors.API Parameter and Response Enhancements:
SERVICE_OFFERING_CATEGORY_ID,SERVICE_OFFERING_CATEGORY_NAME) inApiConstants, and updated related commands (CreateServiceOfferingCmd,UpdateServiceOfferingCmd,ListServiceOfferingsCmd) to accept or filter by category.ResponseGeneratorto support generating responses for service offering categories.Service Offering Model Update:
getCategoryId()method to theServiceOfferinginterface, allowing offerings to be associated with a specific category.Types of changes
Feature/Enhancement Scale or Bug Severity
Feature/Enhancement Scale
Bug Severity
Screenshots (if appropriate):
How Has This Been Tested?
On my dev environment, through the API and cloudmonkey
How did you try to break this feature and the system with this change?
Those changes should not break any features as it is only adding a new column to serviceoffering and adding a new table, it is only a way to filter and categorize.
--
I'm sorry if the formatting isn't perfect, i couldn't get the pre-commit to work, and it is my first code PR.
Warning, i put the SQL where i thought it made sense, but i think you will want to move it where it really should be.