Skip to content

Commit

Permalink
Add resource routeros_ipv6_neighbor_discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
jlpedrosa committed Feb 18, 2024
1 parent bb2fa1f commit 3f9a487
Show file tree
Hide file tree
Showing 7 changed files with 308 additions and 2 deletions.
3 changes: 3 additions & 0 deletions examples/resources/routeros_ipv6_neighbor_discovery/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#The ID can be found via API or the terminal
#The command for the terminal is -> :put [/ipv6/nd get [print show-ids]]
terraform import routeros_ipv6_neighbor_discovery.ndether1 "*0"
19 changes: 19 additions & 0 deletions examples/resources/routeros_ipv6_neighbor_discovery/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

resource "routeros_ipv6_neighbor_discovery" "test" {
interface = "ether1"
hop_limit = 33
advertise_dns = false
advertise_mac_address = true
disabled = false
managed_address_configuration = true
mtu = 9000
other_configuration = true
pref64_prefixes = []
ra_delay = "3s"
ra_interval = "3m20s-10m"
ra_lifetime = "30m"
ra_preference = "high"
reachable_time = "10m"
retransmit_interval = "12m"
}
`
20 changes: 18 additions & 2 deletions routeros/mikrotik_serialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ func loadSkipFields(s string) (m map[string]struct{}) {
return
}

func loadDropByValue(s string) (m map[string]struct{}) {
m = make(map[string]struct{})
for _, value := range strings.Split(s, ",") {
m[value] = struct{}{}
}
return m
}

// ListToString Convert List and Set to a delimited string.
func ListToString(v any) (res string) {
for i, elem := range v.([]interface{}) {
Expand Down Expand Up @@ -139,7 +147,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, MetaSetUnsetFields:
case MetaTransformSet, MetaSkipFields, MetaSetUnsetFields, MetaDropByValue:
continue
default:
meta.Meta[terraformSnakeName] = terraformMetadata.Default.(string)
Expand Down Expand Up @@ -290,7 +298,7 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch
var diags diag.Diagnostics
var err error
var transformSet map[string]string
var setUnsetFields, skipFields map[string]struct{}
var setUnsetFields, skipFields, dropByValue map[string]struct{}

// {"channel": "channel.config", "mikrotik-field-name": "schema-field-name"}
if ts, ok := s[MetaTransformSet]; ok {
Expand All @@ -305,6 +313,10 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch
skipFields = loadSkipFields(sf.Default.(string))
}

if dbv, ok := s[MetaDropByValue]; ok {
dropByValue = loadDropByValue(dbv.Default.(string))
}

// TypeMap,TypeSet initialization information storage.
var maps = make(map[string]map[string]interface{})
var nestedLists = make(map[string]map[string]interface{})
Expand All @@ -324,6 +336,10 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch
continue
}

if _, ok := dropByValue[mikrotikValue]; ok {
continue
}

// Mikrotik fields transformation: "channel" ---> "channel.config".
// For further use in the map.
if transformSet != nil {
Expand Down
1 change: 1 addition & 0 deletions routeros/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func Provider() *schema.Provider {
"routeros_ipv6_dhcp_client_option": ResourceIPv6DhcpClientOption(),
"routeros_ipv6_firewall_addr_list": ResourceIPv6FirewallAddrList(),
"routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(),
"routeros_ipv6_neighbor_discovery": ResourceIPv6NeighborDiscovery(),
"routeros_ipv6_route": ResourceIPv6Route(),

// Aliases for IP objects to retain compatibility between original and fork
Expand Down
13 changes: 13 additions & 0 deletions routeros/provider_schema_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
MetaTransformSet = "___ts___"
MetaSkipFields = "___skip___"
MetaSetUnsetFields = "___unset___"
MetaDropByValue = "___drop_val___"
)

const (
Expand Down Expand Up @@ -79,6 +80,18 @@ func PropId(t IdType) *schema.Schema {
}
}

func PropDropByValue(values ...string) *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: strings.Join(values, ","),
Description: "<em>A list of values when generated by RouterOs will be dropped, useful to default values as 'unspecified' for null</em>",
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return true
},
}
}

// PropTransformSet
func PropTransformSet(s string) *schema.Schema {
return &schema.Schema{
Expand Down
153 changes: 153 additions & 0 deletions routeros/resource_ipv6_neighbor_discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package routeros

import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

/*
[
{
".id": "*3",
"advertise-dns": "false",
"advertise-mac-address": "true",
"default": "false",
"disabled": "false",
"dns": "",
"hop-limit": "unspecified",
"interface": "vlan-wifi-XXX",
"invalid": "false",
"managed-address-configuration": "true",
"mtu": "unspecified",
"other-configuration": "true",
"pref64": "",
"ra-delay": "3s",
"ra-interval": "3m20s-10m",
"ra-lifetime": "30m",
"ra-preference": "high",
"reachable-time": "unspecified",
"retransmit-interval": "unspecified"
}
]
*/

// ResourceIPv6NeighborDiscovery https://help.mikrotik.com/docs/display/ROS/IPv6+Neighbor+Discovery
func ResourceIPv6NeighborDiscovery() *schema.Resource {
resSchema := map[string]*schema.Schema{
MetaResourcePath: PropResourcePath("/ipv6/nd"),
MetaId: PropId(Id),
MetaDropByValue: PropDropByValue("unspecified"),
"advertise_dns": {
Type: schema.TypeBool,
Optional: true,
Description: "Option to redistribute DNS server information using RADVD. You will need a running client-side software with Router Advertisement DNS support to take advantage of the advertised DNS information.",
Default: true,
},
"advertise_mac_address": {
Type: schema.TypeBool,
Optional: true,
Description: "When set, the link-layer address of the outgoing interface is included in the RA.",
Default: true,
},
KeyComment: PropCommentRw,
"dns_servers": {
Type: schema.TypeString,
Optional: true,
Description: "Specify a single IPv6 address or list of addresses that will be provided to hosts for DNS server configuration.",
ValidateFunc: validation.IsCIDR,
},
KeyDisabled: PropDisabledRw,
"hop_limit": {
Type: schema.TypeInt,
Optional: true,
Description: "The default value that should be placed in the Hop Count field of the IP header for outgoing (unicast) IP packets.",
ValidateFunc: validation.IntBetween(0, 255),
},
"interface": {
Type: schema.TypeString,
Required: true,
Description: "The interface on which to run neighbor discovery." +
"all - run ND on all running interfaces.",
},
"managed_address_configuration": {
Type: schema.TypeBool,
Optional: true,
Description: "Name of the IPv6 pool in which received IPv6 prefix will be added",
},
"mtu": {
Type: schema.TypeInt,
Optional: true,
Description: "The flag indicates whether hosts should use stateful autoconfiguration (DHCPv6) to obtain addresses",
ValidateFunc: validation.IntBetween(0, 4294967295),
},
"other_configuration": {
Type: schema.TypeBool,
Optional: true,
Description: "The flag indicates whether hosts should use stateful autoconfiguration to obtain additional information (excluding addresses).",
},
"pref64_prefixes": {
Type: schema.TypeList,
Optional: true,
Description: "Specify IPv6 prefix or list of prefixes within /32, /40. /48, /56, /64, or /96 subnet that will be provided to hosts as NAT64 prefixes.",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.IsCIDR,
},
DiffSuppressFunc: AlwaysPresentNotUserProvided,
},
"ra_delay": {
Type: schema.TypeString,
Optional: true,
Description: "The minimum time allowed between sending multicast router advertisements from the interface.",
Default: "3s",
},
"ra_interval": {
Type: schema.TypeString,
Optional: true,
Description: "The min-max interval allowed between sending unsolicited multicast router advertisements from the interface.",
Default: "3m20s-10m",
},
"ra_preference": {
Type: schema.TypeString,
Optional: true,
Description: "Specify the router preference that is communicated to IPv6 hosts through router advertisements." +
"The preference value in the router advertisements enables IPv6 hosts to select a default router to reach a remote destination",
Default: "medium",
ValidateFunc: validation.StringInSlice([]string{"low", "medium", "high"}, false),
},
"ra_lifetime": {
Type: schema.TypeString,
Optional: true,
Description: "Specify the router preference that is communicated to IPv6 hosts through router advertisements." +
"The preference value in the router advertisements enables IPv6 hosts to select a default router to reach a remote destination",
Default: "30m",
},
"reachable_time": {
Type: schema.TypeString,
Optional: true,
Description: "Specify the router preference that is communicated to IPv6 hosts through router advertisements." +
"The preference value in the router advertisements enables IPv6 hosts to select a default router to reach a remote destination",
DiffSuppressFunc: AlwaysPresentNotUserProvided,
},
"retransmit_interval": {
Type: schema.TypeString,
Optional: true,
Description: "The time between retransmitted Neighbor Solicitation messages." +
"Used by address resolution and the Neighbor Unreachability Detection algorithm (see Sections 7.2 and 7.3 of RFC 2461)",
DiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool {
return true
},
},
}
return &schema.Resource{
CreateContext: DefaultCreate(resSchema),
ReadContext: DefaultRead(resSchema),
UpdateContext: DefaultUpdate(resSchema),
DeleteContext: DefaultDelete(resSchema),
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: resSchema,
}
}
101 changes: 101 additions & 0 deletions routeros/resource_ipv6_neighbor_discovery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package routeros

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

const testIPv6NeighborDiscoveryAddress = "routeros_ipv6_neighbor_discovery.test"

func TestAccIPv6FNeighborDiscoveryTest_full(t *testing.T) {
for _, name := range testNames {
t.Run(name, func(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testSetTransportEnv(t, name)
},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testCheckResourceDestroy("/ipv6/nd", "routeros_ipv6_neighbor_discovery"),
Steps: []resource.TestStep{
{
Config: testAccFullIPv6NeighborDiscoveryConfig(),
Check: resource.ComposeTestCheckFunc(
testResourcePrimaryInstanceId(testIPv6NeighborDiscoveryAddress),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "interface", "ether1"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "hop_limit", "33"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "advertise_dns", "false"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "advertise_mac_address", "true"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "disabled", "false"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "managed_address_configuration", "true"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "mtu", "9000"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "other_configuration", "true"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "ra_delay", "3s"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "ra_lifetime", "3m20s-10m"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "ra_preference", "high"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "reachable_time", "10m"),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "retransmit_interval", "12m"),
),
},
},
})
})
}
}

func TestAccIPv6FNeighborDiscoveryTest_basic(t *testing.T) {
for _, name := range testNames {
t.Run(name, func(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testSetTransportEnv(t, name)
},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testCheckResourceDestroy("/ipv6/nd", "routeros_ipv6_neighbor_discovery"),
Steps: []resource.TestStep{
{
Config: testAccSimpleIPv6NeighborDiscoveryConfig(),
Check: resource.ComposeTestCheckFunc(
testResourcePrimaryInstanceId(testIPv6NeighborDiscoveryAddress),
resource.TestCheckResourceAttr(testIPv6NeighborDiscoveryAddress, "interface", "ether1"),
),
},
},
})
})
}
}

func testAccFullIPv6NeighborDiscoveryConfig() string {
return providerConfig + `
resource "routeros_ipv6_neighbor_discovery" "test" {
interface = "ether1"
hop_limit = 33
advertise_dns = false
advertise_mac_address = true
disabled = false
managed_address_configuration = true
mtu = 9000
other_configuration = true
pref64_prefixes = []
ra_delay = "3s"
ra_interval = "3m20s-10m"
ra_lifetime = "30m"
ra_preference = "high"
reachable_time = "10m"
retransmit_interval = "12m"
}
`
}

func testAccSimpleIPv6NeighborDiscoveryConfig() string {
return providerConfig + `
resource "routeros_ipv6_neighbor_discovery" "test" {
interface = "ether1"
}
`
}

0 comments on commit 3f9a487

Please sign in to comment.