// Copyright (c) EZSCALE. // SPDX-License-Identifier: MPL-2.0 package provider import ( "context" "errors" "fmt" "terraform-provider-virtfusion/internal/client" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "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" ) // Ensure provider-defined types fully satisfy framework interfaces. var ( _ resource.Resource = &SelfServiceHourlyGroupProfileResource{} _ resource.ResourceWithConfigure = &SelfServiceHourlyGroupProfileResource{} ) // NewSelfServiceHourlyGroupProfileResource creates a new self-service hourly group profile resource. func NewSelfServiceHourlyGroupProfileResource() resource.Resource { return &SelfServiceHourlyGroupProfileResource{} } // SelfServiceHourlyGroupProfileResource defines the resource implementation. type SelfServiceHourlyGroupProfileResource struct { client *client.Client } // SelfServiceHourlyGroupProfileResourceModel describes the resource data model. type SelfServiceHourlyGroupProfileResourceModel struct { ID types.String `tfsdk:"id"` UserID types.Int64 `tfsdk:"user_id"` GroupID types.Int64 `tfsdk:"group_id"` ProfileID types.Int64 `tfsdk:"profile_id"` } func (r *SelfServiceHourlyGroupProfileResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_self_service_hourly_group_profile" } func (r *SelfServiceHourlyGroupProfileResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: "Manages a self-service hourly group profile assignment in VirtFusion.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ MarkdownDescription: "The composite identifier of the hourly group profile (userId/groupId/profileId).", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "user_id": schema.Int64Attribute{ MarkdownDescription: "The ID of the user.", Required: true, PlanModifiers: []planmodifier.Int64{ int64planmodifier.RequiresReplace(), }, }, "group_id": schema.Int64Attribute{ MarkdownDescription: "The ID of the hypervisor group.", Required: true, PlanModifiers: []planmodifier.Int64{ int64planmodifier.RequiresReplace(), }, }, "profile_id": schema.Int64Attribute{ MarkdownDescription: "The ID of the hourly profile.", Required: true, PlanModifiers: []planmodifier.Int64{ int64planmodifier.RequiresReplace(), }, }, }, } } func (r *SelfServiceHourlyGroupProfileResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { if req.ProviderData == nil { return } c, ok := req.ProviderData.(*client.Client) if !ok { resp.Diagnostics.AddError( "Unexpected Resource Configure Type", fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } r.client = c } func (r *SelfServiceHourlyGroupProfileResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data SelfServiceHourlyGroupProfileResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } profileReq := map[string]int64{ "userId": data.UserID.ValueInt64(), "groupId": data.GroupID.ValueInt64(), "profileId": data.ProfileID.ValueInt64(), } _, err := r.client.Post(ctx, "/selfService/hourlyGroupProfile", profileReq) if err != nil { resp.Diagnostics.AddError( "Error Creating Hourly Group Profile", fmt.Sprintf("Could not create hourly group profile for user %d: %s", data.UserID.ValueInt64(), err), ) return } // Generate a composite ID. data.ID = types.StringValue(fmt.Sprintf("%d/%d/%d", data.UserID.ValueInt64(), data.GroupID.ValueInt64(), data.ProfileID.ValueInt64())) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (r *SelfServiceHourlyGroupProfileResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data SelfServiceHourlyGroupProfileResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (r *SelfServiceHourlyGroupProfileResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) { // All attributes require replacement — updates are never called. } func (r *SelfServiceHourlyGroupProfileResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var data SelfServiceHourlyGroupProfileResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } apiPath := fmt.Sprintf("/selfService/hourlyGroupProfile/%d/%d/%d", data.UserID.ValueInt64(), data.GroupID.ValueInt64(), data.ProfileID.ValueInt64(), ) _, err := r.client.Delete(ctx, apiPath) if err != nil { var apiErr *client.APIError if errors.As(err, &apiErr) && apiErr.IsNotFound() { return } resp.Diagnostics.AddError( "Error Deleting Hourly Group Profile", fmt.Sprintf("Could not delete hourly group profile for user %d, group %d, profile %d: %s", data.UserID.ValueInt64(), data.GroupID.ValueInt64(), data.ProfileID.ValueInt64(), err, ), ) return } }