From 78b05a2887f6727d619f376da5ac6f35de9cf735 Mon Sep 17 00:00:00 2001 From: Menno Hamburg Date: Tue, 13 Jun 2023 22:27:13 +0200 Subject: [PATCH] Added interface bonding --- .../routeros_interface_bonding/resource.tf | 4 + .../routeros_routing_ospf_area/resource.tf | 8 + .../resource.tf | 3 + .../resource.tf | 12 ++ routeros/provider.go | 1 + routeros/resource_interface_bonding.go | 137 ++++++++++++++++++ routeros/resource_interface_bonding_test.go | 66 +++++++++ 7 files changed, 231 insertions(+) create mode 100644 examples/resources/routeros_interface_bonding/resource.tf create mode 100644 examples/resources/routeros_routing_ospf_area/resource.tf create mode 100644 examples/resources/routeros_routing_ospf_instance/resource.tf create mode 100644 examples/resources/routeros_routing_ospf_interface_template/resource.tf create mode 100644 routeros/resource_interface_bonding.go create mode 100644 routeros/resource_interface_bonding_test.go diff --git a/examples/resources/routeros_interface_bonding/resource.tf b/examples/resources/routeros_interface_bonding/resource.tf new file mode 100644 index 00000000..f8be0a52 --- /dev/null +++ b/examples/resources/routeros_interface_bonding/resource.tf @@ -0,0 +1,4 @@ +resource "routeros_interface_bonding" "test_bonding" { + name = "test_bonding" + slaves = "ether1" +} \ No newline at end of file diff --git a/examples/resources/routeros_routing_ospf_area/resource.tf b/examples/resources/routeros_routing_ospf_area/resource.tf new file mode 100644 index 00000000..09dff98b --- /dev/null +++ b/examples/resources/routeros_routing_ospf_area/resource.tf @@ -0,0 +1,8 @@ +resource "routeros_routing_ospf_instance" "test_routing_ospf_instance" { + name = "test_routing_ospf_instance" +} + +resource "routeros_routing_ospf_area" "test_routing_ospf_area" { + name = "test_routing_ospf_area" + instance = routeros_routing_ospf_instance.test_routing_ospf_instance.name +} \ No newline at end of file diff --git a/examples/resources/routeros_routing_ospf_instance/resource.tf b/examples/resources/routeros_routing_ospf_instance/resource.tf new file mode 100644 index 00000000..b0fee806 --- /dev/null +++ b/examples/resources/routeros_routing_ospf_instance/resource.tf @@ -0,0 +1,3 @@ +resource "routeros_routing_ospf_instance" "test_routing_ospf_instance" { + name = "test_routing_ospf_instance" +} \ No newline at end of file diff --git a/examples/resources/routeros_routing_ospf_interface_template/resource.tf b/examples/resources/routeros_routing_ospf_interface_template/resource.tf new file mode 100644 index 00000000..b3687fe4 --- /dev/null +++ b/examples/resources/routeros_routing_ospf_interface_template/resource.tf @@ -0,0 +1,12 @@ +resource "routeros_routing_ospf_instance" "test_routing_ospf_instance" { + name = "test_routing_ospf_instance" +} + +resource "routeros_routing_ospf_area" "test_routing_ospf_area" { + name = "test_routing_ospf_area" + instance = routeros_routing_ospf_instance.test_routing_ospf_instance.name +} + +resource "routeros_routing_ospf_interface_template" "test_routing_ospf_interface_template" { + area = routeros_routing_ospf_area.test_routing_ospf_area.name +} \ No newline at end of file diff --git a/routeros/provider.go b/routeros/provider.go index 0433cf1d..88d0699f 100644 --- a/routeros/provider.go +++ b/routeros/provider.go @@ -106,6 +106,7 @@ func Provider() *schema.Provider { "routeros_interface_list": ResourceInterfaceList(), "routeros_interface_list_member": ResourceInterfaceListMember(), "routeros_interface_ovpn_server": ResourceInterfaceOpenVPNServer(), + "routeros_interface_bonding": ResourceInterfaceBonding(), // Aliases for interface objects to retain compatibility between original and fork "routeros_bridge": ResourceInterfaceBridge(), diff --git a/routeros/resource_interface_bonding.go b/routeros/resource_interface_bonding.go new file mode 100644 index 00000000..2bc529d7 --- /dev/null +++ b/routeros/resource_interface_bonding.go @@ -0,0 +1,137 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +// ResourceInterfaceBonding https://wiki.mikrotik.com/wiki/Manual:Interface/Bonding +func ResourceInterfaceBonding() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/interface/bonding"), + MetaId: PropId(Name), + + KeyComment: PropCommentRw, + KeyDisabled: PropDisabledRw, + KeyName: PropNameForceNewRw, + KeyArp: PropArpRw, + "mtu": { + Type: schema.TypeString, + Default: "1500", + Optional: true, + Description: "Maximum Transmit Unit in bytes. Must be smaller or equal to the smallest L2MTU value of a bonding slave.", + }, + "arp_interval": { + Type: schema.TypeString, + Optional: true, + // Default: "100ms", + Computed: true, + Description: "Time in milliseconds which defines how often to monitor ARP requests", + DiffSuppressFunc: TimeEquall, + }, + "arp_ip_targets": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "IP target address which will be monitored if link-monitoring is set to " + + "arp. You can specify multiple IP addresses.", + }, + "down_delay": { + Type: schema.TypeString, + Optional: true, + // Default: "0s", + Computed: true, + Description: "If a link failure has been detected, bonding interface is disabled for " + + "down-delay time. Value should be a multiple of mii-interval, otherwise it will be rounded down to the nearest value.", + DiffSuppressFunc: TimeEquall, + }, + "forced_mac_address": { + Type: schema.TypeString, + Optional: true, + Description: "By default, bonding interface will use MAC address of the first selected slave interface. " + + "This property allows to configure static MAC address for the bond interface.", + }, + "lacp_rate": { + Type: schema.TypeString, + Optional: true, + // Default: "2m5s", + Computed: true, + Description: "Link Aggregation Control Protocol rate specifies how often to exchange with LACPDUs between bonding peer. " + + "Used to determine whether link is up or other changes have occurred in the network. LACP tries to adapt to these changes providing failover.", + DiffSuppressFunc: TimeEquall, + }, + "link_monitoring": { + Type: schema.TypeString, + Default: "mii", + Optional: true, + Description: "Method to use for monitoring the link (whether it is up or down)", + ValidateFunc: validation.StringInSlice([]string{"arp", "mii", "none"}, true), + }, + "min_links": { + Type: schema.TypeInt, + //Default: 0, + Optional: true, + Description: "How many active slave links needed for bonding to become active", + ValidateFunc: validation.IntBetween(0, 4294967295), + }, + "mii_interval": { + Type: schema.TypeString, + Optional: true, + // Default: "100ms", + Computed: true, + Description: "How often to monitor the link for failures (parameter used only if link-monitoring is mii)", + DiffSuppressFunc: TimeEquall, + }, + "mode": { + Type: schema.TypeString, + Default: "balance-rr", + Optional: true, + Description: "Specifies one of the bonding policies", + ValidateFunc: validation.StringInSlice([]string{"802.3ad", "active-backup", "balance-alb", + "balance-rr", "balance-tlb", "balance-xor", "broadcast"}, true), + }, + "primary": { + Type: schema.TypeString, + Optional: true, + Default: "none", + Description: "Controls the primary interface between active slave ports, works only for active-backup, balance-tlb and balance-alb modes.", + }, + "slaves": { + Type: schema.TypeString, + Required: true, + //Default: "none", + Description: "At least two ethernet-like interfaces separated by a comma, which will be used for bonding", + }, + "up_delay": { + Type: schema.TypeString, + Optional: true, + // Default: "0s", + Computed: true, + Description: "If a link has been brought up, bonding interface is disabled for up-delay time and after this " + + "time it is enabled. Value should be a multiple of mii-interval, otherwise it will be rounded down to the nearest value.", + DiffSuppressFunc: TimeEquall, + }, + "transmit_hash_policy": { + Type: schema.TypeString, + Optional: true, + Default: "layer-2", + Description: "Selects the transmit hash policy to use for slave selection in balance-xor and 802.3ad modes", + ValidateFunc: validation.StringInSlice([]string{"layer-2", "layer-2-and-3", "layer-3-and-4"}, true), + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_interface_bonding_test.go b/routeros/resource_interface_bonding_test.go new file mode 100644 index 00000000..af8b6076 --- /dev/null +++ b/routeros/resource_interface_bonding_test.go @@ -0,0 +1,66 @@ +package routeros + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +const testInterfaceBondingInstance = "routeros_interface_bonding.test_bonding" + +func TestAccInterfaceBondingTest_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("/interface/bonding", "routeros_interface_bonding"), + Steps: []resource.TestStep{ + { + Config: testAccInterfaceBondingConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckInterfaceBondingExists(testInterfaceBondingInstance), + resource.TestCheckResourceAttr(testInterfaceBondingInstance, "name", "test_bonding"), + ), + }, + }, + }) + + }) + } +} + +func testAccCheckInterfaceBondingExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("not found: %s", name) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no id is set") + } + + return nil + } +} + +func testAccInterfaceBondingConfig() string { + return ` + +provider "routeros" { + insecure = true +} + +resource "routeros_interface_bonding" "test_bonding" { + name = "test_bonding" + slaves = "ether1" +} + +` +}