This is an automated email from the ASF dual-hosted git repository.

kiranchavala pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/cloudstack-terraform-provider.git


The following commit(s) were added to refs/heads/main by this push:
     new 63f866b  service offering.  sdk framework rewrite (#138)
63f866b is described below

commit 63f866bc0f694d8239f69336bd8fb264dd9d683b
Author: poddm <8801231+po...@users.noreply.github.com>
AuthorDate: Mon Sep 15 23:45:23 2025 -0700

    service offering.  sdk framework rewrite (#138)
    
    * sdk framework rewrite
    
    * adding description to schema fields
    
    * fixing domainids value error
    
    * Adding better cpu_speed description for vmware, xen and kvm
    
    * cleaned up comments
    
    * Adding service offering details
    
    * Adding license header to files.  Fixed an issue with setting zone ids to 
null, moved storage_tags field to nested block disk_offering
    
    * add missing set blocks
    
    * Update cloudstack/service_offering_schema.go
    
    * add documentation
    
    ---------
    
    Co-authored-by: CodeBleu <400979+codeb...@users.noreply.github.com>
---
 cloudstack/provider_v6.go                          |   6 +-
 .../service_offering_constrained_resource.go       | 313 ++++++++++++++++++++
 .../service_offering_constrained_resource_test.go  | 319 +++++++++++++++++++++
 cloudstack/service_offering_fixed_resource.go      | 251 ++++++++++++++++
 cloudstack/service_offering_fixed_resource_test.go | 239 +++++++++++++++
 cloudstack/service_offering_models.go              |  86 ++++++
 cloudstack/service_offering_schema.go              | 248 ++++++++++++++++
 .../service_offering_unconstrained_resource.go     | 204 +++++++++++++
 ...service_offering_unconstrained_resource_test.go | 207 +++++++++++++
 cloudstack/service_offering_util.go                | 277 ++++++++++++++++++
 go.mod                                             |  19 +-
 go.sum                                             |  33 +--
 .../r/service_offering_constrained.html.markdown   |  96 +++++++
 .../docs/r/service_offering_fixed.html.markdown    | 101 +++++++
 .../r/service_offering_unconstrained.html.markdown |  95 ++++++
 15 files changed, 2469 insertions(+), 25 deletions(-)

diff --git a/cloudstack/provider_v6.go b/cloudstack/provider_v6.go
index 23637f5..82c06c0 100644
--- a/cloudstack/provider_v6.go
+++ b/cloudstack/provider_v6.go
@@ -164,7 +164,11 @@ func (p *CloudstackProvider) ConfigValidators(ctx 
context.Context) []provider.Co
 }
 
 func (p *CloudstackProvider) Resources(ctx context.Context) []func() 
resource.Resource {
-       return []func() resource.Resource{}
+       return []func() resource.Resource{
+               NewserviceOfferingUnconstrainedResource,
+               NewserviceOfferingConstrainedResource,
+               NewserviceOfferingFixedResource,
+       }
 }
 
 func (p *CloudstackProvider) DataSources(ctx context.Context) []func() 
datasource.DataSource {
diff --git a/cloudstack/service_offering_constrained_resource.go 
b/cloudstack/service_offering_constrained_resource.go
new file mode 100644
index 0000000..92c8077
--- /dev/null
+++ b/cloudstack/service_offering_constrained_resource.go
@@ -0,0 +1,313 @@
+//
+// 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 cloudstack
+
+import (
+       "context"
+       "fmt"
+       "strconv"
+
+       "github.com/apache/cloudstack-go/v2/cloudstack"
+       "github.com/hashicorp/terraform-plugin-framework/resource"
+       "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+       "github.com/hashicorp/terraform-plugin-framework/types"
+       "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+)
+
+var (
+       _ resource.Resource              = &serviceOfferingConstrainedResource{}
+       _ resource.ResourceWithConfigure = &serviceOfferingConstrainedResource{}
+)
+
+func NewserviceOfferingConstrainedResource() resource.Resource {
+       return &serviceOfferingConstrainedResource{}
+}
+
+type serviceOfferingConstrainedResource struct {
+       client *cloudstack.CloudStackClient
+}
+
+func (r *serviceOfferingConstrainedResource) Schema(_ context.Context, _ 
resource.SchemaRequest, resp *resource.SchemaResponse) {
+       resp.Schema = schema.Schema{
+               Attributes: 
serviceOfferingMergeCommonSchema(map[string]schema.Attribute{
+                       "cpu_speed": schema.Int32Attribute{
+                               Description: "VMware and Xen based hypervisors 
this is the CPU speed of the service offering in MHz. For the KVM hypervisor 
the values of the parameters cpuSpeed and cpuNumber will be used to calculate 
the `shares` value. This value is used by the KVM hypervisor to calculate how 
much time the VM will have access to the host's CPU. The `shares` value does 
not have a unit, and its purpose is being a weight value for the host to 
compare between its guest VMs. For more information, see h [...]
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+                       "max_cpu_number": schema.Int32Attribute{
+                               Description: "The maximum number of CPUs to be 
set with Custom Compute Offering",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+                       "max_memory": schema.Int32Attribute{
+                               Description: "The maximum memory size of the 
custom service offering in MB",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+                       "min_cpu_number": schema.Int32Attribute{
+                               Description: "The minimum number of CPUs to be 
set with Custom Compute Offering",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+                       "min_memory": schema.Int32Attribute{
+                               Description: "The minimum memory size of the 
custom service offering in MB",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+               }),
+       }
+}
+
+func (r *serviceOfferingConstrainedResource) Create(ctx context.Context, req 
resource.CreateRequest, resp *resource.CreateResponse) {
+       var plan serviceOfferingConstrainedResourceModel
+       var planDiskQosHypervisor ServiceOfferingDiskQosHypervisor
+       var planDiskOffering ServiceOfferingDiskOffering
+       var planDiskQosStorage ServiceOfferingDiskQosStorage
+
+       resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+       if !plan.ServiceOfferingDiskQosHypervisor.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskQosHypervisor.As(ctx, 
&planDiskQosHypervisor, basetypes.ObjectAsOptions{})...)
+       }
+       if !plan.ServiceOfferingDiskOffering.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskOffering.As(ctx, 
&planDiskOffering, basetypes.ObjectAsOptions{})...)
+       }
+       if !plan.ServiceOfferingDiskQosStorage.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskQosStorage.As(ctx, 
&planDiskQosStorage, basetypes.ObjectAsOptions{})...)
+       }
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       // common params
+       params := 
r.client.ServiceOffering.NewCreateServiceOfferingParams(plan.DisplayText.ValueString(),
 plan.Name.ValueString())
+       plan.commonCreateParams(ctx, params)
+       planDiskQosHypervisor.commonCreateParams(ctx, params)
+       planDiskOffering.commonCreateParams(ctx, params)
+       planDiskQosStorage.commonCreateParams(ctx, params)
+
+       // resource specific params
+       if !plan.CpuSpeed.IsNull() {
+               params.SetCpuspeed(int(plan.CpuSpeed.ValueInt32()))
+       }
+       if !plan.MaxCpuNumber.IsNull() {
+               params.SetMaxcpunumber(int(plan.MaxCpuNumber.ValueInt32()))
+       }
+       if !plan.MaxMemory.IsNull() {
+               params.SetMaxmemory(int(plan.MaxMemory.ValueInt32()))
+       }
+       if !plan.MinCpuNumber.IsNull() {
+               params.SetMincpunumber(int(plan.MinCpuNumber.ValueInt32()))
+       }
+       if !plan.MinMemory.IsNull() {
+               params.SetMinmemory(int(plan.MinMemory.ValueInt32()))
+       }
+
+       // create offering
+       cs, err := r.client.ServiceOffering.CreateServiceOffering(params)
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error creating service offering",
+                       "Could not create constrained offering, unexpected 
error: "+err.Error(),
+               )
+               return
+       }
+
+       //
+       plan.Id = types.StringValue(cs.Id)
+
+       //
+       resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
+}
+
+func (r *serviceOfferingConstrainedResource) Read(ctx context.Context, req 
resource.ReadRequest, resp *resource.ReadResponse) {
+       var state serviceOfferingConstrainedResourceModel
+       var stateDiskQosHypervisor ServiceOfferingDiskQosHypervisor
+       var stateDiskOffering ServiceOfferingDiskOffering
+       var stateDiskQosStorage ServiceOfferingDiskQosStorage
+
+       resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+       if !state.ServiceOfferingDiskQosHypervisor.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskQosHypervisor.As(ctx, 
&stateDiskQosHypervisor, basetypes.ObjectAsOptions{})...)
+       }
+       if !state.ServiceOfferingDiskOffering.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskOffering.As(ctx, 
&stateDiskOffering, basetypes.ObjectAsOptions{})...)
+       }
+       if !state.ServiceOfferingDiskQosStorage.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskQosStorage.As(ctx, 
&stateDiskQosStorage, basetypes.ObjectAsOptions{})...)
+       }
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       cs, _, err := 
r.client.ServiceOffering.GetServiceOfferingByID(state.Id.ValueString())
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error reading service offering",
+                       "Could not read constrained service offering, 
unexpected error: "+err.Error(),
+               )
+               return
+       }
+
+       // resource specific
+       if cs.Cpuspeed > 0 {
+               state.CpuSpeed = types.Int32Value(int32(cs.Cpuspeed))
+       }
+       if v, found := cs.Serviceofferingdetails["maxcpunumber"]; found {
+               i, err := strconv.Atoi(v)
+               if err != nil {
+                       resp.Diagnostics.AddError(
+                               "Error reading service offering",
+                               "Could not read constrained service offering 
max cpu, unexpected error: "+err.Error(),
+                       )
+                       return
+               }
+               state.MaxCpuNumber = types.Int32Value(int32(i))
+       }
+       if v, found := cs.Serviceofferingdetails["mincpunumber"]; found {
+               i, err := strconv.Atoi(v)
+               if err != nil {
+                       resp.Diagnostics.AddError(
+                               "Error reading service offering",
+                               "Could not read constrained service offering 
min cpu number, unexpected error: "+err.Error(),
+                       )
+                       return
+               }
+               state.MinCpuNumber = types.Int32Value(int32(i))
+       }
+       if v, found := cs.Serviceofferingdetails["maxmemory"]; found {
+               i, err := strconv.Atoi(v)
+               if err != nil {
+                       resp.Diagnostics.AddError(
+                               "Error reading service offering",
+                               "Could not read constrained service offering 
max memory, unexpected error: "+err.Error(),
+                       )
+                       return
+               }
+               state.MaxMemory = types.Int32Value(int32(i))
+       }
+       if v, found := cs.Serviceofferingdetails["minmemory"]; found {
+               i, err := strconv.Atoi(v)
+               if err != nil {
+                       resp.Diagnostics.AddError(
+                               "Error reading service offering",
+                               "Could not read constrained service offering 
min memory, unexpected error: "+err.Error(),
+                       )
+                       return
+               }
+               state.MinMemory = types.Int32Value(int32(i))
+       }
+
+       state.commonRead(ctx, cs)
+       stateDiskQosHypervisor.commonRead(ctx, cs)
+       stateDiskOffering.commonRead(ctx, cs)
+       stateDiskQosStorage.commonRead(ctx, cs)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+
+}
+
+// Update updates the resource and sets the updated Terraform state on success.
+func (r *serviceOfferingConstrainedResource) Update(ctx context.Context, req 
resource.UpdateRequest, resp *resource.UpdateResponse) {
+       var state serviceOfferingConstrainedResourceModel
+
+       resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       params := 
r.client.ServiceOffering.NewUpdateServiceOfferingParams(state.Id.ValueString())
+       state.commonUpdateParams(ctx, params)
+
+       cs, err := r.client.ServiceOffering.UpdateServiceOffering(params)
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error updating service offering",
+                       "Could not update constrained service offering, 
unexpected error: "+err.Error(),
+               )
+               return
+       }
+
+       state.commonUpdate(ctx, cs)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+       resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+}
+
+func (r *serviceOfferingConstrainedResource) Delete(ctx context.Context, req 
resource.DeleteRequest, resp *resource.DeleteResponse) {
+       var state serviceOfferingConstrainedResourceModel
+
+       diags := req.State.Get(ctx, &state)
+       resp.Diagnostics.Append(diags...)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       // Delete the service offering
+       _, err := 
r.client.ServiceOffering.DeleteServiceOffering(r.client.ServiceOffering.NewDeleteServiceOfferingParams(state.Id.ValueString()))
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error deleting service offering",
+                       "Could not delete constrained offering, unexpected 
error: "+err.Error(),
+               )
+               return
+       }
+}
+
+func (r *serviceOfferingConstrainedResource) Configure(_ context.Context, req 
resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+       // Add a nil check when handling ProviderData because Terraform
+       // sets that data after it calls the ConfigureProvider RPC.
+       if req.ProviderData == nil {
+               return
+       }
+
+       client, ok := req.ProviderData.(*cloudstack.CloudStackClient)
+
+       if !ok {
+               resp.Diagnostics.AddError(
+                       "Unexpected Data Source Configure Type",
+                       fmt.Sprintf("Expected *cloudstack.CloudStackClient, 
got: %T. Please report this issue to the provider developers.", 
req.ProviderData),
+               )
+               return
+       }
+
+       r.client = client
+}
+
+// Metadata returns the resource type name.
+func (r *serviceOfferingConstrainedResource) Metadata(_ context.Context, req 
resource.MetadataRequest, resp *resource.MetadataResponse) {
+       resp.TypeName = req.ProviderTypeName + "_service_offering_constrained"
+}
diff --git a/cloudstack/service_offering_constrained_resource_test.go 
b/cloudstack/service_offering_constrained_resource_test.go
new file mode 100644
index 0000000..5368db7
--- /dev/null
+++ b/cloudstack/service_offering_constrained_resource_test.go
@@ -0,0 +1,319 @@
+//
+// 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 cloudstack
+
+import (
+       "testing"
+
+       "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccServiceOfferingConstrained(t *testing.T) {
+       resource.Test(t, resource.TestCase{
+               PreCheck:                 func() { testAccPreCheck(t) },
+               ProtoV6ProviderFactories: testAccMuxProvider,
+               Steps: []resource.TestStep{
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained1,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.constrained1",
 "name", "constrained1"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained1ZoneAll,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.constrained1",
 "name", "constrained1"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained2,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.constrained2",
 "name", "constrained2"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained2_update,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.constrained2",
 "name", "constrained2update"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained_disk,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.constrained1",
 "name", "constrained1"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained_disk_hypervisor,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.disk_hypervisor",
 "name", "disk_hypervisor"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingCustomConstrained_disk_storage,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_constrained.disk_storage",
 "name", "disk_storage"),
+                               ),
+                       },
+               },
+       })
+}
+
+const testAccServiceOfferingCustomConstrained1 = `
+resource "cloudstack_zone" "test" {
+       name          = "acctest"
+       dns1          = "8.8.8.8"
+       internal_dns1 = "8.8.4.4"
+       network_type  = "Advanced"
+}
+
+resource "cloudstack_service_offering_constrained" "constrained1" {
+       display_text = "constrained1"
+       name         = "constrained1"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+       
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+       
+       // other
+       host_tags    = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+       
+       // Feature flags
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+       zone_ids = [cloudstack_zone.test.id]
+
+}
+`
+
+const testAccServiceOfferingCustomConstrained1ZoneAll = `
+resource "cloudstack_service_offering_constrained" "constrained1" {
+       display_text = "constrained11"
+       name         = "constrained1"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+
+       // other
+       host_tags    = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       // Feature flags
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+       zone_ids = []
+}
+`
+
+const testAccServiceOfferingCustomConstrained2 = `
+resource "cloudstack_service_offering_constrained" "constrained2" {
+       display_text = "constrained2"
+       name         = "constrained2"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+       
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+       
+       // other
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+       
+       // Feature flags
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+}
+`
+const testAccServiceOfferingCustomConstrained2_update = `
+resource "cloudstack_service_offering_constrained" "constrained2" {
+       display_text = "constrained2update"
+       name         = "constrained2update"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+       
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+       
+       // other
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+       
+       // Feature flags
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+}
+`
+
+const testAccServiceOfferingCustomConstrained_disk = `
+resource "cloudstack_service_offering_constrained" "constrained1" {
+       display_text = "constrained1"
+       name         = "constrained1"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+
+       // other
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       // Feature flags
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+       disk_offering = {
+               storage_type = "local"
+               sdfjklsdf = "sdfjks"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "FOO"
+               disk_offering_strictness = false
+       }
+}
+`
+
+const testAccServiceOfferingCustomConstrained_disk_hypervisor = `
+resource "cloudstack_service_offering_constrained" "disk_hypervisor" {
+       display_text = "disk_hypervisor"
+       name         = "disk_hypervisor"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+
+       // other
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       // Feature flags
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+       disk_offering = {
+               storage_type = "local"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "FOO"
+               disk_offering_strictness = false
+       }
+       disk_hypervisor = {
+               bytes_read_rate             = 1024
+               bytes_read_rate_max         = 1024
+               bytes_read_rate_max_length  = 1024
+               bytes_write_rate            = 1024
+               bytes_write_rate_max        = 1024
+               bytes_write_rate_max_length = 1024
+       }
+}
+`
+
+const testAccServiceOfferingCustomConstrained_disk_storage = `
+resource "cloudstack_service_offering_constrained" "disk_storage" {
+       display_text = "disk_storage"
+       name         = "disk_storage"
+
+       // compute
+       cpu_speed  = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+
+       // memory
+       max_memory     = 4096
+       min_memory     = 1024
+
+       // other
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       // Feature flags
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+       disk_offering = {
+               storage_type = "local"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "FOO"
+               disk_offering_strictness = false
+       }
+       disk_hypervisor = {
+               bytes_read_rate             = 1024
+               bytes_read_rate_max         = 1024
+               bytes_read_rate_max_length  = 1024
+               bytes_write_rate            = 1024
+               bytes_write_rate_max        = 1024
+               bytes_write_rate_max_length = 1024
+       }
+}
+`
diff --git a/cloudstack/service_offering_fixed_resource.go 
b/cloudstack/service_offering_fixed_resource.go
new file mode 100644
index 0000000..6b500fd
--- /dev/null
+++ b/cloudstack/service_offering_fixed_resource.go
@@ -0,0 +1,251 @@
+//
+// 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 cloudstack
+
+import (
+       "context"
+       "fmt"
+
+       "github.com/apache/cloudstack-go/v2/cloudstack"
+       "github.com/hashicorp/terraform-plugin-framework/resource"
+       "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+       "github.com/hashicorp/terraform-plugin-framework/types"
+       "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+)
+
+var (
+       _ resource.Resource              = &serviceOfferingFixedResource{}
+       _ resource.ResourceWithConfigure = &serviceOfferingFixedResource{}
+)
+
+func NewserviceOfferingFixedResource() resource.Resource {
+       return &serviceOfferingFixedResource{}
+}
+
+type serviceOfferingFixedResource struct {
+       client *cloudstack.CloudStackClient
+}
+
+func (r *serviceOfferingFixedResource) Schema(_ context.Context, _ 
resource.SchemaRequest, resp *resource.SchemaResponse) {
+       resp.Schema = schema.Schema{
+               Attributes: 
serviceOfferingMergeCommonSchema(map[string]schema.Attribute{
+                       "cpu_number": schema.Int32Attribute{
+                               Description: "Number of CPU cores",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+                       "cpu_speed": schema.Int32Attribute{
+                               Description: "the CPU speed of the service 
offering in MHz.  This does not apply to KVM.",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+                       "memory": schema.Int32Attribute{
+                               Description: "the total memory of the service 
offering in MB",
+                               Required:    true,
+                               PlanModifiers: []planmodifier.Int32{
+                                       int32planmodifier.RequiresReplace(),
+                               },
+                       },
+               }),
+       }
+}
+
+func (r *serviceOfferingFixedResource) Create(ctx context.Context, req 
resource.CreateRequest, resp *resource.CreateResponse) {
+       var plan serviceOfferingFixedResourceModel
+       var planDiskQosHypervisor ServiceOfferingDiskQosHypervisor
+       var planDiskOffering ServiceOfferingDiskOffering
+       var planDiskQosStorage ServiceOfferingDiskQosStorage
+
+       resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+       if !plan.ServiceOfferingDiskQosHypervisor.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskQosHypervisor.As(ctx, 
&planDiskQosHypervisor, basetypes.ObjectAsOptions{})...)
+       }
+       if !plan.ServiceOfferingDiskOffering.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskOffering.As(ctx, 
&planDiskOffering, basetypes.ObjectAsOptions{})...)
+       }
+       if !plan.ServiceOfferingDiskQosStorage.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskQosStorage.As(ctx, 
&planDiskQosStorage, basetypes.ObjectAsOptions{})...)
+       }
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       // cloudstack params
+       params := 
r.client.ServiceOffering.NewCreateServiceOfferingParams(plan.DisplayText.ValueString(),
 plan.Name.ValueString())
