Skip to content

service and disk offerings #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cloudstack/provider_v6.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,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 {
Expand Down
265 changes: 265 additions & 0 deletions cloudstack/service_offering_constrained_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
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 = &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{
Required: true,
PlanModifiers: []planmodifier.Int32{
int32planmodifier.RequiresReplace(),
},
},
"max_cpu_number": schema.Int32Attribute{
Required: true,
PlanModifiers: []planmodifier.Int32{
int32planmodifier.RequiresReplace(),
},
},
"max_memory": schema.Int32Attribute{
Required: true,
PlanModifiers: []planmodifier.Int32{
int32planmodifier.RequiresReplace(),
},
},
"min_cpu_number": schema.Int32Attribute{
Required: true,
PlanModifiers: []planmodifier.Int32{
int32planmodifier.RequiresReplace(),
},
},
"min_memory": schema.Int32Attribute{
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(params)
planDiskQosHypervisor.commonCreateParams(params)
planDiskOffering.commonCreateParams(params)
planDiskQosStorage.commonCreateParams(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))
}
// These fields arent returned from list
// max_cpu_number
// max_memory
// min_cpu_number
// min_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 *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)...)
}

// Delete deletes the resource and removes the Terraform state on success.
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
}
}

// Configure adds the provider configured client to the resource.
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"
}
Loading