From 77f7e11c2c172211b086c327144236e805608aeb Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Wed, 20 Sep 2023 20:09:18 +0100 Subject: [PATCH 1/5] implementaion of routeros_firewall_connection_tracking --- routeros/provider.go | 37 ++-- ...esource_ip_firewall_connection_tracking.go | 184 ++++++++++++++++++ ...ce_ip_firewall_connection_tracking_test.go | 71 +++++++ 3 files changed, 274 insertions(+), 18 deletions(-) create mode 100644 routeros/resource_ip_firewall_connection_tracking.go create mode 100644 routeros/resource_ip_firewall_connection_tracking_test.go diff --git a/routeros/provider.go b/routeros/provider.go index 36699d28..71e775c8 100644 --- a/routeros/provider.go +++ b/routeros/provider.go @@ -64,24 +64,25 @@ func Provider() *schema.Provider { ResourcesMap: map[string]*schema.Resource{ // IP objects - "routeros_ip_dhcp_client": ResourceDhcpClient(), - "routeros_ip_dhcp_server": ResourceDhcpServer(), - "routeros_ip_dhcp_server_network": ResourceDhcpServerNetwork(), - "routeros_ip_dhcp_server_lease": ResourceDhcpServerLease(), - "routeros_ip_firewall_addr_list": ResourceIPFirewallAddrList(), - "routeros_ip_firewall_filter": ResourceIPFirewallFilter(), - "routeros_ip_firewall_mangle": ResourceIPFirewallMangle(), - "routeros_ip_firewall_nat": ResourceIPFirewallNat(), - "routeros_ip_address": ResourceIPAddress(), - "routeros_ip_pool": ResourceIPPool(), - "routeros_ip_route": ResourceIPRoute(), - "routeros_ip_dns": ResourceDns(), - "routeros_ip_dns_record": ResourceDnsRecord(), - "routeros_ip_service": ResourceIpService(), - "routeros_ipv6_address": ResourceIPv6Address(), - "routeros_ipv6_firewall_addr_list": ResourceIPv6FirewallAddrList(), - "routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(), - "routeros_ipv6_route": ResourceIPv6Route(), + "routeros_firewall_connection_tracking": ResourceIPConnectionTracking(), + "routeros_ip_dhcp_client": ResourceDhcpClient(), + "routeros_ip_dhcp_server": ResourceDhcpServer(), + "routeros_ip_dhcp_server_network": ResourceDhcpServerNetwork(), + "routeros_ip_dhcp_server_lease": ResourceDhcpServerLease(), + "routeros_ip_firewall_addr_list": ResourceIPFirewallAddrList(), + "routeros_ip_firewall_filter": ResourceIPFirewallFilter(), + "routeros_ip_firewall_mangle": ResourceIPFirewallMangle(), + "routeros_ip_firewall_nat": ResourceIPFirewallNat(), + "routeros_ip_address": ResourceIPAddress(), + "routeros_ip_pool": ResourceIPPool(), + "routeros_ip_route": ResourceIPRoute(), + "routeros_ip_dns": ResourceDns(), + "routeros_ip_dns_record": ResourceDnsRecord(), + "routeros_ip_service": ResourceIpService(), + "routeros_ipv6_address": ResourceIPv6Address(), + "routeros_ipv6_firewall_addr_list": ResourceIPv6FirewallAddrList(), + "routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(), + "routeros_ipv6_route": ResourceIPv6Route(), // Aliases for IP objects to retain compatibility between original and fork "routeros_dhcp_client": ResourceDhcpClient(), diff --git a/routeros/resource_ip_firewall_connection_tracking.go b/routeros/resource_ip_firewall_connection_tracking.go new file mode 100644 index 00000000..43f46a75 --- /dev/null +++ b/routeros/resource_ip_firewall_connection_tracking.go @@ -0,0 +1,184 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +/* + { + "active-ipv4": "yes", + "active-ipv6": "yes", + "enabled": "yes", + "generic-timeout": "10m", + "icmp-timeout": "10s", + "loose-tcp-tracking": "true", + "max-entries": "1048576", + "tcp-close-timeout": "1m", + "tcp-close-wait-timeout": "1m", + "tcp-established-timeout": "1d", + "tcp-fin-wait-timeout": "1m", + "tcp-last-ack-timeout": "1m", + "tcp-max-retrans-timeout": "5m", + "tcp-syn-received-timeout": "5s", + "tcp-syn-sent-timeout": "5s", + "tcp-time-wait-timeout": "1m", + "tcp-unacked-timeout": "5m", + "total-entries": "87", + "udp-stream-timeout": "3m", + "udp-timeout": "10s" +} +*/ + +// ResourceIPConnectionTracking https://help.mikrotik.com/docs/display/ROS/Connection+tracking +func ResourceIPConnectionTracking() *schema.Resource { + + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/ip/firewall/connection/tracking"), + MetaId: PropId(Name), + "active_ipv4": { + Type: schema.TypeBool, + Computed: true, + Description: "documentation is missing", + }, + "active_ipv6": { + Type: schema.TypeBool, + Computed: true, + Description: "documentation is missing", + }, + "enabled": { + Type: schema.TypeString, + Optional: true, + Default: "yes", + Description: `Allows to disable or enable connection tracking. Disabling connection tracking will cause several firewall features to stop working. + See the list of affected features. Starting from v6.0rc2 default value is auto. This means that connection tracing is disabled until at least one firewall rule is added.`, + ValidateFunc: ValidationAutoYesNo, + }, + "generic_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10m", + Description: "Timeout for all other connection entries", + ValidateFunc: ValidationTime, + }, + "icmp_timeout": { + Type: schema.TypeString, + Optional: true, + Description: "ICMP connection timeout", + Default: "10s", + ValidateFunc: ValidationTime, + }, + "loose_tcp_tracking": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Disable picking up already established connections", + }, + "max_entries": { + Type: schema.TypeString, + Description: `Max amount of entries that the connection tracking table can hold. This value depends on the installed amount of RAM. + Note that the system does not create a maximum_size connection tracking table when it starts, it may increase if the situation demands it and the system still has free ram, but size will not exceed 1048576`, + Computed: true, + }, + "tcp_close_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10s", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "tcp_close_wait_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10s", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "tcp_established_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "1d", + Description: "Time when established TCP connection times out.", + ValidateFunc: ValidationTime, + }, + "tcp_fin_wait_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10s", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "tcp_last_ack_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10s", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "tcp_max_retrans_timeout": { + Type: schema.TypeString, + Optional: true, + // Documentation did contain the default, I'm getting it from the docker image default (7.10) + Default: "5m", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "tcp_syn_received_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "5s", + Description: "TCP SYN timeout.", + ValidateFunc: ValidationTime, + }, + "tcp_syn_sent_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "5s", + Description: "TCP SYN timeout.", + ValidateFunc: ValidationTime, + }, + "tcp_time_wait_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10s", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "tcp_unacked_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "5m", + Description: "No documentation", + ValidateFunc: ValidationTime, + }, + "total_entries": { + Type: schema.TypeInt, + Computed: true, + Description: "Amount of connections that currently connection table holds.", + }, + "udp_stream_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "3m", + Description: "Specifies the timeout of UDP connections that has seen packets in both directions", + ValidateFunc: ValidationTime, + }, + "udp_timeout": { + Type: schema.TypeString, + Optional: true, + Default: "10s", + Description: "Specifies the timeout for UDP connections that have seen packets in one direction", + ValidateFunc: ValidationTime, + }, + } + return &schema.Resource{ + CreateContext: DefaultSystemCreate(resSchema), + ReadContext: DefaultSystemRead(resSchema), + UpdateContext: DefaultSystemUpdate(resSchema), + DeleteContext: DefaultSystemDelete(resSchema), + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_ip_firewall_connection_tracking_test.go b/routeros/resource_ip_firewall_connection_tracking_test.go new file mode 100644 index 00000000..6398b731 --- /dev/null +++ b/routeros/resource_ip_firewall_connection_tracking_test.go @@ -0,0 +1,71 @@ +package routeros + +import ( + "errors" + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +const testIPConnectionTracking = "routeros_firewall_connection_tracking.data" + +func TestAccIPConnectionTrackingTest_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, + Steps: []resource.TestStep{ + { + Config: testAccIPConnectionTrackingConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(testIPConnectionTracking, "active_ipv4", "true"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "active_ipv6", "true"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "enabled", "yes"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "generic_timeout", "10m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "icmp_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "loose_tcp_tracking", "true"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "max_entries", "419840"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_wait_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_established_timeout", "1d"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_fin_wait_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_last_ack_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_max_retrans_timeout", "5m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_received_timeout", "5s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_sent_timeout", "5s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_time_wait_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_unacked_timeout", "5m"), + resource.TestCheckResourceAttrWith(testIPConnectionTracking, "total_entries", func(value string) error { + nConn, err := strconv.Atoi(value) + if err != nil { + return fmt.Errorf("the total_entries was not a number %q", err) + } + if nConn <= 0 || nConn >= 100 { + return errors.New("number of tcp connections (total_entries) does not seem correct") + } + return nil + }), + resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_stream_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_timeout", "10s"), + ), + }, + }, + }) + }) + } +} + +func testAccIPConnectionTrackingConfig() string { + return providerConfig + ` +resource "routeros_firewall_connection_tracking" "data" { + +} + +` +} From 497e3273d5099ae560ac6d2c52a9fed0d9200b8f Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Wed, 20 Sep 2023 20:39:51 +0100 Subject: [PATCH 2/5] Eliminate the need of having defaults, add more tests --- routeros/provider_schema_helpers.go | 11 ++ ...esource_ip_firewall_connection_tracking.go | 148 +++++++++--------- ...ce_ip_firewall_connection_tracking_test.go | 107 ++++++++++--- 3 files changed, 166 insertions(+), 100 deletions(-) diff --git a/routeros/provider_schema_helpers.go b/routeros/provider_schema_helpers.go index 2032c0cf..f4757586 100644 --- a/routeros/provider_schema_helpers.go +++ b/routeros/provider_schema_helpers.go @@ -354,6 +354,17 @@ var ( return iOld == iNew } + + // AlwaysPresentNotUserProvided is a SupressDiff function that prevents values not provided by users to get updated. + // This is necessary in some system-wide fields that are present regardless if the users provides any values. + // Prevents the need of hardcode values for default values, as those are harder to track over time/versions of + // routeros + AlwaysPresentNotUserProvided = func(k, old, new string, d *schema.ResourceData) bool { + if old != "" && new == "" { + return true + } + return false + } ) func buildReadFilter(m map[string]interface{}) []string { diff --git a/routeros/resource_ip_firewall_connection_tracking.go b/routeros/resource_ip_firewall_connection_tracking.go index 43f46a75..affbde5b 100644 --- a/routeros/resource_ip_firewall_connection_tracking.go +++ b/routeros/resource_ip_firewall_connection_tracking.go @@ -48,30 +48,30 @@ func ResourceIPConnectionTracking() *schema.Resource { "enabled": { Type: schema.TypeString, Optional: true, - Default: "yes", Description: `Allows to disable or enable connection tracking. Disabling connection tracking will cause several firewall features to stop working. See the list of affected features. Starting from v6.0rc2 default value is auto. This means that connection tracing is disabled until at least one firewall rule is added.`, - ValidateFunc: ValidationAutoYesNo, + ValidateFunc: ValidationAutoYesNo, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "generic_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10m", - Description: "Timeout for all other connection entries", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "Timeout for all other connection entries", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "icmp_timeout": { - Type: schema.TypeString, - Optional: true, - Description: "ICMP connection timeout", - Default: "10s", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "ICMP connection timeout", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "loose_tcp_tracking": { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "Disable picking up already established connections", + Type: schema.TypeString, + Optional: true, + Description: "Disable picking up already established connections", + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "max_entries": { Type: schema.TypeString, @@ -80,75 +80,75 @@ func ResourceIPConnectionTracking() *schema.Resource { Computed: true, }, "tcp_close_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10s", - Description: "No documentation", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_close_wait_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10s", - Description: "No documentation", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_established_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "1d", - Description: "Time when established TCP connection times out.", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "Time when established TCP connection times out.", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_fin_wait_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10s", - Description: "No documentation", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_last_ack_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10s", - Description: "No documentation", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_max_retrans_timeout": { Type: schema.TypeString, Optional: true, // Documentation did contain the default, I'm getting it from the docker image default (7.10) - Default: "5m", - Description: "No documentation", - ValidateFunc: ValidationTime, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_syn_received_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "5s", - Description: "TCP SYN timeout.", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "TCP SYN timeout.", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_syn_sent_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "5s", - Description: "TCP SYN timeout.", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "TCP SYN timeout.", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_time_wait_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10s", - Description: "No documentation", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "tcp_unacked_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "5m", - Description: "No documentation", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "No documentation", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "total_entries": { Type: schema.TypeInt, @@ -156,18 +156,18 @@ func ResourceIPConnectionTracking() *schema.Resource { Description: "Amount of connections that currently connection table holds.", }, "udp_stream_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "3m", - Description: "Specifies the timeout of UDP connections that has seen packets in both directions", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "Specifies the timeout of UDP connections that has seen packets in both directions", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, "udp_timeout": { - Type: schema.TypeString, - Optional: true, - Default: "10s", - Description: "Specifies the timeout for UDP connections that have seen packets in one direction", - ValidateFunc: ValidationTime, + Type: schema.TypeString, + Optional: true, + Description: "Specifies the timeout for UDP connections that have seen packets in one direction", + ValidateFunc: ValidationTime, + DiffSuppressFunc: AlwaysPresentNotUserProvided, }, } return &schema.Resource{ diff --git a/routeros/resource_ip_firewall_connection_tracking_test.go b/routeros/resource_ip_firewall_connection_tracking_test.go index 6398b731..f4025b75 100644 --- a/routeros/resource_ip_firewall_connection_tracking_test.go +++ b/routeros/resource_ip_firewall_connection_tracking_test.go @@ -15,44 +15,64 @@ func TestAccIPConnectionTrackingTest_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, Steps: []resource.TestStep{ + // we can set all fields to non default + { + Config: testAccIPConnectionTrackingFullConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(testIPConnectionTracking, "active_ipv4", "true"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "active_ipv6", "true"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "enabled", "yes"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "generic_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "icmp_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "loose_tcp_tracking", "false"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "max_entries", "419840"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_wait_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_established_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_fin_wait_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_last_ack_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_max_retrans_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_received_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_sent_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_time_wait_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_unacked_timeout", "3m"), + resource.TestCheckResourceAttrWith(testIPConnectionTracking, "total_entries", connectionsIsInAcceptableRange), + resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_stream_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_timeout", "3m"), + ), + }, + + // Empty resource don't override the settings { - Config: testAccIPConnectionTrackingConfig(), + Config: testAccIPConnectionTrackingEmptyConfig(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(testIPConnectionTracking, "active_ipv4", "true"), resource.TestCheckResourceAttr(testIPConnectionTracking, "active_ipv6", "true"), resource.TestCheckResourceAttr(testIPConnectionTracking, "enabled", "yes"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "generic_timeout", "10m"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "icmp_timeout", "10s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "loose_tcp_tracking", "true"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "generic_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "icmp_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "loose_tcp_tracking", "false"), resource.TestCheckResourceAttr(testIPConnectionTracking, "max_entries", "419840"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_timeout", "10s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_wait_timeout", "10s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_established_timeout", "1d"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_fin_wait_timeout", "10s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_last_ack_timeout", "10s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_max_retrans_timeout", "5m"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_received_timeout", "5s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_sent_timeout", "5s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_time_wait_timeout", "10s"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_unacked_timeout", "5m"), - resource.TestCheckResourceAttrWith(testIPConnectionTracking, "total_entries", func(value string) error { - nConn, err := strconv.Atoi(value) - if err != nil { - return fmt.Errorf("the total_entries was not a number %q", err) - } - if nConn <= 0 || nConn >= 100 { - return errors.New("number of tcp connections (total_entries) does not seem correct") - } - return nil - }), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_close_wait_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_established_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_fin_wait_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_last_ack_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_max_retrans_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_received_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_syn_sent_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_time_wait_timeout", "3m"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "tcp_unacked_timeout", "3m"), + resource.TestCheckResourceAttrWith(testIPConnectionTracking, "total_entries", connectionsIsInAcceptableRange), resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_stream_timeout", "3m"), - resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_timeout", "10s"), + resource.TestCheckResourceAttr(testIPConnectionTracking, "udp_timeout", "3m"), ), }, }, @@ -61,7 +81,7 @@ func TestAccIPConnectionTrackingTest_basic(t *testing.T) { } } -func testAccIPConnectionTrackingConfig() string { +func testAccIPConnectionTrackingEmptyConfig() string { return providerConfig + ` resource "routeros_firewall_connection_tracking" "data" { @@ -69,3 +89,38 @@ resource "routeros_firewall_connection_tracking" "data" { ` } + +func testAccIPConnectionTrackingFullConfig() string { + return providerConfig + ` +resource "routeros_firewall_connection_tracking" "data" { + enabled = "yes" + generic_timeout = "3m" + icmp_timeout = "3m" + loose_tcp_tracking = "false" + tcp_close_timeout = "3m" + tcp_close_wait_timeout = "3m" + tcp_established_timeout = "3m" + tcp_fin_wait_timeout = "3m" + tcp_last_ack_timeout = "3m" + tcp_max_retrans_timeout = "3m" + tcp_syn_received_timeout = "3m" + tcp_syn_sent_timeout = "3m" + tcp_time_wait_timeout = "3m" + tcp_unacked_timeout = "3m" + udp_stream_timeout = "3m" + udp_timeout = "3m" +} + +` +} + +func connectionsIsInAcceptableRange(value string) error { + nConn, err := strconv.Atoi(value) + if err != nil { + return fmt.Errorf("the total_entries was not a number %q", err) + } + if nConn <= 0 || nConn >= 100 { + return errors.New("number of tcp connections (total_entries) does not seem correct") + } + return nil +} From 864a487c04d22f5a01810f98d1877eb90c845a79 Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Wed, 20 Sep 2023 21:00:06 +0100 Subject: [PATCH 3/5] Add examples, correct name of the resource --- .../resource.tf | 19 ++++++++++ routeros/provider.go | 38 +++++++++---------- ...ce_ip_firewall_connection_tracking_test.go | 6 +-- 3 files changed, 41 insertions(+), 22 deletions(-) create mode 100644 examples/resources/routeros_ip_firewall_connection_tracking/resource.tf diff --git a/examples/resources/routeros_ip_firewall_connection_tracking/resource.tf b/examples/resources/routeros_ip_firewall_connection_tracking/resource.tf new file mode 100644 index 00000000..3bd48371 --- /dev/null +++ b/examples/resources/routeros_ip_firewall_connection_tracking/resource.tf @@ -0,0 +1,19 @@ + +resource "routeros_ip_firewall_connection_tracking" "data" { + enabled = "yes" + generic_timeout = "3m" + icmp_timeout = "3m" + loose_tcp_tracking = "false" + tcp_close_timeout = "3m" + tcp_close_wait_timeout = "3m" + tcp_established_timeout = "3m" + tcp_fin_wait_timeout = "3m" + tcp_last_ack_timeout = "3m" + tcp_max_retrans_timeout = "3m" + tcp_syn_received_timeout = "3m" + tcp_syn_sent_timeout = "3m" + tcp_time_wait_timeout = "3m" + tcp_unacked_timeout = "3m" + udp_stream_timeout = "3m" + udp_timeout = "3m" +} \ No newline at end of file diff --git a/routeros/provider.go b/routeros/provider.go index 71e775c8..12b0fd3f 100644 --- a/routeros/provider.go +++ b/routeros/provider.go @@ -64,25 +64,25 @@ func Provider() *schema.Provider { ResourcesMap: map[string]*schema.Resource{ // IP objects - "routeros_firewall_connection_tracking": ResourceIPConnectionTracking(), - "routeros_ip_dhcp_client": ResourceDhcpClient(), - "routeros_ip_dhcp_server": ResourceDhcpServer(), - "routeros_ip_dhcp_server_network": ResourceDhcpServerNetwork(), - "routeros_ip_dhcp_server_lease": ResourceDhcpServerLease(), - "routeros_ip_firewall_addr_list": ResourceIPFirewallAddrList(), - "routeros_ip_firewall_filter": ResourceIPFirewallFilter(), - "routeros_ip_firewall_mangle": ResourceIPFirewallMangle(), - "routeros_ip_firewall_nat": ResourceIPFirewallNat(), - "routeros_ip_address": ResourceIPAddress(), - "routeros_ip_pool": ResourceIPPool(), - "routeros_ip_route": ResourceIPRoute(), - "routeros_ip_dns": ResourceDns(), - "routeros_ip_dns_record": ResourceDnsRecord(), - "routeros_ip_service": ResourceIpService(), - "routeros_ipv6_address": ResourceIPv6Address(), - "routeros_ipv6_firewall_addr_list": ResourceIPv6FirewallAddrList(), - "routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(), - "routeros_ipv6_route": ResourceIPv6Route(), + "routeros_ip_dhcp_client": ResourceDhcpClient(), + "routeros_ip_dhcp_server": ResourceDhcpServer(), + "routeros_ip_dhcp_server_network": ResourceDhcpServerNetwork(), + "routeros_ip_dhcp_server_lease": ResourceDhcpServerLease(), + "routeros_ip_firewall_addr_list": ResourceIPFirewallAddrList(), + "routeros_ip_firewall_connection_tracking": ResourceIPConnectionTracking(), + "routeros_ip_firewall_filter": ResourceIPFirewallFilter(), + "routeros_ip_firewall_mangle": ResourceIPFirewallMangle(), + "routeros_ip_firewall_nat": ResourceIPFirewallNat(), + "routeros_ip_address": ResourceIPAddress(), + "routeros_ip_pool": ResourceIPPool(), + "routeros_ip_route": ResourceIPRoute(), + "routeros_ip_dns": ResourceDns(), + "routeros_ip_dns_record": ResourceDnsRecord(), + "routeros_ip_service": ResourceIpService(), + "routeros_ipv6_address": ResourceIPv6Address(), + "routeros_ipv6_firewall_addr_list": ResourceIPv6FirewallAddrList(), + "routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(), + "routeros_ipv6_route": ResourceIPv6Route(), // Aliases for IP objects to retain compatibility between original and fork "routeros_dhcp_client": ResourceDhcpClient(), diff --git a/routeros/resource_ip_firewall_connection_tracking_test.go b/routeros/resource_ip_firewall_connection_tracking_test.go index f4025b75..0984b33c 100644 --- a/routeros/resource_ip_firewall_connection_tracking_test.go +++ b/routeros/resource_ip_firewall_connection_tracking_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) -const testIPConnectionTracking = "routeros_firewall_connection_tracking.data" +const testIPConnectionTracking = "routeros_ip_firewall_connection_tracking.data" func TestAccIPConnectionTrackingTest_basic(t *testing.T) { for _, name := range testNames { @@ -83,7 +83,7 @@ func TestAccIPConnectionTrackingTest_basic(t *testing.T) { func testAccIPConnectionTrackingEmptyConfig() string { return providerConfig + ` -resource "routeros_firewall_connection_tracking" "data" { +resource "routeros_ip_firewall_connection_tracking" "data" { } @@ -92,7 +92,7 @@ resource "routeros_firewall_connection_tracking" "data" { func testAccIPConnectionTrackingFullConfig() string { return providerConfig + ` -resource "routeros_firewall_connection_tracking" "data" { +resource "routeros_ip_firewall_connection_tracking" "data" { enabled = "yes" generic_timeout = "3m" icmp_timeout = "3m" From 27cc0a83abaab8d2b0652bcd7b2de12ab0e429c9 Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Wed, 20 Sep 2023 22:36:41 +0100 Subject: [PATCH 4/5] Skip test in old versions --- routeros/resource_ip_firewall_connection_tracking_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/routeros/resource_ip_firewall_connection_tracking_test.go b/routeros/resource_ip_firewall_connection_tracking_test.go index 0984b33c..6a59a5b8 100644 --- a/routeros/resource_ip_firewall_connection_tracking_test.go +++ b/routeros/resource_ip_firewall_connection_tracking_test.go @@ -10,9 +10,15 @@ import ( ) const testIPConnectionTracking = "routeros_ip_firewall_connection_tracking.data" +const testMingIPConnTrackingVersion = "7.10" func TestAccIPConnectionTrackingTest_basic(t *testing.T) { for _, name := range testNames { + if !testCheckMinVersion(t, testMingIPConnTrackingVersion) { + t.Logf("Test skipped, the minimum required version is %v", testMingIPConnTrackingVersion) + return + } + t.Run(name, func(t *testing.T) { resource.Test(t, resource.TestCase{ From b0c92e57cacd5ea96a833ed93b6c742d0a2b07db Mon Sep 17 00:00:00 2001 From: Jose Luis Pedrosa Date: Wed, 20 Sep 2023 22:43:07 +0100 Subject: [PATCH 5/5] Merge master --- CHANGELOG.md | 7 ++ docs/resources/ip_dhcp_server_option.md | 42 +++++++++++ docs/resources/ip_dhcp_server_option_set.md | 45 ++++++++++++ .../routeros_ip_dhcp_server_option/import.sh | 3 + .../resource.tf | 12 +++ .../import.sh | 3 + .../resource.tf | 17 +++++ package.json | 2 +- routeros/provider.go | 2 + routeros/resource_ip_dhcp_server_option.go | 60 +++++++++++++++ .../resource_ip_dhcp_server_option_sets.go | 46 ++++++++++++ ...esource_ip_dhcp_server_option_sets_test.go | 73 +++++++++++++++++++ .../resource_ip_dhcp_server_option_test.go | 65 +++++++++++++++++ 13 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 docs/resources/ip_dhcp_server_option.md create mode 100644 docs/resources/ip_dhcp_server_option_set.md create mode 100644 examples/resources/routeros_ip_dhcp_server_option/import.sh create mode 100644 examples/resources/routeros_ip_dhcp_server_option/resource.tf create mode 100644 examples/resources/routeros_ip_dhcp_server_option_set/import.sh create mode 100644 examples/resources/routeros_ip_dhcp_server_option_set/resource.tf create mode 100644 routeros/resource_ip_dhcp_server_option.go create mode 100644 routeros/resource_ip_dhcp_server_option_sets.go create mode 100644 routeros/resource_ip_dhcp_server_option_sets_test.go create mode 100644 routeros/resource_ip_dhcp_server_option_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c4f8118a..65b1c245 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.15.0](https://github.com/terraform-routeros/terraform-provider-routeros/compare/v1.14.0...v1.15.0) (2023-09-20) + + +### Features + +* Add routeros_ip_dhcp_server_option and routeros_ip_dhcp_server_option_set ([#259](https://github.com/terraform-routeros/terraform-provider-routeros/issues/259)) ([3722afb](https://github.com/terraform-routeros/terraform-provider-routeros/commit/3722afb8574250a7a7e3211f2e40f3b4acfdc56f)) + ## [1.14.0](https://github.com/terraform-routeros/terraform-provider-routeros/compare/v1.13.3...v1.14.0) (2023-09-19) diff --git a/docs/resources/ip_dhcp_server_option.md b/docs/resources/ip_dhcp_server_option.md new file mode 100644 index 00000000..06af7c8f --- /dev/null +++ b/docs/resources/ip_dhcp_server_option.md @@ -0,0 +1,42 @@ +# routeros_ip_dhcp_server_option (Resource) +Creates a DHCP lease on the mikrotik device. + +## Example Usage +```terraform +resource "routeros_ip_dhcp_server_option" "jumbo_frame_opt" { + code = 77 + name = "jumbo-mtu-opt" + value = "0x2336" +} + +resource "routeros_ip_dhcp_server_option" "tftp_option" { + code = 66 + name = "tftpserver-66" + value = "s'10.10.10.22'" +} +``` + + +## Schema + +### Required + +- `code` (Number) The number of the DHCP option +- `name` (String) The name of the DHCP option +- `value` (String) The value with formatting using Mikrotik settings https://wiki.mikrotik.com/wiki/Manual:IP/DHCP_Server#DHCP_Options + +### Optional + + +### Read-Only + +- `id` (String) The ID of this resource. +- `raw_value` (String) The computed value of the option as an hex value + +## 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 [/ip/dhcp-server/option/get [print show-ids]] +terraform import routeros_ip_dhcp_server_option.tftp_option "*1" +``` diff --git a/docs/resources/ip_dhcp_server_option_set.md b/docs/resources/ip_dhcp_server_option_set.md new file mode 100644 index 00000000..f6f481b0 --- /dev/null +++ b/docs/resources/ip_dhcp_server_option_set.md @@ -0,0 +1,45 @@ +# routeros_ip_dhcp_server_option_set (Resource) +Creates a DHCP lease on the mikrotik device. + +## Example Usage +```terraform +resource "routeros_ip_dhcp_server_option" "jumbo_frame_opt" { + code = 77 + name = "jumbo-mtu-opt" + value = "0x2336" +} + +resource "routeros_ip_dhcp_server_option" "tftp_option" { + code = 66 + name = "tftpserver-66" + value = "s'10.10.10.22'" +} + +resource "routeros_ip_dhcp_server_option_set" "lan_option_set" { + name = "lan-option-set" + options = join(",", [routeros_ip_dhcp_server_option.jumbo_frame_opt.name, routeros_ip_dhcp_server_option.tftp_option.name]) +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the DHCP option +- `options` (String) The comma sepparated list of options + +### Optional + + +### Read-Only + +- `id` (String) The ID of this resource. + +## 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 [/ip/dhcp-server/option/sets/get [print show-ids]] +terraform import routeros_ip_dhcp_server_option_set.lan_option_set "*1" +``` diff --git a/examples/resources/routeros_ip_dhcp_server_option/import.sh b/examples/resources/routeros_ip_dhcp_server_option/import.sh new file mode 100644 index 00000000..c7fe9d84 --- /dev/null +++ b/examples/resources/routeros_ip_dhcp_server_option/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/ip/dhcp-server/option/get [print show-ids]] +terraform import routeros_ip_dhcp_server_option.tftp_option "*1" \ No newline at end of file diff --git a/examples/resources/routeros_ip_dhcp_server_option/resource.tf b/examples/resources/routeros_ip_dhcp_server_option/resource.tf new file mode 100644 index 00000000..59a82132 --- /dev/null +++ b/examples/resources/routeros_ip_dhcp_server_option/resource.tf @@ -0,0 +1,12 @@ + +resource "routeros_ip_dhcp_server_option" "jumbo_frame_opt" { + code = 77 + name = "jumbo-mtu-opt" + value = "0x2336" +} + +resource "routeros_ip_dhcp_server_option" "tftp_option" { + code = 66 + name = "tftpserver-66" + value = "s'10.10.10.22'" +} diff --git a/examples/resources/routeros_ip_dhcp_server_option_set/import.sh b/examples/resources/routeros_ip_dhcp_server_option_set/import.sh new file mode 100644 index 00000000..d58b99c0 --- /dev/null +++ b/examples/resources/routeros_ip_dhcp_server_option_set/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/ip/dhcp-server/option/sets/get [print show-ids]] +terraform import routeros_ip_dhcp_server_option_set.lan_option_set "*1" \ No newline at end of file diff --git a/examples/resources/routeros_ip_dhcp_server_option_set/resource.tf b/examples/resources/routeros_ip_dhcp_server_option_set/resource.tf new file mode 100644 index 00000000..6c80b280 --- /dev/null +++ b/examples/resources/routeros_ip_dhcp_server_option_set/resource.tf @@ -0,0 +1,17 @@ + +resource "routeros_ip_dhcp_server_option" "jumbo_frame_opt" { + code = 77 + name = "jumbo-mtu-opt" + value = "0x2336" +} + +resource "routeros_ip_dhcp_server_option" "tftp_option" { + code = 66 + name = "tftpserver-66" + value = "s'10.10.10.22'" +} + +resource "routeros_ip_dhcp_server_option_set" "lan_option_set" { + name = "lan-option-set" + options = join(",", [routeros_ip_dhcp_server_option.jumbo_frame_opt.name, routeros_ip_dhcp_server_option.tftp_option.name]) +} \ No newline at end of file diff --git a/package.json b/package.json index 75d43efd..961985a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "terraform-provider-routeros", - "version": "1.14.0", + "version": "1.15.0", "repository": { "type": "git", "url": "https://github.com/terraform-routeros/terraform-provider-routeros" diff --git a/routeros/provider.go b/routeros/provider.go index 12b0fd3f..ddad6fc9 100644 --- a/routeros/provider.go +++ b/routeros/provider.go @@ -68,6 +68,8 @@ func Provider() *schema.Provider { "routeros_ip_dhcp_server": ResourceDhcpServer(), "routeros_ip_dhcp_server_network": ResourceDhcpServerNetwork(), "routeros_ip_dhcp_server_lease": ResourceDhcpServerLease(), + "routeros_ip_dhcp_server_option": ResourceDhcpServerOption(), + "routeros_ip_dhcp_server_option_set": ResourceDhcpServerOptionSet(), "routeros_ip_firewall_addr_list": ResourceIPFirewallAddrList(), "routeros_ip_firewall_connection_tracking": ResourceIPConnectionTracking(), "routeros_ip_firewall_filter": ResourceIPFirewallFilter(), diff --git a/routeros/resource_ip_dhcp_server_option.go b/routeros/resource_ip_dhcp_server_option.go new file mode 100644 index 00000000..32902567 --- /dev/null +++ b/routeros/resource_ip_dhcp_server_option.go @@ -0,0 +1,60 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +[ + { + ".id": "*4", + "code": "66", + "name": "optionname", + "raw-value": "00002311", + "value": "0x00002311" + } +] +*/ + +// ResourceDhcpServerOption https://wiki.mikrotik.com/wiki/Manual:IP/DHCP_Server +func ResourceDhcpServerOption() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/ip/dhcp-server/option"), + MetaId: PropId(Id), + "code": { + Type: schema.TypeInt, + Required: true, + Description: "The number of the DHCP option", + ValidateFunc: validation.IntBetween(1, 254), + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the DHCP option", + }, + "raw_value": { + Type: schema.TypeString, + Computed: true, + Description: "The computed value of the option as an hex value", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "The value with formatting using Mikrotik settings https://wiki.mikrotik.com/wiki/Manual:IP/DHCP_Server#DHCP_Options", + }, + } + return &schema.Resource{ + Description: "Creates a DHCP lease on the mikrotik device.", + + 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_ip_dhcp_server_option_sets.go b/routeros/resource_ip_dhcp_server_option_sets.go new file mode 100644 index 00000000..724b0cfa --- /dev/null +++ b/routeros/resource_ip_dhcp_server_option_sets.go @@ -0,0 +1,46 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +/* +[ + { + ".id": "*2", + "name": "netboot", + "options": "tftpserver-66,unifi,mtu-jumbo" + } +] +*/ + +// ResourceDhcpServerOption https://wiki.mikrotik.com/wiki/Manual:IP/DHCP_Server +func ResourceDhcpServerOptionSet() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/ip/dhcp-server/option/sets"), + MetaId: PropId(Id), + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the DHCP option", + }, + "options": { + Type: schema.TypeString, + Required: true, + Description: "The comma sepparated list of options", + }, + } + return &schema.Resource{ + Description: "Creates a DHCP lease on the mikrotik device.", + + 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_ip_dhcp_server_option_sets_test.go b/routeros/resource_ip_dhcp_server_option_sets_test.go new file mode 100644 index 00000000..db61ed87 --- /dev/null +++ b/routeros/resource_ip_dhcp_server_option_sets_test.go @@ -0,0 +1,73 @@ +package routeros + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +const testIpDhcpServerOptionSet = "routeros_ip_dhcp_server_option_set.test_option_set" + +func TestAccIpDhcpServerNetworkOptionSet_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("/ip/dhcp-server/option/sets", "routeros_ip_dhcp_server_option_set"), + Steps: []resource.TestStep{ + { + Config: testAccIpDhcpServerOptionSetConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIpDhcpServerOptionSetExists(testIpDhcpServerOptionSet), + resource.TestCheckResourceAttr(testIpDhcpServerOptionSet, "name", "test-opt-set"), + resource.TestCheckResourceAttr(testIpDhcpServerOptionSet, "options", "test-opt1,test-opt2"), + ), + }, + }, + }) + + }) + } +} + +func testAccCheckIpDhcpServerOptionSetExists(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 testAccIpDhcpServerOptionSetConfig() string { + return providerConfig + ` +resource "routeros_ip_dhcp_server_option" "test_option_1" { + code = 77 + name = "test-opt1" + value = "s'10.10.10.22'" + } + +resource "routeros_ip_dhcp_server_option" "test_option_2" { + code = 90 + name = "test-opt2" + value = "s'10.10.10.22'" + } + +resource "routeros_ip_dhcp_server_option_set" "test_option_set" { + name = "test-opt-set" + options = join(",", [routeros_ip_dhcp_server_option.test_option_1.name, routeros_ip_dhcp_server_option.test_option_2.name]) + } +` +} diff --git a/routeros/resource_ip_dhcp_server_option_test.go b/routeros/resource_ip_dhcp_server_option_test.go new file mode 100644 index 00000000..09b495c9 --- /dev/null +++ b/routeros/resource_ip_dhcp_server_option_test.go @@ -0,0 +1,65 @@ +package routeros + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +const testIpDhcpServerOption = "routeros_ip_dhcp_server_option.test_option" + +func TestAccIpDhcpServerNetworkOption_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("/ip/dhcp-server/option", "routeros_ip_dhcp_server_option"), + Steps: []resource.TestStep{ + { + Config: testAccIpDhcpServerOptionConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIpDhcpServerOptionExists(testIpDhcpServerOption), + resource.TestCheckResourceAttr(testIpDhcpServerOption, "code", "77"), + resource.TestCheckResourceAttr(testIpDhcpServerOption, "name", "test-opt"), + resource.TestCheckResourceAttr(testIpDhcpServerOption, "value", "s'10.10.10.22'"), + + resource.TestCheckResourceAttr(testIpDhcpServerOption, "raw_value", "31302e31302e31302e3232"), + ), + }, + }, + }) + + }) + } +} + +func testAccCheckIpDhcpServerOptionExists(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 testAccIpDhcpServerOptionConfig() string { + return providerConfig + ` +resource "routeros_ip_dhcp_server_option" "test_option" { + code = 77 + name = "test-opt" + value = "s'10.10.10.22'" + } +` +}