+       plan.commonCreateParams(ctx, params)
+       planDiskQosHypervisor.commonCreateParams(ctx, params)
+       planDiskOffering.commonCreateParams(ctx, params)
+       planDiskQosStorage.commonCreateParams(ctx, params)
+
+       // resource specific params
+       if !plan.CpuNumber.IsNull() {
+               params.SetCpunumber(int(plan.CpuNumber.ValueInt32()))
+       }
+       if !plan.CpuSpeed.IsNull() {
+               params.SetCpuspeed(int(plan.CpuSpeed.ValueInt32()))
+       }
+       if !plan.Memory.IsNull() {
+               params.SetMemory(int(plan.Memory.ValueInt32()))
+       }
+
+       // create offering
+       cs, err := r.client.ServiceOffering.CreateServiceOffering(params)
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error creating service offering",
+                       "Could not create fixed offering, unexpected error: 
"+err.Error(),
+               )
+               return
+       }
+
+       plan.Id = types.StringValue(cs.Id)
+       resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
+}
+
+func (r *serviceOfferingFixedResource) Read(ctx context.Context, req 
resource.ReadRequest, resp *resource.ReadResponse) {
+
+       var state serviceOfferingFixedResourceModel
+       var stateDiskQosHypervisor ServiceOfferingDiskQosHypervisor
+       var stateDiskOffering ServiceOfferingDiskOffering
+       var stateDiskQosStorage ServiceOfferingDiskQosStorage
+
+       resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+       if !state.ServiceOfferingDiskQosHypervisor.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskQosHypervisor.As(ctx, 
&stateDiskQosHypervisor, basetypes.ObjectAsOptions{})...)
+       }
+       if !state.ServiceOfferingDiskOffering.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskOffering.As(ctx, 
&stateDiskOffering, basetypes.ObjectAsOptions{})...)
+       }
+       if !state.ServiceOfferingDiskQosStorage.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskQosStorage.As(ctx, 
&stateDiskQosStorage, basetypes.ObjectAsOptions{})...)
+       }
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       cs, _, err := 
r.client.ServiceOffering.GetServiceOfferingByID(state.Id.ValueString())
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error reading service offering",
+                       "Could not read fixed service offering, unexpected 
error: "+err.Error(),
+               )
+               return
+       }
+
+       // resource specific
+       if cs.Cpunumber > 0 {
+               state.CpuNumber = types.Int32Value(int32(cs.Cpunumber))
+       }
+       if cs.Cpuspeed > 0 {
+               state.CpuSpeed = types.Int32Value(int32(cs.Cpuspeed))
+       }
+       if cs.Memory > 0 {
+               state.Memory = types.Int32Value(int32(cs.Memory))
+       }
+
+       state.commonRead(ctx, cs)
+       stateDiskQosHypervisor.commonRead(ctx, cs)
+       stateDiskOffering.commonRead(ctx, cs)
+       stateDiskQosStorage.commonRead(ctx, cs)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+
+}
+
+// Update updates the resource and sets the updated Terraform state on success.
+func (r *serviceOfferingFixedResource) Update(ctx context.Context, req 
resource.UpdateRequest, resp *resource.UpdateResponse) {
+       var state serviceOfferingFixedResourceModel
+
+       resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       params := 
r.client.ServiceOffering.NewUpdateServiceOfferingParams(state.Id.ValueString())
+       state.commonUpdateParams(ctx, params)
+
+       cs, err := r.client.ServiceOffering.UpdateServiceOffering(params)
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error updating fixed service offering",
+                       "Could not update fixed service offering, unexpected 
error: "+err.Error(),
+               )
+               return
+       }
+
+       state.commonUpdate(ctx, cs)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+       resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+}
+
+// Delete deletes the resource and removes the Terraform state on success.
+func (r *serviceOfferingFixedResource) Delete(ctx context.Context, req 
resource.DeleteRequest, resp *resource.DeleteResponse) {
+       var state serviceOfferingFixedResourceModel
+
+       diags := req.State.Get(ctx, &state)
+       resp.Diagnostics.Append(diags...)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       // Delete the service offering
+       _, err := 
r.client.ServiceOffering.DeleteServiceOffering(r.client.ServiceOffering.NewDeleteServiceOfferingParams(state.Id.ValueString()))
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error deleting service offering",
+                       "Could not delete fixed offering, unexpected error: 
"+err.Error(),
+               )
+               return
+       }
+}
+
+func (r *serviceOfferingFixedResource) Configure(_ context.Context, req 
resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+       // Add a nil check when handling ProviderData because Terraform
+       // sets that data after it calls the ConfigureProvider RPC.
+       if req.ProviderData == nil {
+               return
+       }
+
+       client, ok := req.ProviderData.(*cloudstack.CloudStackClient)
+       if !ok {
+               resp.Diagnostics.AddError(
+                       "Unexpected Data Source Configure Type",
+                       fmt.Sprintf("Expected *cloudstack.CloudStackClient, 
got: %T. Please report this issue to the provider developers.", 
req.ProviderData),
+               )
+               return
+       }
+       r.client = client
+}
+
+// Metadata returns the resource type name.
+func (r *serviceOfferingFixedResource) Metadata(_ context.Context, req 
resource.MetadataRequest, resp *resource.MetadataResponse) {
+       resp.TypeName = req.ProviderTypeName + "_service_offering_fixed"
+}
diff --git a/cloudstack/service_offering_fixed_resource_test.go 
b/cloudstack/service_offering_fixed_resource_test.go
new file mode 100644
index 0000000..438740e
--- /dev/null
+++ b/cloudstack/service_offering_fixed_resource_test.go
@@ -0,0 +1,239 @@
+//
+// 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 cloudstack
+
+import (
+       "testing"
+
+       "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccServiceOfferingFixed(t *testing.T) {
+       resource.Test(t, resource.TestCase{
+               PreCheck:                 func() { testAccPreCheck(t) },
+               ProtoV6ProviderFactories: testAccMuxProvider,
+               Steps: []resource.TestStep{
+                       {
+                               Config: testAccServiceOfferingFixed1,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_fixed.fixed1", 
"name", "fixed1"),
+                               ),
+                       },
+                       {
+                               Config: testAccServiceOfferingFixed2,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_fixed.fixed2", 
"name", "fixed2"),
+                               ),
+                       },
+                       {
+                               Config: testAccServiceOfferingFixed2_update,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_fixed.fixed2", 
"name", "fixed2update"),
+                               ),
+                       },
+                       {
+                               Config: testAccServiceOfferingFixed_disk,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_fixed.disk", 
"name", "disk"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingFixed_disk_hypervisor,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_fixed.disk_hypervisor",
 "name", "disk_hypervisor"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingFixed_disk_storage,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_fixed.disk_storage",
 "name", "disk_storage"),
