Skip to content

Service offering resource update#252

Open
jeanvetorello wants to merge 17 commits into
apache:mainfrom
jeanvetorello:service-offering-resource-update
Open

Service offering resource update#252
jeanvetorello wants to merge 17 commits into
apache:mainfrom
jeanvetorello:service-offering-resource-update

Conversation

@jeanvetorello

Copy link
Copy Markdown
Contributor

Overview

This PR completely updates the cloudstack_service_offering resource to support CloudStack API version 4.21, achieving 100% SDK coverage with all 54 parameters from CreateServiceOfferingParams fully implemented.

Motivation

I needed to update the Service Offering API to the latest CloudStack version (4.21) to support modern features like GPU configuration, advanced IOPS settings, and dynamic scaling. The existing implementation was missing critical parameters and had several drift issues.

What's New

1. Complete API v4.21 Coverage (54/54 Parameters)

All parameters from CloudStack Go SDK v2 CreateServiceOfferingParams are now implemented:

CPU & Memory:

  • cpu_number, cpu_speed, memory
  • customized, min_cpu_number, max_cpu_number
  • min_memory, max_memory

GPU Support (NEW):

  • gpu_card - GPU card name (maps to gpucardid)
  • gpu_type - vGPU profile UUID (maps to vgpuprofileid)
  • gpu_count - Number of GPUs

Storage:

  • storage_type, storage_tags, host_tags
  • root_disk_size, encrypt_root
  • provisioning_type, cache_mode

IOPS & Bandwidth (12 parameters):

  • bytes_read_rate, bytes_write_rate
  • bytes_read_rate_max, bytes_write_rate_max
  • bytes_read_rate_max_length, bytes_write_rate_max_length
  • iops_read_rate, iops_write_rate
  • iops_read_rate_max, iops_write_rate_max
  • iops_read_rate_max_length, iops_write_rate_max_length

Performance:

  • disk_iops_min, disk_iops_max
  • hypervisor_snapshot_reserve
  • offer_ha, limit_cpu_use
  • dynamic_scaling_enabled
  • customized_iops

System & Domain:

  • is_system, system_vm_type
  • zone_id, domain_id
  • is_volatile, deployment_planner

Advanced:

  • service_offering_details (map for custom settings)

2. Bug Fixes

Fixed service_offering_details Drift

  • Problem: CloudStack adds system keys (External:key, External:value, purge.db.entities) causing state drift
  • Solution: Implemented filtering in Read function (lines 847-863) to only track user-configured keys

Fixed customized Parameter Logic

  • Problem: Incorrect handling of Fixed vs Custom offerings
  • Solution: Smart conditional logic based on CPU/memory presence:
    • If cpu_number + memory provided → customized = false (Fixed Offering)
    • If customized = true + min/max → Custom Constrained
    • If customized = true + no limits → Custom Unconstrained

Identified ForceNew Parameters (47 of 54)

  • Problem: Most CloudStack Service Offering parameters are immutable after creation
  • Solution: Added ForceNew: true to 47 parameters based on CloudStack API limitations
  • Updateable: Only display_text, host_tags, and storage_tags can be updated in-place

3. Comprehensive Testing

Added 4 new tests covering all CloudStack UI offering types:

  • TestAccServiceOfferingTypeFixed - Fixed CPU/memory
  • TestAccServiceOfferingTypeCustomConstrained - Customizable with limits
  • TestAccServiceOfferingTypeCustomUnconstrained - Fully customizable
  • TestAccServiceOfferingAllUITypes - All types together

Total: 17 tests (13 existing + 4 new)

4. Complete Documentation

Created comprehensive documentation in website/docs/r/service_offering.html.markdown:

  • Detailed explanation of all 3 offering types with decision tree
  • GPU configuration examples (A6000, A100, H100, RTX 4090, Multi-GPU)
  • IOPS/bandwidth configuration examples
  • High-performance offerings
  • ForceNew behavior documentation
  • CloudStack API behavior notes

