From 33e37b6c259415a1c88028a686102f69d6e8f053 Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Mon, 12 Feb 2024 22:46:31 +0000 Subject: [PATCH 1/4] Add ipv6 dhcp client resource --- docs/resources/interface_ipip.md | 4 +- docs/resources/ipip.md | 4 +- docs/resources/ipv6_dhcp_client.md | 32 +++++++ routeros/provider.go | 3 +- routeros/resource_ipv6_dhcp_client.go | 102 +++++++++++++++++++++ routeros/resource_ipv6_dhcp_client_test.go | 47 ++++++++++ 6 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 docs/resources/ipv6_dhcp_client.md create mode 100644 routeros/resource_ipv6_dhcp_client.go create mode 100644 routeros/resource_ipv6_dhcp_client_test.go diff --git a/docs/resources/interface_ipip.md b/docs/resources/interface_ipip.md index 56b077cc..670028ec 100644 --- a/docs/resources/interface_ipip.md +++ b/docs/resources/interface_ipip.md @@ -15,9 +15,7 @@ resource "routeros_interface_ipip" "ipip_hq" { ### Required -- `name` (String) Changing the name of this resource will force it to be recreated. - > The links of other configuration properties to this resource may be lost! - > Changing the name of the resource outside of a Terraform will result in a loss of control integrity for that resource! +- `name` (String) Name of the ipip interface. ### Optional diff --git a/docs/resources/ipip.md b/docs/resources/ipip.md index 5648dfc3..f405acb7 100644 --- a/docs/resources/ipip.md +++ b/docs/resources/ipip.md @@ -8,9 +8,7 @@ ### Required -- `name` (String) Changing the name of this resource will force it to be recreated. - > The links of other configuration properties to this resource may be lost! - > Changing the name of the resource outside of a Terraform will result in a loss of control integrity for that resource! +- `name` (String) Name of the ipip interface. ### Optional diff --git a/docs/resources/ipv6_dhcp_client.md b/docs/resources/ipv6_dhcp_client.md new file mode 100644 index 00000000..eeca8732 --- /dev/null +++ b/docs/resources/ipv6_dhcp_client.md @@ -0,0 +1,32 @@ +# routeros_ipv6_dhcp_client (Resource) + + + + + +## Schema + +### Required + +- `interface` (String) The interface on which the DHCPv6 client will be running. +- `pool_name` (String) Name of the IPv6 pool in which received IPv6 prefix will be added +- `pool_prefix_length` (Number) Prefix length parameter that will be set for IPv6 pool in which received IPv6 prefix is added. Prefix length must be greater than the length of the received prefix, otherwise, prefix-length will be set to received prefix length + 8 bits. + +### Optional + +- `add-default-route ` (Boolean) Whether to add default IPv6 route after a client connects. +- `comment` (String) +- `disabled` (Boolean) +- `prefix_hint ` (Number) Include a preferred prefix length. +- `script` (String) Run this script on the DHCP-client status change. Available variables:pd-valid - if the prefix is acquired by the client;pd-prefix - the prefix acquired by the client if any;na-valid - if the address is acquired by the client;na-address - the address acquired by the client if any.options - array of received options (only ROSv7) +- `use_peer_dns` (Boolean) Routing table this route belongs to. + +### Read-Only + +- `duid` (String) Auto-generated DUID that is sent to the server.DUID is generated using one of the MAC addresses available on the router. +- `id` (String) The ID of this resource. +- `prefix` (String) Shows received IPv6 prefix from DHCPv6-PD server +- `request` (List of String) To choose if the DHCPv6 request will ask for the address or the IPv6 prefix, or both. +- `status` (String) Shows the status of DHCPv6 Client:stopped - dhcpv6 client is stoppedsearching - sending "solicit" and trying to get "advertise" Shows actual (resolved) gateway and interface that will be used for packet forwarding.requesting - sent "request" waiting for "reply"bound - received "reply". Prefix assigned. renewing - sent "renew", waiting for "reply" rebinding - sent "rebind", waiting for "reply" error - reply was not received in time or some other error occurred. stopping - sent "release" + + diff --git a/routeros/provider.go b/routeros/provider.go index c5b4ece1..a21fb563 100644 --- a/routeros/provider.go +++ b/routeros/provider.go @@ -97,6 +97,7 @@ func Provider() *schema.Provider { "routeros_ip_dns": ResourceDns(), "routeros_ip_dns_record": ResourceDnsRecord(), "routeros_ip_service": ResourceIpService(), + "routeros_ipv6_dhcp_client": ResourceIPv6DhcpClient(), "routeros_ipv6_address": ResourceIPv6Address(), "routeros_ipv6_firewall_addr_list": ResourceIPv6FirewallAddrList(), "routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(), @@ -210,7 +211,7 @@ func Provider() *schema.Provider { // Helpers "routeros_wireguard_keys": ResourceWireguardKeys(), - "routeros_move_items": ResourceMoveItems(), + "routeros_move_items": ResourceMoveItems(), // User Manager "routeros_user_manager_advanced": ResourceUserManagerAdvanced(), diff --git a/routeros/resource_ipv6_dhcp_client.go b/routeros/resource_ipv6_dhcp_client.go new file mode 100644 index 00000000..e305b47a --- /dev/null +++ b/routeros/resource_ipv6_dhcp_client.go @@ -0,0 +1,102 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +// ResourceIPv6DhcpClient https://help.mikrotik.com/docs/display/ROS/DHCP#DHCP-DHCPv6Client +func ResourceIPv6DhcpClient() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/ipv6/dhcp-client/"), + MetaId: PropId(Id), + + "add-default-route ": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to add default IPv6 route after a client connects.", + Default: true, + }, + KeyComment: PropCommentRw, + KeyDisabled: PropDisabledRw, + "duid": { + Type: schema.TypeString, + Computed: true, + Description: "Auto-generated DUID that is sent to the server." + + "DUID is generated using one of the MAC addresses available on the router.", + }, + "interface": { + Type: schema.TypeString, + Required: true, + Description: "The interface on which the DHCPv6 client will be running.", + }, + "pool_name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the IPv6 pool in which received IPv6 prefix will be added", + }, + "pool_prefix_length": { + Type: schema.TypeInt, + Computed: false, + Required: true, + Description: "Prefix length parameter that will be set for IPv6 pool in which received IPv6 prefix is added." + + " Prefix length must be greater than the length of the received prefix, otherwise, prefix-length will be set to received prefix length + 8 bits.", + ValidateFunc: validation.IntBetween(0, 128), + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "Shows received IPv6 prefix from DHCPv6-PD server", + }, + "prefix_hint ": { + Type: schema.TypeInt, + Optional: true, + Description: "Include a preferred prefix length.", + ValidateFunc: validation.IntBetween(0, 128), + }, + "request": { + Type: schema.TypeList, + Computed: true, + Description: "To choose if the DHCPv6 request will ask for the address or the IPv6 prefix, or both.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Shows the status of DHCPv6 Client:" + + "stopped - dhcpv6 client is stopped" + + "searching - sending \"solicit\" and trying to get \"advertise\" Shows actual (resolved) gateway and interface that will be used for packet forwarding.requesting - sent \"request\" waiting for \"reply\"" + + "bound - received \"reply\". Prefix assigned. " + + "renewing - sent \"renew\", waiting for \"reply\" " + + "rebinding - sent \"rebind\", waiting for \"reply\" " + + "error - reply was not received in time or some other error occurred. " + + "stopping - sent \"release\"", + }, + "script": { + Type: schema.TypeString, + Optional: true, + Description: "Run this script on the DHCP-client status change. Available variables:" + + "pd-valid - if the prefix is acquired by the client;" + + "pd-prefix - the prefix acquired by the client if any;" + + "na-valid - if the address is acquired by the client;" + + "na-address - the address acquired by the client if any." + + "options - array of received options (only ROSv7)", + }, + "use_peer_dns": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Routing table this route belongs to.", + }, + } + 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_ipv6_dhcp_client_test.go b/routeros/resource_ipv6_dhcp_client_test.go new file mode 100644 index 00000000..ef6c8879 --- /dev/null +++ b/routeros/resource_ipv6_dhcp_client_test.go @@ -0,0 +1,47 @@ +package routeros + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +const testIPv6DhcpClient = "routeros_ipv6_dhcp_client.client" + +func TestAccIPv6DhcpClient_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/dhcp-client/client", "routeros_ipv6_dhcp_client"), + Steps: []resource.TestStep{ + { + Config: testAccIPv6DhcpClientConfig(), + Check: resource.ComposeTestCheckFunc( + testResourcePrimaryInstanceId(testIPv6DhcpClient), + resource.TestCheckResourceAttr(testIPv6DhcpClient, "interface", "ether1"), + resource.TestCheckResourceAttr(testIPv6DhcpClient, "pool_name", "inet-provider-pool"), + ), + }, + }, + }) + + }) + } +} + +func testAccIPv6DhcpClientConfig() string { + return providerConfig + ` + +resource "routeros_ipv6_dhcp_client" "client" { + interface = "ether1" + request = ["prefix"] + pool_name = "inet-provider-pool" +} + +` +} From 4d184155fc2371567c69a83b47825a1f92391522 Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Mon, 12 Feb 2024 23:00:01 +0000 Subject: [PATCH 2/4] Add example --- docs/resources/ipv6_dhcp_client.md | 22 ++++++++++++++--- .../routeros_ipv6_dhcp_client/import.sh | 3 +++ .../routeros_ipv6_dhcp_client/resource.tf | 8 +++++++ routeros/resource_ipv6_dhcp_client.go | 24 ++++++++++++++++++- 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 examples/resources/routeros_ipv6_dhcp_client/import.sh create mode 100644 examples/resources/routeros_ipv6_dhcp_client/resource.tf diff --git a/docs/resources/ipv6_dhcp_client.md b/docs/resources/ipv6_dhcp_client.md index eeca8732..ef12f7c4 100644 --- a/docs/resources/ipv6_dhcp_client.md +++ b/docs/resources/ipv6_dhcp_client.md @@ -1,7 +1,17 @@ # routeros_ipv6_dhcp_client (Resource) - +## Example Usage +```terraform +resource "routeros_ipv6_dhcp_client" "inet_provider" { + pool_name = "pub-add-pool" + interface = "ether1" + add-default-route = true + pool_prefix_length = 64 + request = ["prefix"] + disabled = false +} +``` ## Schema @@ -14,7 +24,7 @@ ### Optional -- `add-default-route ` (Boolean) Whether to add default IPv6 route after a client connects. +- `add-default-route` (Boolean) Whether to add default IPv6 route after a client connects. - `comment` (String) - `disabled` (Boolean) - `prefix_hint ` (Number) Include a preferred prefix length. @@ -29,4 +39,10 @@ - `request` (List of String) To choose if the DHCPv6 request will ask for the address or the IPv6 prefix, or both. - `status` (String) Shows the status of DHCPv6 Client:stopped - dhcpv6 client is stoppedsearching - sending "solicit" and trying to get "advertise" Shows actual (resolved) gateway and interface that will be used for packet forwarding.requesting - sent "request" waiting for "reply"bound - received "reply". Prefix assigned. renewing - sent "renew", waiting for "reply" rebinding - sent "rebind", waiting for "reply" error - reply was not received in time or some other error occurred. stopping - sent "release" - +## Import +Import is supported using the following syntax: +```shell +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/ipv6/dhcp-client/ get [print show-ids]] +terraform import routeros_ipv6_dhcp_client.inet_provider "*1" +``` diff --git a/examples/resources/routeros_ipv6_dhcp_client/import.sh b/examples/resources/routeros_ipv6_dhcp_client/import.sh new file mode 100644 index 00000000..fa3ff08a --- /dev/null +++ b/examples/resources/routeros_ipv6_dhcp_client/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/ipv6/dhcp-client/ get [print show-ids]] +terraform import routeros_ipv6_dhcp_client.inet_provider "*1" \ No newline at end of file diff --git a/examples/resources/routeros_ipv6_dhcp_client/resource.tf b/examples/resources/routeros_ipv6_dhcp_client/resource.tf new file mode 100644 index 00000000..59aa0f86 --- /dev/null +++ b/examples/resources/routeros_ipv6_dhcp_client/resource.tf @@ -0,0 +1,8 @@ +resource "routeros_ipv6_dhcp_client" "inet_provider" { + pool_name = "pub-add-pool" + interface = "ether1" + add-default-route = true + pool_prefix_length = 64 + request = ["prefix"] + disabled = false +} diff --git a/routeros/resource_ipv6_dhcp_client.go b/routeros/resource_ipv6_dhcp_client.go index e305b47a..9eb24e5b 100644 --- a/routeros/resource_ipv6_dhcp_client.go +++ b/routeros/resource_ipv6_dhcp_client.go @@ -5,13 +5,35 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) +/* +[ + { + ".id": "*1", + "add-default-route": "false", + "dhcp-options": "", + "dhcp-server-v6": "fe80::", + "disabled": "false", + "duid": "0x000003434343443", + "interface": "if-name", + "invalid": "false", + "pool-name": "blacknight-pub-addr", + "pool-prefix-length": "64", + "prefix": "2a01:----:/56, 6d16h56m8s", + "prefix-hint": "::/0", + "request": "prefix", + "status": "bound", + "use-peer-dns": "true" + } +] +*/ + // ResourceIPv6DhcpClient https://help.mikrotik.com/docs/display/ROS/DHCP#DHCP-DHCPv6Client func ResourceIPv6DhcpClient() *schema.Resource { resSchema := map[string]*schema.Schema{ MetaResourcePath: PropResourcePath("/ipv6/dhcp-client/"), MetaId: PropId(Id), - "add-default-route ": { + "add-default-route": { Type: schema.TypeBool, Optional: true, Description: "Whether to add default IPv6 route after a client connects.", From 1009b24eae5e75f2ddb2237c7e770c607309b108 Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Mon, 12 Feb 2024 23:56:00 +0000 Subject: [PATCH 3/4] Fix test, update sample --- Makefile | 2 +- docs/resources/ipv6_dhcp_client.md | 2 +- .../routeros_ipv6_dhcp_client/resource.tf | 9 +++++++++ routeros/resource_ipv6_dhcp_client.go | 18 ++++++++++-------- routeros/resource_ipv6_dhcp_client_test.go | 9 +++++---- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 1f716bab..d8c2ea84 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ VERSION=$(shell git describe --tags --abbrev=0) all: docs compile checksum clean test: - /usr/bin/go test -timeout 30s github.com/terraform-routeros/terraform-provider-routeros + go test -timeout 30s github.com/terraform-routeros/terraform-provider-routeros docs: go generate diff --git a/docs/resources/ipv6_dhcp_client.md b/docs/resources/ipv6_dhcp_client.md index ef12f7c4..57d4bcce 100644 --- a/docs/resources/ipv6_dhcp_client.md +++ b/docs/resources/ipv6_dhcp_client.md @@ -24,7 +24,7 @@ resource "routeros_ipv6_dhcp_client" "inet_provider" { ### Optional -- `add-default-route` (Boolean) Whether to add default IPv6 route after a client connects. +- `add_default_route` (Boolean) Whether to add default IPv6 route after a client connects. - `comment` (String) - `disabled` (Boolean) - `prefix_hint ` (Number) Include a preferred prefix length. diff --git a/examples/resources/routeros_ipv6_dhcp_client/resource.tf b/examples/resources/routeros_ipv6_dhcp_client/resource.tf index 59aa0f86..a9bdc73f 100644 --- a/examples/resources/routeros_ipv6_dhcp_client/resource.tf +++ b/examples/resources/routeros_ipv6_dhcp_client/resource.tf @@ -6,3 +6,12 @@ resource "routeros_ipv6_dhcp_client" "inet_provider" { request = ["prefix"] disabled = false } + +resource "routeros_ipv6_dhcp_client" "client" { + pool_name = "pub-add-pool" + interface = "ether1" + add-default-route = true + pool_prefix_length = "64" + request = ["prefix"] + interface = "ether1" +} \ No newline at end of file diff --git a/routeros/resource_ipv6_dhcp_client.go b/routeros/resource_ipv6_dhcp_client.go index 9eb24e5b..b8ca6018 100644 --- a/routeros/resource_ipv6_dhcp_client.go +++ b/routeros/resource_ipv6_dhcp_client.go @@ -30,10 +30,10 @@ import ( // ResourceIPv6DhcpClient https://help.mikrotik.com/docs/display/ROS/DHCP#DHCP-DHCPv6Client func ResourceIPv6DhcpClient() *schema.Resource { resSchema := map[string]*schema.Schema{ - MetaResourcePath: PropResourcePath("/ipv6/dhcp-client/"), + MetaResourcePath: PropResourcePath("/ipv6/dhcp-client"), MetaId: PropId(Id), - "add-default-route": { + "add_default_route": { Type: schema.TypeBool, Optional: true, Description: "Whether to add default IPv6 route after a client connects.", @@ -70,16 +70,18 @@ func ResourceIPv6DhcpClient() *schema.Resource { Computed: true, Description: "Shows received IPv6 prefix from DHCPv6-PD server", }, - "prefix_hint ": { - Type: schema.TypeInt, - Optional: true, - Description: "Include a preferred prefix length.", - ValidateFunc: validation.IntBetween(0, 128), + "prefix_hint": { + Type: schema.TypeString, + Optional: true, + Description: "Include a preferred prefix length.", + ValidateFunc: validation.IsIPv6Address, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "request": { Type: schema.TypeList, - Computed: true, + Required: true, Description: "To choose if the DHCPv6 request will ask for the address or the IPv6 prefix, or both.", + Elem: &schema.Schema{Type: schema.TypeString}, }, "status": { Type: schema.TypeString, diff --git a/routeros/resource_ipv6_dhcp_client_test.go b/routeros/resource_ipv6_dhcp_client_test.go index ef6c8879..9c0aed43 100644 --- a/routeros/resource_ipv6_dhcp_client_test.go +++ b/routeros/resource_ipv6_dhcp_client_test.go @@ -17,7 +17,7 @@ func TestAccIPv6DhcpClient_basic(t *testing.T) { testSetTransportEnv(t, name) }, ProviderFactories: testAccProviderFactories, - CheckDestroy: testCheckResourceDestroy("/ipv6/dhcp-client/client", "routeros_ipv6_dhcp_client"), + CheckDestroy: testCheckResourceDestroy("/ipv6/dhcp-client", "routeros_ipv6_dhcp_client"), Steps: []resource.TestStep{ { Config: testAccIPv6DhcpClientConfig(), @@ -25,11 +25,11 @@ func TestAccIPv6DhcpClient_basic(t *testing.T) { testResourcePrimaryInstanceId(testIPv6DhcpClient), resource.TestCheckResourceAttr(testIPv6DhcpClient, "interface", "ether1"), resource.TestCheckResourceAttr(testIPv6DhcpClient, "pool_name", "inet-provider-pool"), + resource.TestCheckResourceAttr(testIPv6DhcpClient, "request.0", "prefix"), ), }, }, }) - }) } } @@ -37,10 +37,11 @@ func TestAccIPv6DhcpClient_basic(t *testing.T) { func testAccIPv6DhcpClientConfig() string { return providerConfig + ` -resource "routeros_ipv6_dhcp_client" "client" { - interface = "ether1" +resource "routeros_ipv6_dhcp_client" "client" { request = ["prefix"] pool_name = "inet-provider-pool" + pool_prefix_length = "64" + interface = "ether1" } ` From 5ee87d33371e566988c4188ffc9e6d773b03c745 Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Tue, 13 Feb 2024 09:42:52 +0000 Subject: [PATCH 4/4] Add validation for request --- routeros/resource_ipv6_dhcp_client.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routeros/resource_ipv6_dhcp_client.go b/routeros/resource_ipv6_dhcp_client.go index b8ca6018..7e270717 100644 --- a/routeros/resource_ipv6_dhcp_client.go +++ b/routeros/resource_ipv6_dhcp_client.go @@ -81,7 +81,10 @@ func ResourceIPv6DhcpClient() *schema.Resource { Type: schema.TypeList, Required: true, Description: "To choose if the DHCPv6 request will ask for the address or the IPv6 prefix, or both.", - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"info", "address", "prefix"}, false), + }, }, "status": { Type: schema.TypeString,