+                               ),
+                       },
+               },
+       })
+}
+
+const testAccServiceOfferingFixed1 = `
+resource "cloudstack_service_offering_fixed" "fixed1" {
+       display_text = "fixed1"
+       name         = "fixed1"
+
+       // compute
+       cpu_number     = 2
+       cpu_speed      = 2500
+       memory         = 2048
+
+       // other
+       host_tags          = "test0101, test0202"
+       network_rate       = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+}
+`
+
+const testAccServiceOfferingFixed2 = `
+resource "cloudstack_service_offering_fixed" "fixed2" {
+       display_text = "fixed2"
+       name         = "fixed2"
+
+       cpu_number     = 2
+       cpu_speed      = 2500
+       memory         = 2048
+
+       host_tags          = "test0101,test0202"
+       network_rate       = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+}
+`
+
+const testAccServiceOfferingFixed2_update = `
+resource "cloudstack_service_offering_fixed" "fixed2" {
+       display_text = "fixed2update"
+       name         = "fixed2update"
+
+       cpu_number     = 2
+       cpu_speed      = 2500
+       memory         = 2048
+
+       host_tags          = "test0101,test0202"
+       network_rate       = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+}
+`
+
+const testAccServiceOfferingFixed_disk = `
+resource "cloudstack_service_offering_fixed" "disk" {
+       display_text = "disk"
+       name         = "disk"
+
+       // compute
+       cpu_number     = 2
+       cpu_speed      = 2500
+       memory         = 2048
+
+       // other
+       host_tags          = "test0101, test0202"
+       network_rate       = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+       disk_offering = {
+               storage_type = "local"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "test0101,test0202"
+               disk_offering_strictness = false
+       }
+}
+`
+
+const testAccServiceOfferingFixed_disk_hypervisor = `
+resource "cloudstack_service_offering_fixed" "disk_hypervisor" {
+       display_text = "disk_hypervisor"
+       name         = "disk_hypervisor"
+
+       // compute
+       cpu_number     = 2
+       cpu_speed      = 2500
+       memory         = 2048
+
+       // other
+       host_tags          = "test0101, test0202"
+       network_rate       = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+       disk_offering = {
+               storage_type = "local"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "test0101,test0202"
+               disk_offering_strictness = false
+       }
+       disk_hypervisor = {
+               bytes_read_rate             = 1024
+               bytes_read_rate_max         = 1024
+               bytes_read_rate_max_length  = 1024
+               bytes_write_rate            = 1024
+               bytes_write_rate_max        = 1024
+               bytes_write_rate_max_length = 1024
+       }
+}
+`
+
+const testAccServiceOfferingFixed_disk_storage = `
+resource "cloudstack_service_offering_fixed" "disk_storage" {
+       display_text = "disk_storage"
+       name         = "disk_storage"
+
+       // compute
+       cpu_number     = 2
+       cpu_speed      = 2500
+       memory         = 2048
+
+       // other
+       host_tags          = "test0101, test0202"
+       network_rate       = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+
+       disk_offering = {
+               storage_type = "local"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "test0101,test0202"
+               disk_offering_strictness = false
+       }
+       disk_storage = {
+               min_iops = 100
+               max_iops = 100
+       }
+}
+`
diff --git a/cloudstack/service_offering_models.go 
b/cloudstack/service_offering_models.go
new file mode 100644
index 0000000..a93ffa4
--- /dev/null
+++ b/cloudstack/service_offering_models.go
@@ -0,0 +1,86 @@
+//
+// 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 cloudstack
+
+import "github.com/hashicorp/terraform-plugin-framework/types"
+
+type serviceOfferingConstrainedResourceModel struct {
+       CpuSpeed     types.Int32 `tfsdk:"cpu_speed"`
+       MaxCpuNumber types.Int32 `tfsdk:"max_cpu_number"`
+       MaxMemory    types.Int32 `tfsdk:"max_memory"`
+       MinCpuNumber types.Int32 `tfsdk:"min_cpu_number"`
+       MinMemory    types.Int32 `tfsdk:"min_memory"`
+       serviceOfferingCommonResourceModel
+}
+
+type serviceOfferingUnconstrainedResourceModel struct {
+       serviceOfferingCommonResourceModel
+}
+
+type serviceOfferingFixedResourceModel struct {
+       CpuNumber types.Int32 `tfsdk:"cpu_number"`
+       CpuSpeed  types.Int32 `tfsdk:"cpu_speed"`
+       Memory    types.Int32 `tfsdk:"memory"`
+       serviceOfferingCommonResourceModel
+}
+
+type serviceOfferingCommonResourceModel struct {
+       DeploymentPlanner                types.String 
`tfsdk:"deployment_planner"`
+       DiskOfferingId                   types.String `tfsdk:"disk_offering_id"`
+       DisplayText                      types.String `tfsdk:"display_text"`
+       DomainIds                        types.Set    `tfsdk:"domain_ids"`
+       DynamicScalingEnabled            types.Bool   
`tfsdk:"dynamic_scaling_enabled"`
+       HostTags                         types.String `tfsdk:"host_tags"`
+       Id                               types.String `tfsdk:"id"`
+       IsVolatile                       types.Bool   `tfsdk:"is_volatile"`
+       LimitCpuUse                      types.Bool   `tfsdk:"limit_cpu_use"`
+       Name                             types.String `tfsdk:"name"`
+       NetworkRate                      types.Int32  `tfsdk:"network_rate"`
+       OfferHa                          types.Bool   `tfsdk:"offer_ha"`
+       ZoneIds                          types.Set    `tfsdk:"zone_ids"`
+       ServiceOfferingDiskQosHypervisor types.Object `tfsdk:"disk_hypervisor"`
+       ServiceOfferingDiskOffering      types.Object `tfsdk:"disk_offering"`
+       ServiceOfferingDiskQosStorage    types.Object `tfsdk:"disk_storage"`
+}
+
+type ServiceOfferingDiskQosHypervisor struct {
+       DiskBytesReadRate           types.Int64 `tfsdk:"bytes_read_rate"`
+       DiskBytesReadRateMax        types.Int64 `tfsdk:"bytes_read_rate_max"`
+       DiskBytesReadRateMaxLength  types.Int64 
`tfsdk:"bytes_read_rate_max_length"`
+       DiskBytesWriteRate          types.Int64 `tfsdk:"bytes_write_rate"`
+       DiskBytesWriteRateMax       types.Int64 `tfsdk:"bytes_write_rate_max"`
+       DiskBytesWriteRateMaxLength types.Int64 
`tfsdk:"bytes_write_rate_max_length"`
+}
+
+type ServiceOfferingDiskOffering struct {
+       CacheMode              types.String `tfsdk:"cache_mode"`
+       DiskOfferingStrictness types.Bool   `tfsdk:"disk_offering_strictness"`
+       ProvisionType          types.String `tfsdk:"provisioning_type"`
+       RootDiskSize           types.Int64  `tfsdk:"root_disk_size"`
+       StorageType            types.String `tfsdk:"storage_type"`
+       StorageTags            types.String `tfsdk:"storage_tags"`
+}
+
+type ServiceOfferingDiskQosStorage struct {
+       CustomizedIops            types.Bool  `tfsdk:"customized_iops"`
+       HypervisorSnapshotReserve types.Int32 
`tfsdk:"hypervisor_snapshot_reserve"`
+       MaxIops                   types.Int64 `tfsdk:"max_iops"`
+       MinIops                   types.Int64 `tfsdk:"min_iops"`
+}
diff --git a/cloudstack/service_offering_schema.go 
b/cloudstack/service_offering_schema.go
new file mode 100644
index 0000000..9586d51
--- /dev/null
+++ b/cloudstack/service_offering_schema.go
@@ -0,0 +1,248 @@
+//
+// 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.
+//
+
+// Nested schema attributes arent validated
+// disk_offering, disk_hypervisor, disk_storage
+// ref: https://github.com/hashicorp/terraform-plugin-framework/issues/805
+
+package cloudstack
+
+import (
+       "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+       
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+       "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+func serviceOfferingMergeCommonSchema(s1 map[string]schema.Attribute) 
map[string]schema.Attribute {
+       common := map[string]schema.Attribute{
+               "deployment_planner": schema.StringAttribute{
+                       Description: "The deployment planner for the service 
offering",
+                       Optional:    true,
+               },
+               "disk_offering_id": schema.StringAttribute{
+                       Description: "The ID of the disk offering",
+                       Optional:    true,
+               },
+               "display_text": schema.StringAttribute{
+                       Description: "The display text of the service offering",
+                       Required:    true,
+               },
+               "domain_ids": schema.SetAttribute{
+                       Description: "the ID of the containing domain(s), null 
for public offerings",
+                       Optional:    true,
+                       ElementType: types.StringType,
+               },
+               "dynamic_scaling_enabled": schema.BoolAttribute{
+                       Description: "Enable dynamic scaling of the service 
offering",
+                       Optional:    true,
+                       Computed:    true,
+                       PlanModifiers: []planmodifier.Bool{
+                               boolplanmodifier.RequiresReplace(),
+                       },
+                       Default: booldefault.StaticBool(false),
+               },
+               "host_tags": schema.StringAttribute{
+                       Description: "The host tag for this service offering",
+                       Optional:    true,
+               },
+               "id": schema.StringAttribute{
+                       Description: "uuid of service offering",
+                       Computed:    true,
+                       PlanModifiers: []planmodifier.String{
+                               stringplanmodifier.UseStateForUnknown(),
+                       },
+               },
+               "is_volatile": schema.BoolAttribute{
+                       Description: "Service offering is volatile",
+                       Optional:    true,
+                       Computed:    true,
+                       PlanModifiers: []planmodifier.Bool{
+                               boolplanmodifier.RequiresReplace(),
+                       },
+                       Default: booldefault.StaticBool(false),
+               },
+               "limit_cpu_use": schema.BoolAttribute{
+                       Description: "Restrict the CPU usage to committed 
service offering",
+                       Optional:    true,
+                       Computed:    true,
+                       PlanModifiers: []planmodifier.Bool{
+                               boolplanmodifier.RequiresReplace(),
+                       },
+                       Default: booldefault.StaticBool(false),
+               },
+               "name": schema.StringAttribute{
+                       Description: "The name of the service offering",
+                       Required:    true,
+               },
+               "network_rate": schema.Int32Attribute{
+                       Description: "Data transfer rate in megabits per 
second",
+                       Optional:    true,
+               },
+               "offer_ha": schema.BoolAttribute{
+                       Description: "The HA for the service offering",
+                       Optional:    true,
+                       Computed:    true,
+                       PlanModifiers: []planmodifier.Bool{
+                               boolplanmodifier.RequiresReplace(),
+                       },
+                       Default: booldefault.StaticBool(false),
+               },
+               "zone_ids": schema.SetAttribute{
+                       Description: "The ID of the zone(s)",
+                       Optional:    true,
+                       ElementType: types.StringType,
+               },
+               "disk_offering": schema.SingleNestedAttribute{
+                       Optional: true,
+                       Attributes: map[string]schema.Attribute{
+                               "cache_mode": schema.StringAttribute{
+                                       Description: "the cache mode to use for 
this disk offering. none, writeback or writethrough",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.String{
+                                               
stringplanmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "disk_offering_strictness": 
schema.BoolAttribute{
+                                       Description: "True/False to indicate 
the strictness of the disk offering association with the compute offering. When 
set to true, override of disk offering is not allowed when VM is deployed and 
change disk offering is not allowed for the ROOT disk after the VM is deployed",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Bool{
+                                               
boolplanmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "provisioning_type": schema.StringAttribute{
+                                       Description: "provisioning type used to 
create volumes. Valid values are thin, sparse, fat.",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.String{
+                                               
stringplanmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "root_disk_size": schema.Int64Attribute{
+                                       Description: "the Root disk size in 
GB.",
+                                       Optional:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "storage_type": schema.StringAttribute{
+                                       Description: "the storage type of the 
service offering. Values are local and shared.",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.String{
+                                               
stringplanmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "storage_tags": schema.StringAttribute{
+                                       Description: "the tags for the service 
offering",
+                                       Optional:    true,
+                               },
+                       },
+               },
+               "disk_hypervisor": schema.SingleNestedAttribute{
+                       Optional: true,
+                       Attributes: map[string]schema.Attribute{
+                               "bytes_read_rate": schema.Int64Attribute{
+                                       Description: "io requests read rate of 
the disk offering",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "bytes_read_rate_max": schema.Int64Attribute{
+                                       Description: "burst requests read rate 
of the disk offering",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "bytes_read_rate_max_length": 
schema.Int64Attribute{
+                                       Description: "length (in seconds) of 
the burst",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "bytes_write_rate": schema.Int64Attribute{
+                                       Description: "io requests write rate of 
the disk offering",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "bytes_write_rate_max": schema.Int64Attribute{
+                                       Description: "burst io requests write 
rate of the disk offering",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "bytes_write_rate_max_length": 
schema.Int64Attribute{
+                                       Description: "length (in seconds) of 
the burst",
+                                       Required:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                       },
+               },
+               "disk_storage": schema.SingleNestedAttribute{
+                       Optional: true,
+                       Attributes: map[string]schema.Attribute{
+                               "customized_iops": schema.BoolAttribute{
+                                       Description: "true if disk offering 
uses custom iops, false otherwise",
+                                       Optional:    true,
+                                       PlanModifiers: []planmodifier.Bool{
+                                               
boolplanmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "hypervisor_snapshot_reserve": 
schema.Int32Attribute{
+                                       Description: "Hypervisor snapshot 
reserve space as a percent of a volume (for managed storage using Xen or 
VMware)",
+                                       Optional:    true,
+                                       PlanModifiers: []planmodifier.Int32{
+                                               
int32planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "max_iops": schema.Int64Attribute{
+                                       Description: "max iops of the compute 
offering",
+                                       Optional:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                               "min_iops": schema.Int64Attribute{
+                                       Description: "min iops of the compute 
offering",
+                                       Optional:    true,
+                                       PlanModifiers: []planmodifier.Int64{
+                                               
int64planmodifier.RequiresReplace(),
+                                       },
+                               },
+                       },
+               },
+       }
+
+       for key, value := range s1 {
+               common[key] = value
+       }
+
+       return common
+
+}
diff --git a/cloudstack/service_offering_unconstrained_resource.go 
b/cloudstack/service_offering_unconstrained_resource.go
new file mode 100644
index 0000000..98b937c
--- /dev/null
+++ b/cloudstack/service_offering_unconstrained_resource.go
@@ -0,0 +1,204 @@
+//
+// 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 cloudstack
+
+import (
+       "context"
+       "fmt"
+
+       "github.com/apache/cloudstack-go/v2/cloudstack"
+       "github.com/hashicorp/terraform-plugin-framework/resource"
+       "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+       "github.com/hashicorp/terraform-plugin-framework/types"
+       "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+)
+
+var (
+       _ resource.Resource              = 
&serviceOfferingUnconstrainedResource{}
+       _ resource.ResourceWithConfigure = 
&serviceOfferingUnconstrainedResource{}
+)
+
+func NewserviceOfferingUnconstrainedResource() resource.Resource {
+       return &serviceOfferingUnconstrainedResource{}
+}
+
+type serviceOfferingUnconstrainedResource struct {
+       client *cloudstack.CloudStackClient
+}
+
+// Schema defines the schema for the resource.
+func (r *serviceOfferingUnconstrainedResource) Schema(_ context.Context, _ 
resource.SchemaRequest, resp *resource.SchemaResponse) {
+       resp.Schema = schema.Schema{
+               Attributes: 
serviceOfferingMergeCommonSchema(map[string]schema.Attribute{}),
+       }
+}
+
+func (r *serviceOfferingUnconstrainedResource) Create(ctx context.Context, req 
resource.CreateRequest, resp *resource.CreateResponse) {
+       var plan serviceOfferingUnconstrainedResourceModel
+       var planDiskQosHypervisor ServiceOfferingDiskQosHypervisor
+       var planDiskOffering ServiceOfferingDiskOffering
+       var planDiskQosStorage ServiceOfferingDiskQosStorage
+
+       resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+       if !plan.ServiceOfferingDiskQosHypervisor.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskQosHypervisor.As(ctx, 
&planDiskQosHypervisor, basetypes.ObjectAsOptions{})...)
+       }
+       if !plan.ServiceOfferingDiskOffering.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskOffering.As(ctx, 
&planDiskOffering, basetypes.ObjectAsOptions{})...)
+       }
+       if !plan.ServiceOfferingDiskQosStorage.IsNull() {
+               
resp.Diagnostics.Append(plan.ServiceOfferingDiskQosStorage.As(ctx, 
&planDiskQosStorage, basetypes.ObjectAsOptions{})...)
+       }
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       // cloudstack params
+       params := 
r.client.ServiceOffering.NewCreateServiceOfferingParams(plan.DisplayText.ValueString(),
 plan.Name.ValueString())
+       plan.commonCreateParams(ctx, params)
+       planDiskQosHypervisor.commonCreateParams(ctx, params)
+       planDiskOffering.commonCreateParams(ctx, params)
+       planDiskQosStorage.commonCreateParams(ctx, params)
+
+       // create offering
+       cs, err := r.client.ServiceOffering.CreateServiceOffering(params)
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error creating service offering",
+                       "Could not create unconstrained offering, unexpected 
error: "+err.Error(),
+               )
+               return
+       }
+
+       plan.Id = types.StringValue(cs.Id)
+       resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
+
+}
+
+func (r *serviceOfferingUnconstrainedResource) Read(ctx context.Context, req 
resource.ReadRequest, resp *resource.ReadResponse) {
+       var state serviceOfferingUnconstrainedResourceModel
+       var stateDiskQosHypervisor ServiceOfferingDiskQosHypervisor
+       var stateDiskOffering ServiceOfferingDiskOffering
+       var stateDiskQosStorage ServiceOfferingDiskQosStorage
+
+       resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+       if !state.ServiceOfferingDiskQosHypervisor.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskQosHypervisor.As(ctx, 
&stateDiskQosHypervisor, basetypes.ObjectAsOptions{})...)
+       }
+       if !state.ServiceOfferingDiskOffering.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskOffering.As(ctx, 
&stateDiskOffering, basetypes.ObjectAsOptions{})...)
+       }
+       if !state.ServiceOfferingDiskQosStorage.IsNull() {
+               
resp.Diagnostics.Append(state.ServiceOfferingDiskQosStorage.As(ctx, 
&stateDiskQosStorage, basetypes.ObjectAsOptions{})...)
+       }
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       cs, _, err := 
r.client.ServiceOffering.GetServiceOfferingByID(state.Id.ValueString())
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error creating service offering",
+                       "Could not read unconstrained service offering, 
unexpected error: "+err.Error(),
+               )
+               return
+       }
+
+       state.commonRead(ctx, cs)
+       stateDiskQosHypervisor.commonRead(ctx, cs)
+       stateDiskOffering.commonRead(ctx, cs)
+       stateDiskQosStorage.commonRead(ctx, cs)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+
+}
+
+func (r *serviceOfferingUnconstrainedResource) Update(ctx context.Context, req 
resource.UpdateRequest, resp *resource.UpdateResponse) {
+       var state serviceOfferingUnconstrainedResourceModel
+
+       resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       params := 
r.client.ServiceOffering.NewUpdateServiceOfferingParams(state.Id.ValueString())
+       state.commonUpdateParams(ctx, params)
+
+       cs, err := r.client.ServiceOffering.UpdateServiceOffering(params)
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error updating service offering",
+                       "Could not update unconstrained service offering, 
unexpected error: "+err.Error(),
+               )
+               return
+       }
+
+       state.commonUpdate(ctx, cs)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+       resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+
+}
+
+func (r *serviceOfferingUnconstrainedResource) Delete(ctx context.Context, req 
resource.DeleteRequest, resp *resource.DeleteResponse) {
+       var state serviceOfferingUnconstrainedResourceModel
+
+       diags := req.State.Get(ctx, &state)
+       resp.Diagnostics.Append(diags...)
+       if resp.Diagnostics.HasError() {
+               return
+       }
+
+       // Delete the service offering
+       _, err := 
r.client.ServiceOffering.DeleteServiceOffering(r.client.ServiceOffering.NewDeleteServiceOfferingParams(state.Id.ValueString()))
+       if err != nil {
+               resp.Diagnostics.AddError(
+                       "Error deleting service offering",
+                       "Could not delete unconstrained offering, unexpected 
error: "+err.Error(),
+               )
+               return
+       }
+}
+
+func (r *serviceOfferingUnconstrainedResource) Configure(_ context.Context, 
req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+       if req.ProviderData == nil {
+               return
+       }
+
+       client, ok := req.ProviderData.(*cloudstack.CloudStackClient)
+
+       if !ok {
+               resp.Diagnostics.AddError(
+                       "Unexpected Data Source Configure Type",
+                       fmt.Sprintf("Expected *cloudstack.CloudStackClient, 
got: %T. Please report this issue to the provider developers.", 
req.ProviderData),
+               )
+               return
+       }
+
+       r.client = client
+}
+
+func (r *serviceOfferingUnconstrainedResource) Metadata(_ context.Context, req 
resource.MetadataRequest, resp *resource.MetadataResponse) {
+       resp.TypeName = req.ProviderTypeName + "_service_offering_unconstrained"
+}
diff --git a/cloudstack/service_offering_unconstrained_resource_test.go 
b/cloudstack/service_offering_unconstrained_resource_test.go
new file mode 100644
index 0000000..5aba779
--- /dev/null
+++ b/cloudstack/service_offering_unconstrained_resource_test.go
@@ -0,0 +1,207 @@
+// //
+// // 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 cloudstack
+
+import (
+       "testing"
+
+       "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccServiceOfferingUnconstrained(t *testing.T) {
+       resource.Test(t, resource.TestCase{
+               PreCheck:                 func() { testAccPreCheck(t) },
+               ProtoV6ProviderFactories: testAccMuxProvider,
+               Steps: []resource.TestStep{
+                       {
+                               Config: testAccServiceOfferingUnconstrained1,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_unconstrained.unconstrained1",
 "name", "unconstrained1"),
+                               ),
+                       },
+                       {
+                               Config: testAccServiceOfferingUnconstrained2,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_unconstrained.unconstrained2",
 "name", "unconstrained2"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingUnconstrained2_update,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_unconstrained.unconstrained2",
 "name", "unconstrained2update"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingUnconstrained_disk,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_unconstrained.disk",
 "name", "disk"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingUnconstrained_disk_hypervisor,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_unconstrained.disk_hypervisor",
 "name", "disk_hypervisor"),
+                               ),
+                       },
+                       {
+                               Config: 
testAccServiceOfferingUnconstrained_disk_storage,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
resource.TestCheckResourceAttr("cloudstack_service_offering_unconstrained.disk_storage",
 "name", "disk_storage"),
+                               ),
+                       },
+               },
+       })
+}
+
+const testAccServiceOfferingUnconstrained1 = `
+resource "cloudstack_service_offering_unconstrained" "unconstrained1" {
+       display_text = "unconstrained1"
+       name         = "unconstrained1"
+
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+}
+`
+
+const testAccServiceOfferingUnconstrained2 = `
+resource "cloudstack_service_offering_unconstrained" "unconstrained2" {
+       display_text = "unconstrained2"
+       name         = "unconstrained2"
+
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+}
+`
+
+const testAccServiceOfferingUnconstrained2_update = `
+resource "cloudstack_service_offering_unconstrained" "unconstrained2" {
+       display_text = "unconstrained2update"
+       name         = "unconstrained2update"
+
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+}
+`
+
+const testAccServiceOfferingUnconstrained_disk = `
+resource "cloudstack_service_offering_unconstrained" "disk" {
+       display_text = "disk"
+       name         = "disk"
+
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+
+       disk_offering = {
+               storage_type = "shared"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "test0101,test0202"
+               disk_offering_strictness = false
+       }
+}
+`
+
+const testAccServiceOfferingUnconstrained_disk_hypervisor = `
+resource "cloudstack_service_offering_unconstrained" "disk_hypervisor" {
+       display_text = "disk_hypervisor"
+       name         = "disk_hypervisor"
+
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+
+       disk_offering = {
+               storage_type = "shared"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "test0101,test0202"
+               disk_offering_strictness = false
+       }
+       disk_hypervisor = {
+               bytes_read_rate             = 1024
+               bytes_read_rate_max         = 1024
+               bytes_read_rate_max_length  = 1024
+               bytes_write_rate            = 1024
+               bytes_write_rate_max        = 1024
+               bytes_write_rate_max_length = 1024
+       }
+
+}
+`
+
+const testAccServiceOfferingUnconstrained_disk_storage = `
+resource "cloudstack_service_offering_unconstrained" "disk_storage" {
+       display_text = "disk_storage"
+       name         = "disk_storage"
+
+       host_tags = "test0101,test0202"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = true
+       is_volatile             = true
+       limit_cpu_use           = true
+       offer_ha                = true
+
+       disk_offering = {
+               storage_type = "shared"
+               provisioning_type = "thin"
+               cache_mode = "none"
+               root_disk_size = "5"
+               storage_tags = "test0101,test0202"
+               disk_offering_strictness = false
+       }
+       disk_storage = {
+               min_iops = 100
+               max_iops = 100
+       }
+}
+`
diff --git a/cloudstack/service_offering_util.go 
b/cloudstack/service_offering_util.go
new file mode 100644
index 0000000..ae52aa1
--- /dev/null
+++ b/cloudstack/service_offering_util.go
@@ -0,0 +1,277 @@
+// 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 cloudstack
+
+import (
+       "context"
+       "strings"
+
+       "github.com/apache/cloudstack-go/v2/cloudstack"
+       "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+// 
------------------------------------------------------------------------------------------------------------------------------
+// Common update methods
+// -
+func (state *serviceOfferingCommonResourceModel) commonUpdate(ctx 
context.Context, cs *cloudstack.UpdateServiceOfferingResponse) {
+       if cs.Displaytext != "" {
+               state.DisplayText = types.StringValue(cs.Displaytext)
+       }
+       if cs.Domainid != "" {
+               state.DomainIds, _ = types.SetValueFrom(ctx, types.StringType, 
strings.Split(cs.Domainid, ","))
+       }
+       if cs.Hosttags != "" {
+               state.HostTags = types.StringValue(cs.Hosttags)
+       }
+       if cs.Name != "" {
+               state.Name = types.StringValue(cs.Name)
+       }
+       if cs.Zoneid != "" {
+               state.ZoneIds, _ = types.SetValueFrom(ctx, types.StringType, 
strings.Split(cs.Zoneid, ","))
+       }
+}
+
+func (plan *serviceOfferingCommonResourceModel) commonUpdateParams(ctx 
context.Context, p *cloudstack.UpdateServiceOfferingParams) 
*cloudstack.UpdateServiceOfferingParams {
+       if !plan.DisplayText.IsNull() {
+               p.SetDisplaytext(plan.DisplayText.ValueString())
+       }
+       if !plan.DomainIds.IsNull() {
+               p.SetDomainid(plan.DomainIds.String())
+       }
+       if !plan.HostTags.IsNull() {
+               p.SetHosttags(plan.HostTags.ValueString())
+       }
+       if !plan.Name.IsNull() {
+               p.SetName(plan.Name.ValueString())
+       }
+       if !plan.ZoneIds.IsNull() && len(plan.ZoneIds.Elements()) > 0 {
+               p.SetZoneid(plan.ZoneIds.String())
+       } else {
+               p.SetZoneid("all")
+       }
+
+       return p
+
+}
+
+// 
------------------------------------------------------------------------------------------------------------------------------
+// common Read methods
+// -
+func (state *serviceOfferingCommonResourceModel) commonRead(ctx 
context.Context, cs *cloudstack.ServiceOffering) {
+       state.Id = types.StringValue(cs.Id)
+
+       if cs.Deploymentplanner != "" {
+               state.DeploymentPlanner = 
types.StringValue(cs.Deploymentplanner)
+       }
+       if cs.Diskofferingid != "" {
+               state.DiskOfferingId = types.StringValue(cs.Diskofferingid)
+       }
+       if cs.Displaytext != "" {
+               state.DisplayText = types.StringValue(cs.Displaytext)
+       }
+       if cs.Domainid != "" {
+               state.DomainIds, _ = types.SetValueFrom(ctx, types.StringType, 
strings.Split(cs.Domainid, ","))
+       }
+       if cs.Hosttags != "" {
+               state.HostTags = types.StringValue(cs.Hosttags)
+       }
+       if cs.Name != "" {
+               state.Name = types.StringValue(cs.Name)
+       }
+       if cs.Networkrate > 0 {
+               state.NetworkRate = types.Int32Value(int32(cs.Networkrate))
+       }
+       if cs.Zoneid != "" {
+               state.ZoneIds, _ = types.SetValueFrom(ctx, types.StringType, 
strings.Split(cs.Zoneid, ","))
+       }
+
+       state.DynamicScalingEnabled = types.BoolValue(cs.Dynamicscalingenabled)
+       state.IsVolatile = types.BoolValue(cs.Isvolatile)
+       state.LimitCpuUse = types.BoolValue(cs.Limitcpuuse)
+       state.OfferHa = types.BoolValue(cs.Offerha)
+
+}
+
+func (state *ServiceOfferingDiskQosHypervisor) commonRead(ctx context.Context, 
cs *cloudstack.ServiceOffering) {
+       if cs.DiskBytesReadRate > 0 {
+               state.DiskBytesReadRate = types.Int64Value(cs.DiskBytesReadRate)
+       }
+       if cs.DiskBytesReadRateMax > 0 {
+               state.DiskBytesReadRateMax = 
types.Int64Value(cs.DiskBytesReadRateMax)
+       }
+       if cs.DiskBytesReadRateMaxLength > 0 {
+               state.DiskBytesReadRateMaxLength = 
types.Int64Value(cs.DiskBytesReadRateMaxLength)
+       }
+       if cs.DiskBytesWriteRate > 0 {
+               state.DiskBytesWriteRate = 
types.Int64Value(cs.DiskBytesWriteRate)
+       }
+       if cs.DiskBytesWriteRateMax > 0 {
+               state.DiskBytesWriteRateMax = 
types.Int64Value(cs.DiskBytesWriteRateMax)
+       }
+       if cs.DiskBytesWriteRateMaxLength > 0 {
+               state.DiskBytesWriteRateMaxLength = 
types.Int64Value(cs.DiskBytesWriteRateMaxLength)
+       }
+
+}
+
+func (state *ServiceOfferingDiskOffering) commonRead(ctx context.Context, cs 
*cloudstack.ServiceOffering) {
+
+       if cs.CacheMode != "" {
+               state.CacheMode = types.StringValue(cs.CacheMode)
+       }
+       if cs.Diskofferingstrictness {
+               state.DiskOfferingStrictness = 
types.BoolValue(cs.Diskofferingstrictness)
+       }
+       if cs.Provisioningtype != "" {
+               state.ProvisionType = types.StringValue(cs.Provisioningtype)
+       }
+       if cs.Rootdisksize > 0 {
+               state.RootDiskSize = types.Int64Value(cs.Rootdisksize)
+       }
+       if cs.Storagetype != "" {
+               state.StorageType = types.StringValue(cs.Storagetype)
+       }
+       if cs.Storagetags != "" {
+               state.StorageTags = types.StringValue(cs.Storagetags)
+       }
+}
+
+func (state *ServiceOfferingDiskQosStorage) commonRead(ctx context.Context, cs 
*cloudstack.ServiceOffering) {
+       if cs.Iscustomizediops {
+               state.CustomizedIops = types.BoolValue(cs.Iscustomizediops)
+       }
+       if cs.Hypervisorsnapshotreserve > 0 {
+               state.HypervisorSnapshotReserve = 
types.Int32Value(int32(cs.Hypervisorsnapshotreserve))
+       }
+       if cs.Maxiops > 0 {
+               state.MaxIops = types.Int64Value(cs.Maxiops)
+       }
+       if cs.Miniops > 0 {
+               state.MinIops = types.Int64Value(cs.Miniops)
+       }
+
+}
+
+// 
------------------------------------------------------------------------------------------------------------------------------
+// common Create methods
+// -
+func (plan *serviceOfferingCommonResourceModel) commonCreateParams(ctx 
context.Context, p *cloudstack.CreateServiceOfferingParams) 
*cloudstack.CreateServiceOfferingParams {
+       if !plan.DeploymentPlanner.IsNull() && 
!plan.DeploymentPlanner.IsUnknown() {
+               p.SetDeploymentplanner(plan.DeploymentPlanner.ValueString())
+       } else {
+               plan.DeploymentPlanner = types.StringNull()
+       }
+       if !plan.DiskOfferingId.IsNull() {
+               p.SetDiskofferingid(plan.DiskOfferingId.ValueString())
+       }
+       if !plan.DomainIds.IsNull() {
+               domainids := make([]string, len(plan.DomainIds.Elements()))
+               plan.DomainIds.ElementsAs(ctx, &domainids, false)
+               p.SetDomainid(domainids)
+       }
+       if !plan.DynamicScalingEnabled.IsNull() {
+               
p.SetDynamicscalingenabled(plan.DynamicScalingEnabled.ValueBool())
+       }
+       if !plan.HostTags.IsNull() {
+               p.SetHosttags(plan.HostTags.ValueString())
+       }
+       if !plan.IsVolatile.IsNull() {
+               p.SetIsvolatile(plan.IsVolatile.ValueBool())
+       }
+       if !plan.LimitCpuUse.IsNull() {
+               p.SetLimitcpuuse(plan.LimitCpuUse.ValueBool())
+       }
+       if !plan.NetworkRate.IsNull() {
+               p.SetNetworkrate(int(plan.NetworkRate.ValueInt32()))
+       }
+       if !plan.OfferHa.IsNull() {
+               p.SetOfferha(plan.OfferHa.ValueBool())
+       }
+       if !plan.ZoneIds.IsNull() {
+               zoneIds := make([]string, len(plan.ZoneIds.Elements()))
+               plan.ZoneIds.ElementsAs(ctx, &zoneIds, false)
+               p.SetZoneid(zoneIds)
+       }
+
+       return p
+
+}
+func (plan *ServiceOfferingDiskQosHypervisor) commonCreateParams(ctx 
context.Context, p *cloudstack.CreateServiceOfferingParams) 
*cloudstack.CreateServiceOfferingParams {
+       if !plan.DiskBytesReadRate.IsNull() {
+               p.SetBytesreadrate(plan.DiskBytesReadRate.ValueInt64())
+       }
+       if !plan.DiskBytesReadRateMax.IsNull() {
+               p.SetBytesreadratemax(plan.DiskBytesReadRateMax.ValueInt64())
+       }
+       if !plan.DiskBytesReadRateMaxLength.IsNull() {
+               
p.SetBytesreadratemaxlength(plan.DiskBytesReadRateMaxLength.ValueInt64())
+       }
+       if !plan.DiskBytesWriteRate.IsNull() {
+               p.SetByteswriterate(plan.DiskBytesWriteRate.ValueInt64())
+       }
+       if !plan.DiskBytesWriteRateMax.IsNull() {
+               p.SetByteswriteratemax(plan.DiskBytesWriteRateMax.ValueInt64())
+       }
+       if !plan.DiskBytesWriteRateMaxLength.IsNull() {
+               
p.SetByteswriteratemaxlength(plan.DiskBytesWriteRateMaxLength.ValueInt64())
+       }
+
+       return p
+}
+
+func (plan *ServiceOfferingDiskOffering) commonCreateParams(ctx 
context.Context, p *cloudstack.CreateServiceOfferingParams) 
*cloudstack.CreateServiceOfferingParams {
+
+       if !plan.CacheMode.IsNull() {
+               p.SetCachemode(plan.CacheMode.ValueString())
+       }
+       if !plan.DiskOfferingStrictness.IsNull() {
+               
p.SetDiskofferingstrictness(plan.DiskOfferingStrictness.ValueBool())
+       }
+       if !plan.ProvisionType.IsNull() {
+               p.SetProvisioningtype(plan.ProvisionType.ValueString())
+       }
+       if !plan.RootDiskSize.IsNull() {
+               p.SetRootdisksize(plan.RootDiskSize.ValueInt64())
+       }
+       if !plan.StorageType.IsNull() {
+               p.SetStoragetype(plan.StorageType.ValueString())
+       }
+       if !plan.StorageTags.IsNull() {
+               p.SetTags(plan.StorageTags.ValueString())
+       }
+
+       return p
+
+}
+
+func (plan *ServiceOfferingDiskQosStorage) commonCreateParams(ctx 
context.Context, p *cloudstack.CreateServiceOfferingParams) 
*cloudstack.CreateServiceOfferingParams {
+       if !plan.CustomizedIops.IsNull() {
+               p.SetCustomizediops(plan.CustomizedIops.ValueBool())
+       }
+       if !plan.HypervisorSnapshotReserve.IsNull() {
+               
p.SetHypervisorsnapshotreserve(int(plan.HypervisorSnapshotReserve.ValueInt32()))
+       }
+       if !plan.MaxIops.IsNull() {
+               p.SetMaxiops(int64(plan.MaxIops.ValueInt64()))
+       }
+       if !plan.MinIops.IsNull() {
+               p.SetMiniops((plan.MinIops.ValueInt64()))
+       }
+
+       return p
+}
diff --git a/go.mod b/go.mod
index c09a776..de1b205 100644
--- a/go.mod
+++ b/go.mod
@@ -21,10 +21,10 @@ require (
        github.com/apache/cloudstack-go/v2 v2.17.1
        github.com/go-ini/ini v1.67.0
        github.com/hashicorp/go-multierror v1.1.1
-       github.com/hashicorp/terraform-plugin-framework v1.7.0
+       github.com/hashicorp/terraform-plugin-framework v1.12.0
        github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
-       github.com/hashicorp/terraform-plugin-go v0.22.1
-       github.com/hashicorp/terraform-plugin-mux v0.15.0
+       github.com/hashicorp/terraform-plugin-go v0.24.0
+       github.com/hashicorp/terraform-plugin-mux v0.16.0
        github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
        github.com/hashicorp/terraform-plugin-testing v1.7.0
 )
@@ -35,14 +35,15 @@ require (
        github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
        github.com/cloudflare/circl v1.6.1 // indirect
        github.com/fatih/color v1.16.0 // indirect
-       github.com/golang/protobuf v1.5.3 // indirect
+       github.com/golang/mock v1.6.0 // indirect
+       github.com/golang/protobuf v1.5.4 // indirect
        github.com/google/go-cmp v0.6.0 // indirect
        github.com/hashicorp/errwrap v1.0.0 // indirect
        github.com/hashicorp/go-checkpoint v0.5.0 // indirect
        github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
        github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // 
indirect
        github.com/hashicorp/go-hclog v1.6.2 // indirect
-       github.com/hashicorp/go-plugin v1.6.0 // indirect
+       github.com/hashicorp/go-plugin v1.6.1 // indirect
        github.com/hashicorp/go-uuid v1.0.3 // indirect
        github.com/hashicorp/go-version v1.6.0 // indirect
        github.com/hashicorp/hc-install v0.6.3 // indirect
@@ -77,10 +78,12 @@ require (
        golang.org/x/text v0.23.0 // indirect
        golang.org/x/tools v0.22.0 // indirect
        google.golang.org/appengine v1.6.8 // indirect
-       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20240123012728-ef4313101c80 // indirect
-       google.golang.org/grpc v1.62.1 // indirect
-       google.golang.org/protobuf v1.33.0 // indirect
+       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20240604185151-ef581f913117 // indirect
+       google.golang.org/grpc v1.66.2 // indirect
+       google.golang.org/protobuf v1.34.2 // indirect
        gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 )
 
 go 1.23.0
+
+toolchain go1.22.4
diff --git a/go.sum b/go.sum
index 3c302c0..d71638e 100644
--- a/go.sum
+++ b/go.sum
@@ -41,8 +41,8 @@ github.com/golang/groupcache 
v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er
 github.com/golang/protobuf v1.1.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.5.0/go.mod 
h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2/go.mod 
h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 
h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod 
h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod 
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/go-cmp v0.3.1/go.mod 
h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.5.5/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -60,8 +60,8 @@ github.com/hashicorp/go-hclog v1.6.2 
h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04n
 github.com/hashicorp/go-hclog v1.6.2/go.mod 
h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
 github.com/hashicorp/go-multierror v1.1.1 
h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
 github.com/hashicorp/go-multierror v1.1.1/go.mod 
h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-plugin v1.6.0 
h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
-github.com/hashicorp/go-plugin v1.6.0/go.mod 
h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
+github.com/hashicorp/go-plugin v1.6.1 
h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
+github.com/hashicorp/go-plugin v1.6.1/go.mod 
h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0=
 github.com/hashicorp/go-uuid v1.0.0/go.mod 
h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.3 
h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
 github.com/hashicorp/go-uuid v1.0.3/go.mod 
h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -77,16 +77,16 @@ github.com/hashicorp/terraform-exec v0.20.0 
h1:DIZnPsqzPGuUnq6cH8jWcPunBfY+C+M8J
 github.com/hashicorp/terraform-exec v0.20.0/go.mod 
h1:ckKGkJWbsNqFKV1itgMnE0hY9IYf1HoiekpuN0eWoDw=
 github.com/hashicorp/terraform-json v0.21.0 
h1:9NQxbLNqPbEMze+S6+YluEdXgJmhQykRyRNd+zTI05U=
 github.com/hashicorp/terraform-json v0.21.0/go.mod 
h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk=
-github.com/hashicorp/terraform-plugin-framework v1.7.0 
h1:wOULbVmfONnJo9iq7/q+iBOBJul5vRovaYJIu2cY/Pw=
-github.com/hashicorp/terraform-plugin-framework v1.7.0/go.mod 
h1:jY9Id+3KbZ17OMpulgnWLSfwxNVYSoYBQFTgsx044CI=
+github.com/hashicorp/terraform-plugin-framework v1.12.0 
h1:7HKaueHPaikX5/7cbC1r9d1m12iYHY+FlNZEGxQ42CQ=
+github.com/hashicorp/terraform-plugin-framework v1.12.0/go.mod 
h1:N/IOQ2uYjW60Jp39Cp3mw7I/OpC/GfZ0385R0YibmkE=
 github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 
h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
 github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod 
h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
-github.com/hashicorp/terraform-plugin-go v0.22.1 
h1:iTS7WHNVrn7uhe3cojtvWWn83cm2Z6ryIUDTRO0EV7w=
-github.com/hashicorp/terraform-plugin-go v0.22.1/go.mod 
h1:qrjnqRghvQ6KnDbB12XeZ4FluclYwptntoWCr9QaXTI=
+github.com/hashicorp/terraform-plugin-go v0.24.0 
h1:2WpHhginCdVhFIrWHxDEg6RBn3YaWzR2o6qUeIEat2U=
+github.com/hashicorp/terraform-plugin-go v0.24.0/go.mod 
h1:tUQ53lAsOyYSckFGEefGC5C8BAaO0ENqzFd3bQeuYQg=
 github.com/hashicorp/terraform-plugin-log v0.9.0 
h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
 github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod 
h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
-github.com/hashicorp/terraform-plugin-mux v0.15.0 
h1:+/+lDx0WUsIOpkAmdwBIoFU8UP9o2eZASoOnLsWbKME=
-github.com/hashicorp/terraform-plugin-mux v0.15.0/go.mod 
h1:9ezplb1Dyq394zQ+ldB0nvy/qbNAz3mMoHHseMTMaKo=
+github.com/hashicorp/terraform-plugin-mux v0.16.0 
h1:RCzXHGDYwUwwqfYYWJKBFaS3fQsWn/ZECEiW7p2023I=
+github.com/hashicorp/terraform-plugin-mux v0.16.0/go.mod 
h1:PF79mAsPc8CpusXPfEVa4X8PtkB+ngWoiUClMrNZlYo=
 github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 
h1:qHprzXy/As0rxedphECBEQAh3R4yp6pKksKHcqZx5G8=
 github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0/go.mod 
h1:H+8tjs9TjV2w57QFVSMBQacf8k/E1XwLXGCARgViC6A=
 github.com/hashicorp/terraform-plugin-testing v1.7.0 
h1:I6aeCyZ30z4NiI3tzyDoO6fS7YxP5xSL1ceOon3gTe8=
@@ -168,6 +168,7 @@ golang.org/x/crypto 
v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod 
h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
 golang.org/x/crypto v0.36.0/go.mod 
h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod 
h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
 golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
@@ -215,14 +216,14 @@ golang.org/x/xerrors 
v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 google.golang.org/appengine v1.1.0/go.mod 
h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.6.8 
h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
 google.golang.org/appengine v1.6.8/go.mod 
h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 
h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
-google.golang.org/genproto/googleapis/rpc 
v0.0.0-20240123012728-ef4313101c80/go.mod 
h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
-google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
-google.golang.org/grpc v1.62.1/go.mod 
h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 
h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
+google.golang.org/genproto/googleapis/rpc 
v0.0.0-20240604185151-ef581f913117/go.mod 
h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
+google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
+google.golang.org/grpc v1.66.2/go.mod 
h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod 
h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod 
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.33.0 
h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod 
h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 
h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod 
h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/website/docs/r/service_offering_constrained.html.markdown 
b/website/docs/r/service_offering_constrained.html.markdown
new file mode 100644
index 0000000..20a33b5
--- /dev/null
+++ b/website/docs/r/service_offering_constrained.html.markdown
@@ -0,0 +1,96 @@
+---
+page_title: "cloudstack_service_offering_constrained Resource"
+description: |-
+       Provides a CloudStack Constrained Service Offering resource. This 
allows you to create and manage constrained compute offerings in CloudStack.
+---
+
+# cloudstack_service_offering_constrained
+
+Provides a CloudStack Constrained Service Offering resource. This resource 
allows you to create and manage service offerings with constrained CPU and 
memory parameters.
+
+## Example Usage
+
+```hcl
+resource "cloudstack_service_offering_constrained" "example" {
+       display_text = "Example Constrained Offering"
+       name         = "example_constrained"
+
+       cpu_speed      = 2500
+       max_cpu_number = 10
+       min_cpu_number = 2
+       max_memory     = 4096
+       min_memory     = 1024
+
+       host_tags    = "tag1,tag2"
+       network_rate = 1024
+       deployment_planner = "UserDispersingPlanner"
+
+       dynamic_scaling_enabled = false
+       is_volatile             = false
+       limit_cpu_use           = false
+       offer_ha                = false
+       zone_ids = ["zone-uuid"]
+
+       disk_offering {
+               cache_mode                = "none"
+               disk_offering_strictness  = true
+               provisioning_type         = "thin"
+               storage_type              = "local"
+       }
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+- `display_text` (String, Required) - The display text of the service offering.
+- `name` (String, Required) - The name of the service offering.
+- `cpu_speed` (Int, Required) - CPU speed in MHz.
+- `max_cpu_number` (Int, Required) - Maximum number of CPUs.
+- `min_cpu_number` (Int, Required) - Minimum number of CPUs.
+- `max_memory` (Int, Required) - Maximum memory in MB.
+- `min_memory` (Int, Required) - Minimum memory in MB.
+- `deployment_planner` (String, Optional) - The deployment planner for the 
service offering.
+- `disk_offering_id` (String, Optional) - The ID of the disk offering.
+- `domain_ids` (Set of String, Optional) - The ID(s) of the containing 
domain(s), null for public offerings.
+- `dynamic_scaling_enabled` (Bool, Optional, Default: false) - Enable dynamic 
scaling of the service offering.
+- `host_tags` (String, Optional) - The host tag for this service offering.
+- `is_volatile` (Bool, Optional, Default: false) - Service offering is 
volatile.
+- `limit_cpu_use` (Bool, Optional, Default: false) - Restrict the CPU usage to 
committed service offering.
+- `network_rate` (Int, Optional) - Data transfer rate in megabits per second.
+- `offer_ha` (Bool, Optional, Default: false) - Enable HA for the service 
offering.
+- `zone_ids` (Set of String, Optional) - The ID(s) of the zone(s).
+
+### Nested Blocks
+
+#### `disk_offering` (Block, Optional)
+
+- `cache_mode` (String, Required) - The cache mode to use for this disk 
offering. One of `none`, `writeback`, or `writethrough`.
+- `disk_offering_strictness` (Bool, Required) - True/False to indicate the 
strictness of the disk offering association with the compute offering.
+- `provisioning_type` (String, Required) - Provisioning type used to create 
volumes. Valid values are `thin`, `sparse`, `fat`.
+- `root_disk_size` (Int, Optional) - The root disk size in GB.
+- `storage_type` (String, Required) - The storage type of the service 
offering. Values are `local` and `shared`.
+- `storage_tags` (String, Optional) - The tags for the service offering.
+
+#### `disk_hypervisor` (Block, Optional)
+
+- `bytes_read_rate` (Int, Required) - IO requests read rate of the disk 
offering.
+- `bytes_read_rate_max` (Int, Required) - Burst requests read rate of the disk 
offering.
+- `bytes_read_rate_max_length` (Int, Required) - Length (in seconds) of the 
burst.
+- `bytes_write_rate` (Int, Required) - IO requests write rate of the disk 
offering.
+- `bytes_write_rate_max` (Int, Required) - Burst IO requests write rate of the 
disk offering.
+- `bytes_write_rate_max_length` (Int, Required) - Length (in seconds) of the 
burst.
+
+#### `disk_storage` (Block, Optional)
+
+- `customized_iops` (Bool, Optional) - True if disk offering uses custom IOPS, 
false otherwise.
+- `hypervisor_snapshot_reserve` (Int, Optional) - Hypervisor snapshot reserve 
space as a percent of a volume (for managed storage using Xen or VMware).
+- `max_iops` (Int, Optional) - Max IOPS of the compute offering.
+- `min_iops` (Int, Optional) - Min IOPS of the compute offering.
+
+## Attributes Reference
+
+In addition to the arguments above, the following attributes are exported:
+
+- `id` - The UUID of the service offering.
diff --git a/website/docs/r/service_offering_fixed.html.markdown 
b/website/docs/r/service_offering_fixed.html.markdown
new file mode 100644
index 0000000..448baa4
--- /dev/null
+++ b/website/docs/r/service_offering_fixed.html.markdown
@@ -0,0 +1,101 @@
+---
+page_title: "cloudstack_service_offering_fixed Resource"
+sidebar_current: terraform-resource-service_offering_fixed
+description: |-
+  Provides a CloudStack Service Offering (Fixed) resource. This resource 
allows you to create and manage fixed compute service offerings in CloudStack.
+---
+
+# cloudstack_service_offering_fixed
+
+Provides a CloudStack Service Offering (Fixed) resource. This resource allows 
you to create and manage fixed compute service offerings in CloudStack.
+
+## Example Usage
+
+```hcl
+resource "cloudstack_service_offering_fixed" "fixed1" {
+  name         = "fixed1"
+  display_text = "fixed1"
+  cpu_number   = 2
+  cpu_speed    = 2000
+  memory       = 4096
+  # Optional common attributes:
+  # deployment_planner = "FirstFit"
+  # disk_offering_id   = "..."
+  # domain_ids         = ["...", "..."]
+  # dynamic_scaling_enabled = false
+  # host_tags          = "..."
+  # is_volatile        = false
+  # limit_cpu_use      = false
+  # network_rate       = 1000
+  # offer_ha           = false
+  # zone_ids           = ["..."]
+  # disk_offering { ... }
+  # disk_hypervisor { ... }
+  # disk_storage { ... }
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+- `name` (Required) - The name of the service offering.
+- `display_text` (Required) - The display text of the service offering.
+- `cpu_number` (Required) - Number of CPU cores.
+- `cpu_speed` (Required) - The CPU speed in MHz (not applicable to KVM).
+- `memory` (Required) - The total memory in MB.
+
+### Common Attributes
+
+- `deployment_planner` (Optional) - The deployment planner for the service 
offering.
+- `disk_offering_id` (Optional) - The ID of the disk offering.
+- `domain_ids` (Optional) - The ID(s) of the containing domain(s), null for 
public offerings.
+- `dynamic_scaling_enabled` (Optional, Computed) - Enable dynamic scaling of 
the service offering. Defaults to `false`.
+- `host_tags` (Optional) - The host tag for this service offering.
+- `id` (Computed) - The UUID of the service offering.
+- `is_volatile` (Optional, Computed) - Service offering is volatile. Defaults 
to `false`.
+- `limit_cpu_use` (Optional, Computed) - Restrict the CPU usage to committed 
service offering. Defaults to `false`.
+- `network_rate` (Optional) - Data transfer rate in megabits per second.
+- `offer_ha` (Optional, Computed) - The HA for the service offering. Defaults 
to `false`.
+- `zone_ids` (Optional) - The ID(s) of the zone(s).
+
+### Nested Blocks
+
+#### `disk_offering` (Optional)
+
+- `cache_mode` (Required) - The cache mode to use for this disk offering. One 
of `none`, `writeback`, or `writethrough`.
+- `disk_offering_strictness` (Required) - True/False to indicate the 
strictness of the disk offering association.
+- `provisioning_type` (Required) - Provisioning type used to create volumes. 
Valid values: `thin`, `sparse`, `fat`.
+- `root_disk_size` (Optional) - The root disk size in GB.
+- `storage_type` (Required) - The storage type. Values: `local`, `shared`.
+- `storage_tags` (Optional) - The tags for the service offering.
+
+#### `disk_hypervisor` (Optional)
+
+- `bytes_read_rate` (Required) - IO requests read rate.
+- `bytes_read_rate_max` (Required) - Burst requests read rate.
+- `bytes_read_rate_max_length` (Required) - Length (in seconds) of the burst.
+- `bytes_write_rate` (Required) - IO requests write rate.
+- `bytes_write_rate_max` (Required) - Burst IO requests write rate.
+- `bytes_write_rate_max_length` (Required) - Length (in seconds) of the burst.
+
+#### `disk_storage` (Optional)
+
+- `customized_iops` (Optional) - True if disk offering uses custom IOPS.
+- `hypervisor_snapshot_reserve` (Optional) - Hypervisor snapshot reserve space 
as a percent of a volume.
+- `max_iops` (Optional) - Max IOPS of the compute offering.
+- `min_iops` (Optional) - Min IOPS of the compute offering.
+
+## Attributes Reference
+
+In addition to the arguments above, the following attributes are exported:
+
+- `id` - The ID of the service offering.
+
+## Import
+
+Service offerings can be imported using the ID:
+
+```sh
+terraform import cloudstack_service_offering_fixed.example <id>
+```
diff --git a/website/docs/r/service_offering_unconstrained.html.markdown 
b/website/docs/r/service_offering_unconstrained.html.markdown
new file mode 100644
index 0000000..4a71140
--- /dev/null
+++ b/website/docs/r/service_offering_unconstrained.html.markdown
@@ -0,0 +1,95 @@
+---
+page_title: "cloudstack_service_offering_unconstrained Resource"
+sidebar_current: terraform-resource-service_offering_unconstrained
+description: |-
+  Provides a CloudStack Service Offering (Unconstrained) resource. This 
resource allows you to create and manage unconstrained compute service 
offerings in CloudStack.
+---
+
+# cloudstack_service_offering_unconstrained
+
+Provides a CloudStack Service Offering (Unconstrained) resource. This resource 
allows you to create and manage unconstrained compute service offerings in 
CloudStack.
+
+## Example Usage
+
+```hcl
+resource "cloudstack_service_offering_unconstrained" "unconstrained1" {
+  name         = "unconstrained1"
+  display_text = "unconstrained1"
+  # Optional common attributes:
+  # deployment_planner = "FirstFit"
+  # disk_offering_id   = "..."
+  # domain_ids         = ["...", "..."]
+  # dynamic_scaling_enabled = false
+  # host_tags          = "..."
+  # is_volatile        = false
+  # limit_cpu_use      = false
+  # network_rate       = 1000
+  # offer_ha           = false
+  # zone_ids           = ["..."]
+  # disk_offering { ... }
+  # disk_hypervisor { ... }
+  # disk_storage { ... }
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+- `name` (Required) - The name of the service offering.
+- `display_text` (Required) - The display text of the service offering.
+
+### Common Attributes
+
+- `deployment_planner` (Optional) - The deployment planner for the service 
offering.
+- `disk_offering_id` (Optional) - The ID of the disk offering.
+- `domain_ids` (Optional) - The ID(s) of the containing domain(s), null for 
public offerings.
+- `dynamic_scaling_enabled` (Optional, Computed) - Enable dynamic scaling of 
the service offering. Defaults to `false`.
+- `host_tags` (Optional) - The host tag for this service offering.
+- `id` (Computed) - The UUID of the service offering.
+- `is_volatile` (Optional, Computed) - Service offering is volatile. Defaults 
to `false`.
+- `limit_cpu_use` (Optional, Computed) - Restrict the CPU usage to committed 
service offering. Defaults to `false`.
+- `network_rate` (Optional) - Data transfer rate in megabits per second.
+- `offer_ha` (Optional, Computed) - The HA for the service offering. Defaults 
to `false`.
+- `zone_ids` (Optional) - The ID(s) of the zone(s).
+
+### Nested Blocks
+
+#### `disk_offering` (Optional)
+
+- `cache_mode` (Required) - The cache mode to use for this disk offering. One 
of `none`, `writeback`, or `writethrough`.
+- `disk_offering_strictness` (Required) - True/False to indicate the 
strictness of the disk offering association.
+- `provisioning_type` (Required) - Provisioning type used to create volumes. 
Valid values: `thin`, `sparse`, `fat`.
+- `root_disk_size` (Optional) - The root disk size in GB.
+- `storage_type` (Required) - The storage type. Values: `local`, `shared`.
+- `storage_tags` (Optional) - The tags for the service offering.
+
+#### `disk_hypervisor` (Optional)
+
+- `bytes_read_rate` (Required) - IO requests read rate.
+- `bytes_read_rate_max` (Required) - Burst requests read rate.
+- `bytes_read_rate_max_length` (Required) - Length (in seconds) of the burst.
+- `bytes_write_rate` (Required) - IO requests write rate.
+- `bytes_write_rate_max` (Required) - Burst IO requests write rate.
+- `bytes_write_rate_max_length` (Required) - Length (in seconds) of the burst.
+
+#### `disk_storage` (Optional)
+
+- `customized_iops` (Optional) - True if disk offering uses custom IOPS.
+- `hypervisor_snapshot_reserve` (Optional) - Hypervisor snapshot reserve space 
as a percent of a volume.
+- `max_iops` (Optional) - Max IOPS of the compute offering.
+- `min_iops` (Optional) - Min IOPS of the compute offering.
+
+## Attributes Reference
+
+In addition to the arguments above, the following attributes are exported:
+
+- `id` - The ID of the service offering.
+
+## Import
+
+Service offerings can be imported using the ID:
+
+```sh
+terraform import cloudstack_service_offering_unconstrained.example <id>
+```

Reply via email to