From 0064e631b01d1c9291d8a6f5c81a180cbb3a1399 Mon Sep 17 00:00:00 2001 From: Maksym Nazarenko Date: Mon, 18 Sep 2023 23:34:37 +0300 Subject: [PATCH] migrate ip_address resource to PluginFramework --- client/ip_addr.go | 12 +- docs/resources/ip_address.md | 4 +- mikrotik/provider.go | 1 - mikrotik/provider_framework.go | 1 + mikrotik/resource_ip_address.go | 197 ++++++++++++++------------------ 5 files changed, 97 insertions(+), 118 deletions(-) diff --git a/client/ip_addr.go b/client/ip_addr.go index ad904b55..7b4b86b8 100644 --- a/client/ip_addr.go +++ b/client/ip_addr.go @@ -5,12 +5,12 @@ import ( ) type IpAddress struct { - Id string `mikrotik:".id"` - Address string `mikrotik:"address"` - Comment string `mikrotik:"comment"` - Disabled bool `mikrotik:"disabled"` - Interface string `mikrotik:"interface"` - Network string `mikrotik:"network"` + Id string `mikrotik:".id" codegen:"id,mikrotikID"` + Address string `mikrotik:"address" codegen:"address,required"` + Comment string `mikrotik:"comment" codegen:"comment"` + Disabled bool `mikrotik:"disabled" codegen:"disabled"` + Interface string `mikrotik:"interface" codegen:"interface,required"` + Network string `mikrotik:"network" codegen:"network,computed"` } var _ Resource = (*IpAddress)(nil) diff --git a/docs/resources/ip_address.md b/docs/resources/ip_address.md index 74080df5..b49320be 100644 --- a/docs/resources/ip_address.md +++ b/docs/resources/ip_address.md @@ -21,11 +21,11 @@ resource "mikrotik_ip_address" "lan" { ### Optional - `comment` (String) The comment for the IP address assignment. -- `disabled` (Boolean) Whether to disable IP address. Default: `false`. +- `disabled` (Boolean) Whether to disable IP address. ### Read-Only -- `id` (String) The ID of this resource. +- `id` (String) Unique ID of this resource. - `network` (String) IP address for the network. ## Import diff --git a/mikrotik/provider.go b/mikrotik/provider.go index 512047c5..8510e39e 100644 --- a/mikrotik/provider.go +++ b/mikrotik/provider.go @@ -71,7 +71,6 @@ func Provider(client *mt.Mikrotik) *schema.Provider { "mikrotik_dns_record": resourceRecord(), "mikrotik_interface_list_member": resourceInterfaceListMember(), "mikrotik_interface_list": resourceInterfaceList(), - "mikrotik_ip_address": resourceIpAddress(), "mikrotik_firewall_filter_rule": resourceFirewallFilterRule(), }, } diff --git a/mikrotik/provider_framework.go b/mikrotik/provider_framework.go index b3939343..751307bd 100644 --- a/mikrotik/provider_framework.go +++ b/mikrotik/provider_framework.go @@ -188,6 +188,7 @@ func (p *ProviderFramework) Resources(ctx context.Context) []func() resource.Res NewDhcpServerResource, NewInterfaceWireguardPeerResource, NewInterfaceWireguardResource, + NewIpAddressResource, NewIpv6AddressResource, NewPoolResource, NewSchedulerResource, diff --git a/mikrotik/resource_ip_address.go b/mikrotik/resource_ip_address.go index 65f12e32..4bcd9917 100644 --- a/mikrotik/resource_ip_address.go +++ b/mikrotik/resource_ip_address.go @@ -4,145 +4,124 @@ import ( "context" "github.com/ddelnano/terraform-provider-mikrotik/client" - "github.com/ddelnano/terraform-provider-mikrotik/mikrotik/internal/utils" - "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 resourceIpAddress() *schema.Resource { - return &schema.Resource{ - Description: "Assigns an IP address to an interface.", +type ipAddress struct { + client *client.Mikrotik +} - CreateContext: resourceIpAddressCreate, - ReadContext: resourceIpAddressRead, - UpdateContext: resourceIpAddressUpdate, - DeleteContext: resourceIpAddressDelete, - Importer: &schema.ResourceImporter{ - StateContext: utils.ImportStateContextUppercaseWrapper(schema.ImportStatePassthroughContext), - }, +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &ipAddress{} + _ resource.ResourceWithConfigure = &ipAddress{} + _ resource.ResourceWithImportState = &ipAddress{} +) + +// NewIpAddressResource is a helper function to simplify the provider implementation. +func NewIpAddressResource() resource.Resource { + return &ipAddress{} +} + +func (r *ipAddress) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*client.Mikrotik) +} - Schema: map[string]*schema.Schema{ - "address": { - Type: schema.TypeString, +// Metadata returns the resource type name. +func (r *ipAddress) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_ip_address" +} + +// Schema defines the schema for the resource. +func (s *ipAddress) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Assigns an IP address to an interface.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + Description: "Unique ID of this resource.", + }, + "address": schema.StringAttribute{ Required: true, Description: "The IP address and netmask of the interface using slash notation.", }, - "comment": { - Type: schema.TypeString, + "comment": schema.StringAttribute{ Optional: true, + Computed: true, Description: "The comment for the IP address assignment.", }, - "disabled": { - Type: schema.TypeBool, + "disabled": schema.BoolAttribute{ Optional: true, - Default: false, + Computed: true, Description: "Whether to disable IP address.", }, - "interface": { - Type: schema.TypeString, + "interface": schema.StringAttribute{ Required: true, Description: "The interface on which the IP address is assigned.", }, - "network": { - Type: schema.TypeString, - Computed: true, + "network": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, Description: "IP address for the network.", }, }, } } -func resourceIpAddressCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - ipAddress := prepareIpAddress(d) - - c := m.(*client.Mikrotik) - - ipaddr, err := c.AddIpAddress(ipAddress) - - if err != nil { - return diag.FromErr(err) - } - - return addrToData(ipaddr, d) +// Create creates the resource and sets the initial Terraform state. +func (r *ipAddress) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var terraformModel ipAddressModel + var mikrotikModel client.IpAddress + GenericCreateResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func resourceIpAddressRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - c := m.(*client.Mikrotik) - - ipaddr, err := c.FindIpAddress(d.Id()) - - // Clear the state if the error represents that the resource no longer exists - if client.IsNotFoundError(err) { - d.SetId("") - return nil - } - - // Make sure all other errors are propagated - if err != nil { - return diag.FromErr(err) - } - - return addrToData(ipaddr, d) +// Read refreshes the Terraform state with the latest data. +func (r *ipAddress) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var terraformModel ipAddressModel + var mikrotikModel client.IpAddress + GenericReadResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func resourceIpAddressUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - c := m.(*client.Mikrotik) - - ipAddress := prepareIpAddress(d) - ipAddress.Id = d.Id() - - ipaddr, err := c.UpdateIpAddress(ipAddress) - - if err != nil { - return diag.FromErr(err) - } - - return addrToData(ipaddr, d) +// Update updates the resource and sets the updated Terraform state on success. +func (r *ipAddress) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var terraformModel ipAddressModel + var mikrotikModel client.IpAddress + GenericUpdateResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func resourceIpAddressDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - c := m.(*client.Mikrotik) - - err := c.DeleteIpAddress(d.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 *ipAddress) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var terraformModel ipAddressModel + var mikrotikModel client.IpAddress + GenericDeleteResource(&terraformModel, &mikrotikModel, r.client)(ctx, req, resp) } -func addrToData(ipaddr *client.IpAddress, d *schema.ResourceData) diag.Diagnostics { - values := map[string]interface{}{ - "address": ipaddr.Address, - "comment": ipaddr.Comment, - "disabled": ipaddr.Disabled, - "interface": ipaddr.Interface, - "network": ipaddr.Network, - } - - d.SetId(ipaddr.Id) - - 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 *ipAddress) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // Retrieve import ID and save to id attribute + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } -func prepareIpAddress(d *schema.ResourceData) *client.IpAddress { - ipaddr := new(client.IpAddress) - - ipaddr.Comment = d.Get("comment").(string) - ipaddr.Address = d.Get("address").(string) - ipaddr.Disabled = d.Get("disabled").(bool) - ipaddr.Interface = d.Get("interface").(string) - ipaddr.Network = d.Get("network").(string) - - return ipaddr +type ipAddressModel struct { + Id tftypes.String `tfsdk:"id"` + Address tftypes.String `tfsdk:"address"` + Comment tftypes.String `tfsdk:"comment"` + Disabled tftypes.Bool `tfsdk:"disabled"` + Interface tftypes.String `tfsdk:"interface"` + Network tftypes.String `tfsdk:"network"` }