Skip to content

service offering. sdk framework rewrite#138

Merged
kiranchavala merged 11 commits into
apache:mainfrom
poddm:offerings
Sep 16, 2025
Merged

service offering. sdk framework rewrite#138
kiranchavala merged 11 commits into
apache:mainfrom
poddm:offerings

Conversation

@poddm

@poddm poddm commented Oct 21, 2024

Copy link
Copy Markdown
Contributor

Enhanced the following resources to support the full api spec.

  • cloudstack_service_offering_constrained
  • cloudstack_service_offering_unconstrained
  • cloudstack_service_offering_fixed

I split the service offering API up into multiple resources to make it a bit clearer of the different qos types

@CodeBleu

Copy link
Copy Markdown
Contributor

@poddm Can you add the updated docs to this PR as well? I believe you had docs on the other PR you closed, but there doesn't appear to be updated docs for this.

I have pulled down your branch to test, and am still having issues with needing to specify the domain or domainid.

I get the following error:

│ Error: Error creating service offering
│
│   with cloudstack_service_offering_fixed.standard_offering["8-8"],
│   on service_offerings.tf line 21, in resource "cloudstack_service_offering_fixed" "standard_offering":
│   21: resource "cloudstack_service_offering_fixed" "standard_offering" {
│
│ Could not create fixed offering, unexpected error: CloudStack API error 431 (CSExceptionErrorCode: 9999): Unable to execute API command createserviceoffering due to invalid value. Invalid parameter domainid value="79151a13-70ff-4ddc-918e-8d8deab2c289" due to incorrect
│ long value format, or entity does not exist or due to incorrect parameter annotation for the field in api cmd class.

I'm using it like this:

resource "cloudstack_service_offering_fixed" "standard_offering" {
  for_each = local.cpu_ram_map

  name         = "ACE-${each.value.cpu}C${each.value.cpu}-${each.value.ram}R${each.value.ram}-S"
  domain_ids  = [local.domain_id]
  display_text = "ACE-${each.value.cpu}C${each.value.cpu}-${each.value.ram}R${each.value.ram}-S"
  cpu_number   = each.value.cpu
  cpu_speed    = var.standard_cpu_speed
  host_tags    = "standard"
  storage_tags = "standard_storage"
  memory       = each.value.ram * 1024 # Convert GB to MB
  offer_ha     = false
}

my locals

locals {
  cpus = [1, 2, 4, 8, 16, 32, 64]
  rams = [1, 2, 4, 8, 24, 32, 40, 48, 56, 64, 128]

  cpu_ram_combinations = flatten([
    for cpu in local.cpus : [
      for ram in local.rams : {
        cpu = cpu
        ram = ram
      }
    ]
  ])
  # Create a map for for_each
  cpu_ram_map = {
    for combination in local.cpu_ram_combinations :
    "${combination.cpu}-${combination.ram}" => combination
  }
  domain_id = "79151a13-70ff-4ddc-918e-8d8deab2c289"
}

@CodeBleu CodeBleu added this to the v0.6.0 milestone Oct 22, 2024
@poddm poddm changed the title sdk framework rewrite service offering. sdk framework rewrite Oct 24, 2024
@poddm

poddm commented Oct 25, 2024

Copy link
Copy Markdown
Contributor Author

@CodeBleu , I fixed the domain ids issue. Try now.

Also, regarding the documentation. I was looking at using the generator but it might be better to scope all that work to its own PR. https://github.com/hashicorp/terraform-plugin-docs

@CodeBleu

CodeBleu commented Oct 25, 2024

Copy link
Copy Markdown
Contributor

@CodeBleu , I fixed the domain ids issue. Try now.

Also, regarding the documentation. I was looking at using the generator but it might be better to scope all that work to its own PR. https://github.com/hashicorp/terraform-plugin-docs

@poddm Thanks!!
I was able to successfully add offering with specifying the UUID for domain_ids in an list, but I have a couple of questions.

  1. Can this also be added with putting the name "ACE" or "/ROOT/ACE" and it automatically get the correct UUID?
  2. I need to specify the storage_type as well, but I need to be able to do this without having to specify a disk_offering Is this feasable? Right now without specifying the disk_offering it defaults to shared, and I'd like to be able to change this to local without having to specify a full disk_offering.

I just did a disk_offering and it applied, however it still shows shared instead of local like I have selected.

-/+ resource "cloudstack_service_offering_fixed" "standard_offering" {
      + disk_offering           = {
          + cache_mode               = "none" # forces replacement
          + disk_offering_strictness = false # forces replacement
          + provisioning_type        = "thin" # forces replacement
          + root_disk_size           = 0 # forces replacement
          + storage_type             = "local" # forces replacement
        }
      ~ id                      = "16ee216c-eba1-4dc0-ab96-5bc6513c6616" -> (known after apply)
        name                    = "ACE-8C8-8R8-S"
        # (11 unchanged attributes hidden)
    }

you can see above that the tags is not shown there

{
  "format_version": "1.0",
  "terraform_version": "1.8.1",
  "values": {
    "root_module": {
      "resources": [
        {
          "address": "cloudstack_service_offering_fixed.standard_offering[\"8-8\"]",
          "mode": "managed",
          "type": "cloudstack_service_offering_fixed",
          "name": "standard_offering",
          "index": "8-8",
          "provider_name": "registry.opentofu.org/cloudstack/cloudstack",
          "schema_version": 0,
          "values": {
            "cpu_number": 8,
            "cpu_speed": 2400,
            "deployment_planner": null,
            "disk_hypervisor": null,
            "disk_offering": {
              "cache_mode": "none",
              "disk_offering_strictness": false,
              "provisioning_type": "thin",
              "root_disk_size": 0,
              "storage_type": "local"
            },
            "disk_offering_id": null,
            "disk_storage": null,
            "display_text": "ACE-8C8-8R8-S",
            "domain_ids": [
              "79151a13-70ff-4ddc-918e-8d8deab2c289"
            ],
            "dynamic_scaling_enabled": false,
            "host_tags": "standard",
            "id": "b7945e90-5432-4a87-b8f8-0711576ed75c",
            "is_volatile": false,
            "limit_cpu_use": false,
            "memory": 8192,
            "name": "ACE-8C8-8R8-S",
            "network_rate": null,
            "offer_ha": false,
            "storage_tags": "standard_storage",
            "zone_ids": null
          },
          "sensitive_values": {
            "disk_offering": {},
            "domain_ids": [
              false
            ]
          }
        }
      ]
    }
  }
}

Also, why is storage_tags avail in both at the 'root' level of the resource and also as tags in the disk_offerings?

resource "cloudstack_service_offering_fixed" "standard_offering" {
  for_each = local.cpu_ram_map

  name                     = "ACE-${each.value.cpu}C${each.value.cpu}-${each.value.ram}R${each.value.ram}-S"
  domain_ids               = [local.domain_id]
  display_text             = "ACE-${each.value.cpu}C${each.value.cpu}-${each.value.ram}R${each.value.ram}-S"
  cpu_number               = each.value.cpu
  cpu_speed                = var.standard_cpu_speed
  host_tags                = "standard"
  storage_tags             = "standard_storage"
  memory                   = each.value.ram * 1024 # Convert GB to MB
  offer_ha                 = false
  disk_offering            =  {
    storage_type             = "local"
    provisioning_type        = "thin"
    cache_mode               = "none"
    root_disk_size           = 0
    tags                     = "standard_storage"
    disk_offering_strictness = false
  }
}

image

@poddm

poddm commented Oct 25, 2024

Copy link
Copy Markdown
Contributor Author

Can this also be added with putting the name "ACE" or "/ROOT/ACE" and it automatically get the correct UUID?

I think it would be better to add a data resource for domains. The problem I see with this approach is the resource will never become tainted if it was recreated as the same name. Subsequent resources that may modify or depend on the domain would never detect the newly re/created domain.

ex.

data "cloudstack_domain" "ace" {
    name = "/ROOT/ACE" 
}

resource "cloudstack_service_offering_fixed" "standard_offering" {
  ...
  domain_ids = [data.cloudstack_domain.ace.id]
}

I need to specify the storage_type as well, but I need to be able to do this without having to specify a disk_offering Is this feasable? Right now without specifying the disk_offering it defaults to shared, and I'd like to be able to change this to local without having to specify a full disk_offering.

Let me check. I believe storage_type is only applicable when creating a "compute only disk offering"/disk_offering block.

Also, why is storage_tags avail in both at the 'root' level of the resource and also as tags in the disk_offerings?

Thats a bug. storage tags should be in the disk_offering block

@CodeBleu

Copy link
Copy Markdown
Contributor

@poddm Thank you so much for looking into this.

Once this offering stuff is complete, I still need a way to implement this with the cloudstack_instance resource. If I specify an offering that is constrained/dynamic, I need a way in the cloudstack_instance resource to specify the min/max of the CPU, Mem..etc. Otherwise right now it will just fail saying that it's missing values I'm not able to provide currently, and I can't use it.

Is this something you can fix with a new PR for cloudstack_instance

Comment thread cloudstack/service_offering_constrained_resource.go Outdated
Comment thread cloudstack/service_offering_constrained_resource.go Outdated
Comment thread cloudstack/service_offering_constrained_resource.go Outdated
Comment thread cloudstack/service_offering_constrained_resource.go Outdated
Comment thread cloudstack/service_offering_constrained_resource.go
Comment thread cloudstack/service_offering_constrained_resource.go Outdated
Comment thread cloudstack/service_offering_models.go Outdated
@vishesh92

Copy link
Copy Markdown
Member

@poddm I haven' tested but PR looks good. Left some minor comments.

@poddm

poddm commented Oct 28, 2024

Copy link
Copy Markdown
Contributor Author

@poddm Thank you so much for looking into this.

Once this offering stuff is complete, I still need a way to implement this with the cloudstack_instance resource. If I specify an offering that is constrained/dynamic, I need a way in the cloudstack_instance resource to specify the min/max of the CPU, Mem..etc. Otherwise right now it will just fail saying that it's missing values I'm not able to provide currently, and I can't use it.

Is this something you can fix with a new PR for cloudstack_instance

You can provide the values in the details field.

resource "cloudstack_instance" "this" {
    name = cloud
    display_name  = "cloud details"
    details = {cpuNumber = "4", memory = "2048"}
}

@CodeBleu

CodeBleu commented Oct 28, 2024

Copy link
Copy Markdown
Contributor

@poddm Thank you so much for looking into this.
Once this offering stuff is complete, I still need a way to implement this with the cloudstack_instance resource. If I specify an offering that is constrained/dynamic, I need a way in the cloudstack_instance resource to specify the min/max of the CPU, Mem..etc. Otherwise right now it will just fail saying that it's missing values I'm not able to provide currently, and I can't use it.
Is this something you can fix with a new PR for cloudstack_instance

You can provide the values in the details field.

resource "cloudstack_instance" "this" {
    name = cloud
    display_name  = "cloud details"
    details = {cpuNumber = "4", memory = "2048"}
}

@poddm This is not currently part of the provider. Do you have this in your own branch? If so, Is there a PR for this too?

https://registry.terraform.io/providers/cloudstack/cloudstack/latest/docs/resources/instance

I tried to use what you show anyway, and I get this:

cloudstack_instance.test_box[0]: Creating...
╷
│ Error: Error creating the new instance ace-test-box-0: invalid character '<' looking for beginning of value
│
│   with cloudstack_instance.test_box[0],
│   on main.tf line 46, in resource "cloudstack_instance" "test_box":
│   46: resource "cloudstack_instance" "test_box" {
│
╵

  # cloudstack_instance.test_box[0] will be created
  + resource "cloudstack_instance" "test_box" {
      + details          = {
          + "cpuNumber" = "8"
          + "memory"    = "4096"
        }

@CodeBleu

Copy link
Copy Markdown
Contributor

@poddm Not sure if you saw that I'm still having issues with this or not. Wondering what I need to do?
#138 (comment)

…to null, moved storage_tags field to nested block disk_offering
@poddm

poddm commented Oct 30, 2024

Copy link
Copy Markdown
Contributor Author

@CodeBleu ,

I need to specify the storage_type as well, but I need to be able to do this without having to specify a disk_offering Is this feasable? Right now without specifying the disk_offering it defaults to shared, and I'd like to be able to change this to local without having to specify a full disk_offering.

I fixed the duplicate storage_offering field.

Error: Error creating the new instance ace-test-box-0: invalid character '<' looking for beginning of value

This usually means the management server api returned an html error response and not json like the client library is expecting. I've been using this in 0.4.0 release.

@CodeBleu

Copy link
Copy Markdown
Contributor

@poddm

I fixed the duplicate storage_offering field.

Thanks, I will test this later. My main issue was the storage_type would not change to what I selected. It defaults to shared and I wanted local. This is mentioned above in big comment, so maybe that part got lost.

image

Error: Error creating the new instance ace-test-box-0: invalid character '<' looking for beginning of value

This usually means the management server api returned an html error response and not json like the client library is expecting. I've been using this in 0.4.0 release.

What should I do?

  1. I don't even see the details part of cloudstack_instance even documented.
  2. I went ahead and used what you said to use, but I get that error whenever I add the details part

@CodeBleu

CodeBleu commented Dec 3, 2024

Copy link
Copy Markdown
Contributor

@poddm Was wondering if you could help me with this ☝️ ? I need the storage_type to be what my terraform is set to, but it's not.
#138 (comment)

@poddm

poddm commented Dec 5, 2024

Copy link
Copy Markdown
Contributor Author

@poddm Was wondering if you could help me with this ☝️ ? I need the storage_type to be what my terraform is set to, but it's not. #138 (comment)

fixed.

@CodeBleu

CodeBleu commented Dec 5, 2024

Copy link
Copy Markdown
Contributor

@poddm Was wondering if you could help me with this ☝️ ? I need the storage_type to be what my terraform is set to, but it's not. #138 (comment)

fixed.

@poddm Thanks, I do see that it is showing the storage_type correctly now, however I need the offering to allow 0 as the root_disk_size, so when using the service offering, I can specify whatever disk size I want during deployment.

Could not create fixed offering, unexpected error: CloudStack API error 431 (CSExceptionErrorCode: 4350): The Root disk size is of 0 GB but it must be greater than 0.

@poddm

poddm commented Dec 9, 2024

Copy link
Copy Markdown
Contributor Author

The error is being thrown from cloudstacks API. Try setting this global var to 0.

Custom diskoffering size min (custom.diskoffering.size.min)
Minimum size in GB for custom disk offering.

@CodeBleu

CodeBleu commented Dec 9, 2024

Copy link
Copy Markdown
Contributor

The error is being thrown from cloudstacks API. Try setting this global var to 0.

Custom diskoffering size min (custom.diskoffering.size.min)
Minimum size in GB for custom disk offering.

Not really sure where you are talking about. Before the last change, this wasn't an issue and would create the offering with a root_disk_size of 0, but the local/shared storage_type was not working. When I updated it with that fix...now is when I get the error about 0 for the size

In my resource "cloudstack_service_offering_fixed" "standard_offering" {

I have this:
root_disk_size = 0

Comment thread cloudstack/service_offering_schema.go Outdated
@CodeBleu

CodeBleu commented Jun 10, 2025

Copy link
Copy Markdown
Contributor

@poddm Reviewing this PR again, I believe the only issue remaining ( that I had) was the root_disk_size needing to work if not specified or set to 0 You can see above where I was able to resolve that issue. Is this something you can add to your PR and hopefully we can get this across the line? CC: @vishesh92

Update: I went ahead and committed my suggestion for the root_disk_size fix

@shwstppr shwstppr requested a review from Copilot September 1, 2025 15:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enhances the service offering resources to support the full CloudStack API specification by implementing a complete SDK framework rewrite. The main purpose is to split the service offering API into three distinct resource types based on different Quality of Service (QoS) types, making it clearer for users to understand the different offering configurations.

  • Implements three new service offering resource types: constrained, unconstrained, and fixed
  • Updates the Terraform plugin framework to version 1.12.0 and related dependencies
  • Adds comprehensive test coverage for all three resource types with various disk configurations

Reviewed Changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
go.mod Updates Terraform plugin framework and related dependencies to newer versions
cloudstack/service_offering_util.go Implements common utility functions for CRUD operations across all service offering types
cloudstack/service_offering_schema.go Defines shared schema attributes for service offering resources with nested disk configurations
cloudstack/service_offering_models.go Defines Go struct models for the three service offering types and their nested objects
cloudstack/service_offering_*_resource.go Implements the three service offering resource types with full CRUD operations
cloudstack/service_offering_*_resource_test.go Comprehensive test cases for all three resource types
cloudstack/provider_v6.go Registers the new service offering resources with the provider

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

state.DisplayText = types.StringValue(cs.Displaytext)
}
if cs.Domainid != "" {
state.DomainIds, _ = types.SetValueFrom(ctx, types.StringType, strings.Split(cs.Domainid, ","))

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Error from types.SetValueFrom is ignored. This could lead to silent failures when converting domain IDs. The error should be handled properly or at least logged.

Copilot uses AI. Check for mistakes.
state.Name = types.StringValue(cs.Name)
}
if cs.Zoneid != "" {
state.ZoneIds, _ = types.SetValueFrom(ctx, types.StringType, strings.Split(cs.Zoneid, ","))

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Error from types.SetValueFrom is ignored. This could lead to silent failures when converting zone IDs. The error should be handled properly or at least logged.

Copilot uses AI. Check for mistakes.
p.SetDisplaytext(plan.DisplayText.ValueString())
}
if !plan.DomainIds.IsNull() {
p.SetDomainid(plan.DomainIds.String())

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Using plan.DomainIds.String() directly may not provide the correct format for the API. This will likely result in a string representation like '["id1", "id2"]' instead of a comma-separated list. Consider extracting the actual string values and joining them with commas.

Copilot uses AI. Check for mistakes.
p.SetName(plan.Name.ValueString())
}
if !plan.ZoneIds.IsNull() && len(plan.ZoneIds.Elements()) > 0 {
p.SetZoneid(plan.ZoneIds.String())

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Using plan.ZoneIds.String() directly may not provide the correct format for the API. This will likely result in a string representation like '["id1", "id2"]' instead of a comma-separated list. Consider extracting the actual string values and joining them with commas.

Suggested change
p.SetZoneid(plan.ZoneIds.String())
zoneIds := plan.ZoneIds.Elements()
zoneIdStrs := make([]string, len(zoneIds))
for i, v := range zoneIds {
zoneIdStrs[i] = v.(types.String).ValueString()
}
p.SetZoneid(strings.Join(zoneIdStrs, ","))

Copilot uses AI. Check for mistakes.
state.DisplayText = types.StringValue(cs.Displaytext)
}
if cs.Domainid != "" {
state.DomainIds, _ = types.SetValueFrom(ctx, types.StringType, strings.Split(cs.Domainid, ","))

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Error from types.SetValueFrom is ignored. This could lead to silent failures when converting domain IDs. The error should be handled properly or at least logged.

Copilot uses AI. Check for mistakes.
state.NetworkRate = types.Int32Value(int32(cs.Networkrate))
}
if cs.Zoneid != "" {
state.ZoneIds, _ = types.SetValueFrom(ctx, types.StringType, strings.Split(cs.Zoneid, ","))

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Error from types.SetValueFrom is ignored. This could lead to silent failures when converting zone IDs. The error should be handled properly or at least logged.

Copilot uses AI. Check for mistakes.
p.SetHypervisorsnapshotreserve(int(plan.HypervisorSnapshotReserve.ValueInt32()))
}
if !plan.MaxIops.IsNull() {
p.SetMaxiops(int64(plan.MaxIops.ValueInt64()))

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Redundant type conversion from int64 to int64. The ValueInt64() method already returns int64, so the conversion is unnecessary.

Suggested change
p.SetMaxiops(int64(plan.MaxIops.ValueInt64()))
p.SetMaxiops(plan.MaxIops.ValueInt64())

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +18
// //
// // Licensed to the Apache Software Foundation (ASF) under one
// // or more contributor license agreements. See the NOTICE file
// // distributed with this work for additional information
// // regarding copyright ownership. The ASF licenses this file
// // to you under the Apache License, Version 2.0 (the
// // "License"); you may not use this file except in compliance
// // with the License. You may obtain a copy of the License at
// //
// // http://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing,
// // software distributed under the License is distributed on an
// // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// // KIND, either express or implied. See the License for the
// // specific language governing permissions and limitations
// // under the License.
// //

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

The license header has extra comment slashes. Lines 1-18 have double comment prefixes ('//' instead of a single '//'). This should be consistent with other files in the codebase.

Suggested change
// //
// // 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.
// //
//
// 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.
//

Copilot uses AI. Check for mistakes.

disk_offering = {
storage_type = "local"
sdfjklsdf = "sdfjks"

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

This appears to be test data with a nonsensical attribute name 'sdfjklsdf'. This will likely cause the test to fail as this is not a valid schema attribute. This should be removed or replaced with a valid attribute.

Suggested change
sdfjklsdf = "sdfjks"

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +121
if !plan.CpuSpeed.IsNull() {
params.SetCpuspeed(int(plan.CpuSpeed.ValueInt32()))
}

Copilot AI Sep 1, 2025

Copy link

Choose a reason for hiding this comment

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

Missing validation that CpuSpeed is required. The schema shows this field as required, but there's a null check here. Either remove the null check or make the schema field optional.

Suggested change
if !plan.CpuSpeed.IsNull() {
params.SetCpuspeed(int(plan.CpuSpeed.ValueInt32()))
}
params.SetCpuspeed(int(plan.CpuSpeed.ValueInt32()))

Copilot uses AI. Check for mistakes.

@shwstppr shwstppr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

code lgtm. Didn't test.
@poddm @CodeBleu please see if any of the Copilot recommendations worth implementing

@vishesh92

Copy link
Copy Markdown
Member

@poddm Can you also update the documentation for this?

@kiranchavala kiranchavala left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, tested manually by creating , updating and destroy

Screenshot 2025-09-09 at 4 43 23 PM
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 = []
}


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
}

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
}

 terraform apply 

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # cloudstack_service_offering_constrained.constrained1 will be created
  + resource "cloudstack_service_offering_constrained" "constrained1" {
      + cpu_speed               = 2500
      + deployment_planner      = "UserDispersingPlanner"
      + display_text            = "constrained1"
      + dynamic_scaling_enabled = false
      + host_tags               = "test0101,test0202"
      + id                      = (known after apply)
      + is_volatile             = false
      + limit_cpu_use           = false
      + max_cpu_number          = 10
      + max_memory              = 4096
      + min_cpu_number          = 2
      + min_memory              = 1024
      + name                    = "constrained1"
      + network_rate            = 1024
      + offer_ha                = false
      + zone_ids                = []
    }

  # cloudstack_service_offering_fixed.fixed1 will be created
  + resource "cloudstack_service_offering_fixed" "fixed1" {
      + cpu_number              = 2
      + cpu_speed               = 2500
      + deployment_planner      = "UserDispersingPlanner"
      + display_text            = "fixed1"
      + dynamic_scaling_enabled = false
      + host_tags               = "test0101, test0202"
      + id                      = (known after apply)
      + is_volatile             = false
      + limit_cpu_use           = false
      + memory                  = 2048
      + name                    = "fixed1"
      + network_rate            = 1024
      + offer_ha                = false
    }

  # cloudstack_service_offering_unconstrained.unconstrained1 will be created
  + resource "cloudstack_service_offering_unconstrained" "unconstrained1" {
      + deployment_planner      = "UserDispersingPlanner"
      + display_text            = "unconstrained1"
      + dynamic_scaling_enabled = false
      + host_tags               = "test0101,test0202"
      + id                      = (known after apply)
      + is_volatile             = false
      + limit_cpu_use           = false
      + name                    = "unconstrained1"
      + network_rate            = 1024
      + offer_ha                = false
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

cloudstack_service_offering_unconstrained.unconstrained1: Creating...
cloudstack_service_offering_fixed.fixed1: Creating...
cloudstack_service_offering_constrained.constrained1: Creating...
cloudstack_service_offering_unconstrained.unconstrained1: Creation complete after 0s [id=e88e011a-7b3e-4f8d-b7dd-d309497fa5f3]
cloudstack_service_offering_fixed.fixed1: Creation complete after 0s [id=a0789747-d1ca-4ecb-b99e-110b2c42b126]
cloudstack_service_offering_constrained.constrained1: Creation complete after 0s [id=38323d62-adcc-4858-af26-debdddb067fe]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

@poddm

poddm commented Sep 10, 2025

Copy link
Copy Markdown
Contributor Author

@vishesh92, docs are updated.

@kiranchavala kiranchavala merged commit 63f866b into apache:main Sep 16, 2025
43 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants