// 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/int64default" "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" ) var ( _ resource.Resource = &ServerIPv4Resource{} _ resource.ResourceWithConfigure = &ServerIPv4Resource{} ) // NewServerIPv4Resource returns a new resource for managing server IPv4 addresses. func NewServerIPv4Resource() resource.Resource { return &ServerIPv4Resource{} } // ServerIPv4Resource defines the resource implementation. type ServerIPv4Resource struct { client *client.Client } // ServerIPv4ResourceModel describes the resource data model. type ServerIPv4ResourceModel struct { ID types.String `tfsdk:"id"` ServerID types.Int64 `tfsdk:"server_id"` Quantity types.Int64 `tfsdk:"quantity"` } func (r *ServerIPv4Resource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_server_ipv4" } func (r *ServerIPv4Resource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: "Adds IPv4 addresses to a VirtFusion server.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ MarkdownDescription: "Resource identifier.", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "server_id": schema.Int64Attribute{ MarkdownDescription: "The ID of the server. Changing this forces a new resource to be created.", Required: true, PlanModifiers: []planmodifier.Int64{ int64planmodifier.RequiresReplace(), }, }, "quantity": schema.Int64Attribute{ MarkdownDescription: "The number of IPv4 addresses to add. Defaults to `1`. Changing this forces a new resource to be created.", Optional: true, Computed: true, Default: int64default.StaticInt64(1), PlanModifiers: []planmodifier.Int64{ int64planmodifier.RequiresReplace(), }, }, }, } } func (r *ServerIPv4Resource) 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.", req.ProviderData), ) return } r.client = c } func (r *ServerIPv4Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data ServerIPv4ResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } serverID := data.ServerID.ValueInt64() quantity := data.Quantity.ValueInt64() var body interface{} if quantity > 1 { body = client.ServerIPv4AddRequest{ Quantity: quantity, } } _, err := r.client.Post(ctx, fmt.Sprintf("/servers/%d/ipv4", serverID), body) if err != nil { resp.Diagnostics.AddError("Error adding IPv4 to server", err.Error()) return } data.ID = types.StringValue(fmt.Sprintf("%d/ipv4/%d", serverID, quantity)) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (r *ServerIPv4Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data ServerIPv4ResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } // No dedicated read endpoint; return stored state as-is. resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (r *ServerIPv4Resource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // All attributes have RequiresReplace, so Update should never be called. resp.Diagnostics.AddError( "Update Not Supported", "All attributes of virtfusion_server_ipv4 require replacement. This function should not be called.", ) } func (r *ServerIPv4Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var data ServerIPv4ResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } serverID := data.ServerID.ValueInt64() _, err := r.client.Delete(ctx, fmt.Sprintf("/servers/%d/ipv4", serverID)) if err != nil { var apiErr *client.APIError if errors.As(err, &apiErr) && apiErr.IsNotFound() { return } resp.Diagnostics.AddError("Error removing IPv4 from server", err.Error()) } }