From 0b1276cb60f0aec4765db85e6de7d0405ff781ad Mon Sep 17 00:00:00 2001 From: Maksym Date: Tue, 19 Sep 2023 20:46:18 +0300 Subject: [PATCH] migrate dns_record resource to PluginFramework (#198) --- client/dns.go | 10 +- docs/resources/dns_record.md | 2 +- mikrotik/provider.go | 1 - mikrotik/provider_framework.go | 1 + mikrotik/resource_dns_record.go | 198 ++++++++++++--------------- mikrotik/resource_dns_record_test.go | 9 +- 6 files changed, 96 insertions(+), 125 deletions(-) diff --git a/client/dns.go b/client/dns.go index 021c44fb..ed7a988e 100644 --- a/client/dns.go +++ b/client/dns.go @@ -6,11 +6,11 @@ import ( ) type DnsRecord struct { - Id string `mikrotik:".id"` - Name string `mikrotik:"name"` - Ttl types.MikrotikDuration `mikrotik:"ttl"` - Address string `mikrotik:"address"` - Comment string `mikrotik:"comment"` + Id string `mikrotik:".id" codegen:"id,mikrotikID"` + Name string `mikrotik:"name" codegen:"name,terraformID,required"` + Ttl types.MikrotikDuration `mikrotik:"ttl" codegen:"ttl"` + Address string `mikrotik:"address" codegen:"address,required"` + Comment string `mikrotik:"comment" codegen:"comment"` } func (d *DnsRecord) ActionToCommand(action Action) string { diff --git a/docs/resources/dns_record.md b/docs/resources/dns_record.md index 97e79a82..d71ef8fd 100644 --- a/docs/resources/dns_record.md +++ b/docs/resources/dns_record.md @@ -25,7 +25,7 @@ resource "mikrotik_dns_record" "record" { ### Read-Only -- `id` (String) The ID of this resource. +- `id` (String) Unique ID of this resource. ## Import Import is supported using the following syntax: diff --git a/mikrotik/provider.go b/mikrotik/provider.go index 8510e39e..ccae4075 100644 --- a/mikrotik/provider.go +++ b/mikrotik/provider.go @@ -68,7 +68,6 @@ func Provider(client *mt.Mikrotik) *schema.Provider { "mikrotik_bridge_port": resourceBridgePort(), "mikrotik_bridge_vlan": resourceBridgeVlan(), "mikrotik_dhcp_server_network": resourceDhcpServerNetwork(), - "mikrotik_dns_record": resourceRecord(), "mikrotik_interface_list_member": resourceInterfaceListMember(), "mikrotik_interface_list": resourceInterfaceList(), "mikrotik_firewall_filter_rule": resourceFirewallFilterRule(), diff --git a/mikrotik/provider_framework.go b/mikrotik/provider_framework.go index 751307bd..46d4202c 100644 --- a/mikrotik/provider_framework.go +++ b/mikrotik/provider_framework.go @@ -186,6 +186,7 @@ func (p *ProviderFramework) Resources(ctx context.Context) []func() resource.Res NewBridgeResource, NewDhcpLeaseResource, NewDhcpServerResource, + NewDnsRecordResource, NewInterfaceWireguardPeerResource, NewInterfaceWireguardResource, NewIpAddressResource, diff --git a/mikrotik/resource_dns_record.go b/mikrotik/resource_dns_record.go index d9b4c3ed..2cec2310 100644 --- a/mikrotik/resource_dns_record.go +++ b/mikrotik/resource_dns_record.go @@ -2,147 +2,117 @@ package mikrotik import ( "context" - "log" "github.com/ddelnano/terraform-provider-mikrotik/client" - "github.com/ddelnano/terraform-provider-mikrotik/client/types" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "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/stringplanmodifier" + + tftypes "github.com/hashicorp/terraform-plugin-framework/types" ) -func resourceRecord() *schema.Resource { - return &schema.Resource{ - Description: "Creates a DNS record on the MikroTik device.", +type dnsRecord struct { + client *client.Mikrotik +} - CreateContext: resourceServerCreate, - ReadContext: resourceServerRead, - UpdateContext: resourceServerUpdate, - DeleteContext: resourceServerDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &dnsRecord{} + _ resource.ResourceWithConfigure = &dnsRecord{} + _ resource.ResourceWithImportState = &dnsRecord{} +) + +// NewDnsRecordResource is a helper function to simplify the provider implementation. +func NewDnsRecordResource() resource.Resource { + return &dnsRecord{} +} - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, +func (r *dnsRecord) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*client.Mikrotik) +} + +// Metadata returns the resource type name. +func (r *dnsRecord) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_record" +} + +// Schema defines the schema for the resource. +func (s *dnsRecord) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Creates a DNS record on the MikroTik device.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + Description: "Unique ID of this resource.", + }, + "name": schema.StringAttribute{ Required: true, Description: "The name of the DNS hostname to be created.", }, - "address": { - Type: schema.TypeString, + "ttl": schema.Int64Attribute{ + Optional: true, + Computed: true, + Description: "The ttl of the DNS record.", + }, + "address": schema.StringAttribute{ Required: true, Description: "The A record to be returend from the DNS hostname.", }, - "comment": { - Type: schema.TypeString, - Optional: true, - Description: "The comment text associated with the DNS record.", - }, - "ttl": { - Type: schema.TypeInt, + "comment": schema.StringAttribute{ Optional: true, Computed: true, - Description: "The ttl of the DNS record.", + Description: "The comment text associated with the DNS record.", }, }, } } -func resourceServerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - record := prepareDnsRecord(d) - - c := m.(*client.Mikrotik) - - dnsRecord, err := c.AddDnsRecord(record) - if err != nil { - return diag.FromErr(err) - } - - return recordToData(dnsRecord, d) +// Create creates the resource and sets the initial Terraform state. +func (r *dnsRecord) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var terraformModel dnsRecordModel + var mikrotikModel client.DnsRecord + GenericCreateResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func resourceServerRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - c := m.(*client.Mikrotik) - - record, err := c.FindDnsRecord(d.Id()) - - if client.IsNotFoundError(err) { - d.SetId("") - return nil - } - if err != nil { - return diag.FromErr(err) - } - - return recordToData(record, d) +// Read refreshes the Terraform state with the latest data. +func (r *dnsRecord) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var terraformModel dnsRecordModel + var mikrotikModel client.DnsRecord + GenericReadResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func resourceServerUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - c := m.(*client.Mikrotik) - - currentRecord, err := c.FindDnsRecord(d.Id()) - record := prepareDnsRecord(d) - record.Id = currentRecord.Id - - if err != nil { - return diag.FromErr(err) - } - - log.Printf("[DEBUG] About to update dns record with %v", record) - dnsRecord, err := c.UpdateDnsRecord(record) - if err != nil { - return diag.FromErr(err) - } - - return recordToData(dnsRecord, d) +// Update updates the resource and sets the updated Terraform state on success. +func (r *dnsRecord) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var terraformModel dnsRecordModel + var mikrotikModel client.DnsRecord + GenericUpdateResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func resourceServerDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - name := d.Id() - - c := m.(*client.Mikrotik) - - record, err := c.FindDnsRecord(name) - - if err != nil { - return diag.FromErr(err) - } - err = c.DeleteDnsRecord(record.Id) - - if err != nil { - return diag.FromErr(err) - } - d.SetId("") - return nil +// Delete deletes the resource and removes the Terraform state on success. +func (r *dnsRecord) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var terraformModel dnsRecordModel + var mikrotikModel client.DnsRecord + GenericDeleteResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func recordToData(record *client.DnsRecord, d *schema.ResourceData) diag.Diagnostics { - values := map[string]interface{}{ - "name": record.Name, - "address": record.Address, - "ttl": record.Ttl, - } - - d.SetId(record.Name) - - var diags diag.Diagnostics - - for key, value := range values { - if err := d.Set(key, value); err != nil { - diags = append(diags, diag.Errorf("failed to set %s: %v", key, err)...) - } - } - - return diags +func (r *dnsRecord) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // Retrieve import ID and save to id attribute + resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp) } -func prepareDnsRecord(d *schema.ResourceData) *client.DnsRecord { - dnsRecord := new(client.DnsRecord) - - dnsRecord.Name = d.Get("name").(string) - dnsRecord.Ttl = types.MikrotikDuration(d.Get("ttl").(int)) - dnsRecord.Address = d.Get("address").(string) - dnsRecord.Comment = d.Get("comment").(string) - - return dnsRecord +type dnsRecordModel struct { + Id tftypes.String `tfsdk:"id"` + Name tftypes.String `tfsdk:"name"` + Ttl tftypes.Int64 `tfsdk:"ttl"` + Address tftypes.String `tfsdk:"address"` + Comment tftypes.String `tfsdk:"comment"` } diff --git a/mikrotik/resource_dns_record_test.go b/mikrotik/resource_dns_record_test.go index 9c7c2982..ebac648b 100644 --- a/mikrotik/resource_dns_record_test.go +++ b/mikrotik/resource_dns_record_test.go @@ -142,8 +142,9 @@ func TestAccMikrotikDnsRecord_import(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "id")), }, { - ResourceName: resourceName, ImportState: true, + ResourceName: resourceName, + ImportStateId: dnsName, ImportStateVerify: true, }, }, @@ -184,7 +185,7 @@ func testAccDnsRecordExists(resourceName string) resource.TestCheckFunc { c := client.NewClient(client.GetConfigFromEnv()) - dnsRecord, err := c.FindDnsRecord(rs.Primary.ID) + dnsRecord, err := c.FindDnsRecord(rs.Primary.Attributes["name"]) if err != nil { return fmt.Errorf("Unable to get the dns record with error: %v", err) @@ -194,7 +195,7 @@ func testAccDnsRecordExists(resourceName string) resource.TestCheckFunc { return fmt.Errorf("Unable to get the dns record with name: %s", dnsRecord.Name) } - if dnsRecord.Name == rs.Primary.ID { + if dnsRecord.Name == rs.Primary.Attributes["name"] { return nil } return nil @@ -208,7 +209,7 @@ func testAccCheckMikrotikDnsRecordDestroy(s *terraform.State) error { continue } - dnsRecord, err := c.FindDnsRecord(rs.Primary.ID) + dnsRecord, err := c.FindDnsRecord(rs.Primary.Attributes["name"]) if !client.IsNotFoundError(err) && err != nil { return err