package provider import ( "context" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "git.veillax.com/Veillax/hhctl/client" ) var ( _ resource.Resource = &domainResource{} _ resource.ResourceWithConfigure = &domainResource{} _ resource.ResourceWithImportState = &domainResource{} ) func NewDomain() resource.Resource { return &domainResource{} } type domainResource struct{ c *client.Client } type domainModel struct { ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` EdgeID types.String `tfsdk:"edge_id"` IP types.String `tfsdk:"ip"` Note types.String `tfsdk:"note"` } func (r *domainResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_domain" } func (r *domainResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { replace := []planmodifier.String{stringplanmodifier.RequiresReplace()} // the API has no domain update opt := func(d string) schema.StringAttribute { return schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString(""), PlanModifiers: replace, Description: d} } resp.Schema = schema.Schema{ Description: "A base domain the organization owns. Web hostnames of ports must sit under one. Changing any field replaces the domain.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}}, "name": schema.StringAttribute{Required: true, PlanModifiers: replace, Description: "Domain, like example.com."}, "edge_id": opt("The edge the domain's DNS points at."), "ip": opt("The edge's public IP the domain points at."), "note": opt("Free-form note."), }, } } func (r *domainResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { r.c = clientFrom(req.ProviderData) } func (r *domainResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan domainModel if resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...); resp.Diagnostics.HasError() { return } d, err := r.c.CreateDomain(client.Domain{Name: plan.Name.ValueString(), EdgeID: plan.EdgeID.ValueString(), IP: plan.IP.ValueString(), Note: plan.Note.ValueString()}) if err != nil { resp.Diagnostics.AddError("Adding domain", err.Error()) return } plan.ID = types.StringValue(d.ID) resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } func (r *domainResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state domainModel if resp.Diagnostics.Append(req.State.Get(ctx, &state)...); resp.Diagnostics.HasError() { return } d, err := r.c.GetDomain(state.ID.ValueString()) if client.IsNotFound(err) { resp.State.RemoveResource(ctx) return } if err != nil { resp.Diagnostics.AddError("Reading domain", err.Error()) return } state.Name, state.EdgeID, state.IP, state.Note = types.StringValue(d.Name), types.StringValue(d.EdgeID), types.StringValue(d.IP), types.StringValue(d.Note) resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } func (r *domainResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Domains can't be updated", "Every field forces a new domain; this is a provider bug.") } func (r *domainResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state domainModel if resp.Diagnostics.Append(req.State.Get(ctx, &state)...); resp.Diagnostics.HasError() { return } if err := r.c.DeleteDomain(state.ID.ValueString()); err != nil && !client.IsNotFound(err) { resp.Diagnostics.AddError("Deleting domain", err.Error()) } } func (r *domainResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { importByID(ctx, req, resp) }