jean and others added 14 commits October 15, 2025 10:06
- Add service_offering_details attribute to cloudstack_service_offering resource
- Support for GPU configuration with pciDevice and vgpuType parameters
- Include comprehensive test coverage and documentation
- Add practical examples for GPU service offerings
- Addresses issue apache#246
- Update service offering documentation with GPU examples
- Add service_offering_details parameter documentation
- Update CHANGELOG with new feature entry
- Include practical examples for GPU configuration
- Fix code formatting to comply with Go standards
- Align map fields and remove trailing whitespace
- Required for CI/CD pipeline to pass
@CodeBleu

CodeBleu commented Oct 17, 2025

Copy link
Copy Markdown
Contributor

@jeanvetorello There was already work done for service offerings around fixed, constrained and unconstrained.

Please see the following for discussions around this.
#138
#113
#77

@poddm can you review this and give your input on this as your commit a while back took a different aproach and I know we had this discussion about this before. (see links above)

@DaanHoogland Also, what is your opinion on this as we need to pick a path and stick to it. We shouldn't have multiple resource files out there for the same thing

We need to make sure we are using the most recent framework/sdk as well.

This is what was decided back then on method to split up the resources

image image

@CodeBleu CodeBleu requested a review from DaanHoogland October 17, 2025 23:33
Comment on lines -1 to -18
//
// 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.
//

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license needs to be there

Comment thread .gitignore
!command/test-fixtures/**/.terraform/
.terraform.lock.hcl
provider.tf
examples/ No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
examples/
examples/

@DaanHoogland

Copy link
Copy Markdown
Contributor

@DaanHoogland Also, what is your opinion on this as we need to pick a path and stick to it. We shouldn't have multiple resource files out there for the same thing

@CodeBleu , I completely agree with the blanket statement, but am sure I am missing some context. on first sight I thought you were talking about production code vs test code, but I see no issue there. Can you explain?

@CodeBleu

CodeBleu commented Oct 21, 2025

Copy link
Copy Markdown
Contributor

@DaanHoogland Also, what is your opinion on this as we need to pick a path and stick to it. We shouldn't have multiple resource files out there for the same thing

@CodeBleu , I completely agree with the blanket statement, but am sure I am missing some context. on first sight I thought you were talking about production code vs test code, but I see no issue there. Can you explain?

@DaanHoogland There are both resource_cloudstack_service_offering.go and service_offering_*.go files in the code for service offerings. They both take a different approach and this PR is updating what I thought was the old way?
See
#138
#113
#77
for more context.

@poddm

poddm commented Oct 21, 2025

Copy link
Copy Markdown
Contributor

@CodeBleu, I think you're right. We should deprecated this resource.

I can open a PR if thats whats decided.

@DaanHoogland

Copy link
Copy Markdown
Contributor

There are both resource_cloudstack_service_offering.go and service_offering_*.go files in the code for service offerings.

makes sense, @CodeBleu .

I can open a PR if thats whats decided.

thanks @poddm .

it makes no sense to maintain two SDKs for the same API. Will we then defer merging this? or is this a parallel effort?

@jeanvetorello

Copy link
Copy Markdown
Contributor Author

I need to remove old duplicate service offering files to pass all tests. Should I proceed?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the Service Offering support by consolidating the previously split “fixed / constrained / unconstrained” resources into an updated, unified cloudstack_service_offering resource intended to align with CloudStack API v4.21, alongside expanded docs and acceptance tests.

Changes:

  • Expanded cloudstack_service_offering schema/Create/Read logic to cover many more CloudStack service offering parameters (GPU, IOPS/bandwidth, lease, etc.).
  • Removed the legacy split service offering resources/util/schema/models and their dedicated docs/tests.
  • Reworked documentation into a single service_offering doc page and significantly expanded acceptance testing.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
