From 678c9a4c67d2553e3bc72dc6a29d14d415520fa6 Mon Sep 17 00:00:00 2001 From: vaerh <64400271+vaerh@users.noreply.github.com> Date: Tue, 31 Oct 2023 22:38:58 +0300 Subject: [PATCH] fix(no-release): Some boolean params can't be reset and the provider does not understand the value (#269) Fixes #253 --- routeros/mikrotik_serialize.go | 28 +++++++++++++++++-- routeros/provider_schema_helpers.go | 22 ++++++++++++--- routeros/resource_routing_ospf_area.go | 13 +++++---- ...esource_routing_ospf_interface_template.go | 15 ++++++---- ...ce_routing_ospf_interface_template_test.go | 1 + 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/routeros/mikrotik_serialize.go b/routeros/mikrotik_serialize.go index 8bbb3086..a16ca62c 100644 --- a/routeros/mikrotik_serialize.go +++ b/routeros/mikrotik_serialize.go @@ -115,7 +115,7 @@ func TerraformResourceDataToMikrotik(s map[string]*schema.Schema, d *schema.Reso meta := &MikrotikItemMetadata{} rawConfig := d.GetRawConfig() var transformSet map[string]string - var skipFields map[string]struct{} + var skipFields, setUnsetFields map[string]struct{} // {"channel.config": "channel", "schema-field-name": "mikrotik-field-name"} if ts, ok := s[MetaTransformSet]; ok { @@ -126,6 +126,9 @@ func TerraformResourceDataToMikrotik(s map[string]*schema.Schema, d *schema.Reso if sf, ok := s[MetaSkipFields]; ok { skipFields = loadSkipFields(sf.Default.(string)) } + if suf, ok := s[MetaSetUnsetFields]; ok { + setUnsetFields = loadSkipFields(suf.Default.(string)) + } // Schema map iteration. for terraformSnakeName, terraformMetadata := range s { @@ -136,7 +139,7 @@ func TerraformResourceDataToMikrotik(s map[string]*schema.Schema, d *schema.Reso meta.IdType = IdType(terraformMetadata.Default.(int)) case MetaResourcePath: meta.Path = terraformMetadata.Default.(string) - case MetaTransformSet, MetaSkipFields: + case MetaTransformSet, MetaSkipFields, MetaSetUnsetFields: continue default: meta.Meta[terraformSnakeName] = terraformMetadata.Default.(string) @@ -195,6 +198,17 @@ func TerraformResourceDataToMikrotik(s map[string]*schema.Schema, d *schema.Reso case schema.TypeInt: item[mikrotikKebabName] = strconv.Itoa(value.(int)) case schema.TypeBool: + // true: {...,"interfaces":"ether3","passive":"","priority":"128",...} + // false: {...,"interfaces":"ether3", "priority":"128",...} + if _, ok := setUnsetFields[terraformSnakeName]; ok { + if value.(bool) { + item[mikrotikKebabName] = "" + } else { + // Unset + item["!"+mikrotikKebabName] = "" + } + continue + } item[mikrotikKebabName] = BoolToMikrotikJSON(value.(bool)) // Used to represent an ordered collection of items. case schema.TypeList: @@ -269,7 +283,7 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch var diags diag.Diagnostics var err error var transformSet map[string]string - var skipFields map[string]struct{} + var setUnsetFields, skipFields map[string]struct{} // {"channel": "channel.config", "mikrotik-field-name": "schema-field-name"} if ts, ok := s[MetaTransformSet]; ok { @@ -277,6 +291,9 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch } // "field_first", "field_second", "field_third" + if suf, ok := s[MetaSetUnsetFields]; ok { + setUnsetFields = loadSkipFields(suf.Default.(string)) + } if sf, ok := s[MetaSkipFields]; ok { skipFields = loadSkipFields(sf.Default.(string)) } @@ -352,6 +369,10 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch err = d.Set(terraformSnakeName, i) case schema.TypeBool: + if _, ok := setUnsetFields[terraformSnakeName]; ok { + err = d.Set(terraformSnakeName, true) + break + } err = d.Set(terraformSnakeName, BoolFromMikrotikJSON(mikrotikValue)) case schema.TypeList, schema.TypeSet: @@ -544,6 +565,7 @@ func MikrotikResourceDataToTerraformDatasource(items *[]MikrotikItem, resourceDa propValue = i case schema.TypeBool: + // TODO Add support for set/unset fields? propValue = BoolFromMikrotikJSON(mikrotikValue) case schema.TypeList: diff --git a/routeros/provider_schema_helpers.go b/routeros/provider_schema_helpers.go index 99b69386..ec663102 100644 --- a/routeros/provider_schema_helpers.go +++ b/routeros/provider_schema_helpers.go @@ -14,10 +14,11 @@ import ( // All metadata fields must be present in each resource schema, and the field type must be string. const ( - MetaId = "___id___" - MetaResourcePath = "___path___" - MetaTransformSet = "___ts___" - MetaSkipFields = "___skip___" + MetaId = "___id___" + MetaResourcePath = "___path___" + MetaTransformSet = "___ts___" + MetaSkipFields = "___skip___" + MetaSetUnsetFields = "___unset___" ) const ( @@ -104,6 +105,19 @@ func PropSkipFields(s string) *schema.Schema { } } +// PropSetUnsetFields +func PropSetUnsetFields(s string) *schema.Schema { + return &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: s, + Description: "A set of fields that require setting/unsetting. This is an internal service field, setting a value is not required.", + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, + } +} + // PropName func PropName(description string) *schema.Schema { return &schema.Schema{ diff --git a/routeros/resource_routing_ospf_area.go b/routeros/resource_routing_ospf_area.go index e60ea650..adc267f2 100644 --- a/routeros/resource_routing_ospf_area.go +++ b/routeros/resource_routing_ospf_area.go @@ -21,8 +21,9 @@ import ( // ResourceRoutingOspfArea https://help.mikrotik.com/docs/display/ROS/OSPF func ResourceRoutingOspfArea() *schema.Resource { resSchema := map[string]*schema.Schema{ - MetaResourcePath: PropResourcePath("/routing/ospf/area"), - MetaId: PropId(Id), + MetaResourcePath: PropResourcePath("/routing/ospf/area"), + MetaId: PropId(Id), + MetaSetUnsetFields: PropSetUnsetFields(`"no_summaries"`), "area_id": { Type: schema.TypeString, @@ -45,9 +46,11 @@ func ResourceRoutingOspfArea() *schema.Resource { }, KeyName: PropNameForceNewRw, "no_summaries": { - Type: schema.TypeBool, - Optional: true, - Description: "If set then the area will not flood summary LSAs in the stub area.", + Type: schema.TypeBool, + Optional: true, + Description: "If set then the area will not flood summary LSAs in the stub area. " + + "The correct value of this attribute may not be displayed in Winbox. " + + "Please check the parameters in the console!", }, "nssa_translate": { Type: schema.TypeString, diff --git a/routeros/resource_routing_ospf_interface_template.go b/routeros/resource_routing_ospf_interface_template.go index 2894f701..9ab8edb7 100644 --- a/routeros/resource_routing_ospf_interface_template.go +++ b/routeros/resource_routing_ospf_interface_template.go @@ -34,8 +34,9 @@ import ( // ResourceRoutingOspfInterfaceTemplate https://help.mikrotik.com/docs/display/ROS/OSPF func ResourceRoutingOspfInterfaceTemplate() *schema.Resource { resSchema := map[string]*schema.Schema{ - MetaResourcePath: PropResourcePath("/routing/ospf/interface-template"), - MetaId: PropId(Id), + MetaResourcePath: PropResourcePath("/routing/ospf/interface-template"), + MetaId: PropId(Id), + MetaSetUnsetFields: PropSetUnsetFields(`"passive"`), "area": { Type: schema.TypeString, @@ -107,10 +108,12 @@ func ResourceRoutingOspfInterfaceTemplate() *schema.Resource { Description: "The network prefix associated with the area.", }, "passive": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "If enabled, then do not send or receive OSPF traffic on the matching interfaces", + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If enabled, then do not send or receive OSPF traffic on the matching interfaces. " + + "The correct value of this attribute may not be displayed in Winbox. " + + "Please check the parameters in the console!", }, "prefix_list": { Type: schema.TypeString, diff --git a/routeros/resource_routing_ospf_interface_template_test.go b/routeros/resource_routing_ospf_interface_template_test.go index 53ade75d..ea9078e2 100644 --- a/routeros/resource_routing_ospf_interface_template_test.go +++ b/routeros/resource_routing_ospf_interface_template_test.go @@ -50,6 +50,7 @@ resource "routeros_routing_ospf_area" "test_routing_ospf_area" { resource "routeros_routing_ospf_interface_template" "test_routing_ospf_interface_template" { area = routeros_routing_ospf_area.test_routing_ospf_area.name interfaces = ["ether3"] + passive = true } `