terraform-routeros / terraform-provider-routeros

Terraform Provider for Mikrotik RouterOS
Mozilla Public License 2.0
187 stars 54 forks source link

Pointers for new resources #161

Closed durandguru closed 9 months ago

durandguru commented 1 year ago

I'm playing around with creating some resources I am missing in the current provider. I have found out how to create locally a new resource and build the provider to test. Some things I can copy from existing resources but are there some pointers to get started?

vaerh commented 1 year ago

I can try to describe the steps I take to create a new resource and some of the pitfalls. But creating some resources (as shown by routeros_dns_record) can be time consuming, as not everything is immediately obvious. If my description is not needed, then I would open a certain number of requests for improvements and work on them.

durandguru commented 1 year ago

I want to kind of learn it and help and not do a request for everything I need, I can deduce some things from the existing files. I can always play around and if it is too difficult create an feature request.

vaerh commented 1 year ago

Ok! I will do a general review here. At the moment, the provider is designed in such a way that to add a new resource, you just need to correctly describe its schema. So far I have implemented two types of resources:

  1. Ordinary dynamic entities that can be deleted.
  2. System resources that cannot be deleted.

Depending on this, in the schema.Resource of each resource, its context functions are selected (DefaultCreate, DefaultRead, DefaultValidateUpdate, DefaultSystemDelete ... see resource_default_actions.go) The difference between system resources and others is that there is no process of deleting them. When DeleteContext is called, the internal resource identifier is simply deleted d.SetId("") (see SystemResourceDelete in capsman branch). Within each scheme, two metadata fields must be specified, one of which is used for delivering the path of the Miktrotik resource to the functional handler, the second field is used to indicate how the resource can be accessed (by a unique resource name or sequence number). The scheme is used by terraform to process scripts, and in the case of a provider, to automate the process of converting data between Mikrotik and Terraform.

image

The transport is abstracted from the resource context through the СRUD model, which describes the data format for various clients. The most interesting resource data operations occur in the serialization module (mikrotik_serialize.go). It describes the procedures for determining the type of the processed field from the resource schema (String, Int, List, etc.) and converting between Mikrotik and TF formats. Along with the addition of CAPsMAN, the serializer will be redesigned a bit and new types will be added.

Schema

The fields of each resource are arranged in alphabetical order for ease of searching. With the type of resource fields, everything is more or less clear, but I want to draw your attention to the fact that when using the List type, it is necessary that the values of the TF scenario attribute be arranged in a certain sequence (most often alphabetically), because otherwise we will have a TF plan error: request

resource {
  field = [1, 5, 3]   ===> {"field":"1,5,3"}
}

response

{"field":"1,3,5"}

I plan to implement the Set type which does not have this drawback.

There is one more thing with Computed fields, this property should be enabled if Mikrotik returns some values without our request. To make life easier, there are a number of helpers that are located in the file of the same name. For example, when working with fields that accept time intervals, you should use DiffSuppressFunc: TimeEquall, since Mikrotik will turn the value 315 into 5m15s.

To get the primary schema values, I use the "</> RESTED" extension for Firefox. And here you can find my working settings for VSCode. Snippets: Ctrl+C "control-channel-width", press tfs + Enter

"control_channel_width": {
    Type:        schema.TypeString,
    Optional:    true,
    Description: "",
},

Ctrl+C "40mhz-turbo | 20mhz | 10mhz | 5mhz", press tfsis + Enter

       ValidateFunc: validation.StringInSlice([]string{"40mhz-turbo", "20mhz", "10mhz", "5mhz"}, false),
vaerh commented 1 year ago

@durandguru https://gist.github.com/vaerh/b4e3e6735396be637a018131c43a0d5c