website/docs/r/service_offering.html.markdown Replaces/expands service offering documentation into a single, detailed page.
website/docs/r/service_offering_unconstrained.html.markdown Deletes legacy unconstrained resource documentation.
website/docs/r/service_offering_fixed.html.markdown Deletes legacy fixed resource documentation.
website/docs/r/service_offering_constrained.html.markdown Deletes legacy constrained resource documentation.
cloudstack/resource_cloudstack_service_offering.go Major expansion of the unified service offering resource schema and CRUD logic.
cloudstack/resource_cloudstack_service_offering_test.go Adds/updates extensive acceptance test coverage for the unified resource.
cloudstack/data_source_cloudstack_service_offering.go Expands the service offering data source with many additional computed attributes.
cloudstack/data_source_cloudstack_service_offering_test.go Updates data source acceptance test to check additional attribute parity.
cloudstack/provider_v6.go Removes registration of the deleted legacy service offering resources.
cloudstack/service_offering_util.go Deletes legacy shared helper logic for split resources.
cloudstack/service_offering_unconstrained_resource.go Deletes legacy unconstrained resource implementation.
cloudstack/service_offering_unconstrained_resource_test.go Deletes legacy unconstrained acceptance tests.
cloudstack/service_offering_schema.go Deletes legacy split-resource schema definitions.
cloudstack/service_offering_models.go Deletes legacy split-resource models.
cloudstack/service_offering_fixed_resource.go Deletes legacy fixed resource implementation.
cloudstack/service_offering_fixed_resource_test.go Deletes legacy fixed acceptance tests.
cloudstack/service_offering_constrained_resource.go Deletes legacy constrained resource implementation.
cloudstack/service_offering_constrained_resource_test.go Deletes legacy constrained acceptance tests.
.gitignore Adds examples/ to ignored paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 580 to 586
if details, ok := d.GetOk("service_offering_details"); ok {
serviceOfferingDetails := make(map[string]string)
for k, v := range details.(map[string]interface{}) {
serviceOfferingDetails[k] = v.(string)
}
p.SetServiceofferingdetails(serviceOfferingDetails)
}
Comment on lines +700 to +706
if v, ok := d.GetOk("service_offering_details"); ok {
details := make(map[string]string)
for key, value := range v.(map[string]interface{}) {
details[key] = value.(string)
}
p.SetServiceofferingdetails(details)
}
Comment on lines +588 to +594
if v, ok := d.GetOk("zone_id"); ok {
zones := make([]string, 0)
for _, z := range v.([]interface{}) {
zones = append(zones, z.(string))
}
p.SetZoneid(zones)
}
Comment on lines +68 to +74
"storage_type": {
Description: "The storage type of the service offering",
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: "shared",
},
Comment on lines +349 to +354
"hypervisor_snapshot_reserve": {
Description: "Hypervisor snapshot reserve space as a percent of a volume (for managed storage using Xen or VMware)",
Type: schema.TypeInt,
Optional: true,
Computed: true,
},

* `storage_type` - (Optional) The storage type of the service offering. Valid values are `local` and `shared`. Changing this forces a new resource to be created.

* `storage_tags` - (Optional) Comma-separated list of tags for matching storage pools. Changing this forces a new resource to be created.
Comment on lines +245 to +249
* `bytes_read_rate` - (Optional) Bytes read rate in bytes per second. Changing this forces a new resource to be created.

* `min_memory` - (Optional) Minimum memory (in MB) allowed for customized offerings.
Changing this forces a new resource to be created.
* `bytes_read_rate_max` - (Optional) Burst bytes read rate in bytes per second. Changing this forces a new resource to be created.

* `max_memory` - (Optional) Maximum memory (in MB) allowed for customized offerings.
Changing this forces a new resource to be created.
* `bytes_read_rate_max_length` - (Optional) Length of the burst bytes read rate in seconds. Changing this forces a new resource to be created.
Comment on lines +257 to +267
* `iops_read_rate` - (Optional) IO requests read rate in IOPS. Changing this forces a new resource to be created.

* `iops_read_rate_max` - (Optional) Burst IO requests read rate in IOPS. Changing this forces a new resource to be created.

* `iops_read_rate_max_length` - (Optional) Length of the burst IO requests read rate in seconds. Changing this forces a new resource to be created.

* `iops_write_rate` - (Optional) IO requests write rate in IOPS. Changing this forces a new resource to be created.

* `iops_write_rate_max` - (Optional) Burst IO requests write rate in IOPS. Changing this forces a new resource to be created.

* `iops_write_rate_max_length` - (Optional) Length of the burst IO requests write rate in seconds. Changing this forces a new resource to be created.
Comment on lines +271 to +274
* `disk_iops_min` - (Optional) Minimum IOPS for the disk. Changing this forces a new resource to be created.

* `disk_iops_max` - (Optional) Maximum IOPS for the disk. Changing this forces a new resource to be created.

Comment on lines 323 to 325
* `id` - The ID of the service offering.
* `created` - The date when the service offering was created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants