From 4b0645dc39c68f6f71e69789a0de1478aabaa030 Mon Sep 17 00:00:00 2001 From: Chris McKeown Date: Sun, 28 Apr 2024 21:01:57 +0100 Subject: [PATCH] Multiple network resource and data source improvements --- docs/data-sources/network.md | 2 +- docs/resources/network.md | 2 +- internal/provider/cidr.go | 11 --- internal/provider/data_network.go | 34 +++++++-- internal/provider/resource_network.go | 88 +++++++++++++++++----- internal/provider/resource_network_test.go | 2 +- 6 files changed, 101 insertions(+), 38 deletions(-) diff --git a/docs/data-sources/network.md b/docs/data-sources/network.md index d2d8b5c93..21b029c55 100644 --- a/docs/data-sources/network.md +++ b/docs/data-sources/network.md @@ -59,7 +59,7 @@ data "unifi_network" "my_network" { - `ipv6_pd_prefixid` (String) Specifies the IPv6 Prefix ID. - `ipv6_pd_start` (String) Start address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`. - `ipv6_pd_stop` (String) End address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`. -- `ipv6_ra_enable` (Boolean) Specifies whether to enable router advertisements or not. +- `ipv6_ra_enabled` (Boolean) Specifies whether to enable router advertisements or not. - `ipv6_ra_preferred_lifetime` (Number) Lifetime in which the address can be used. Address becomes deprecated afterwards. Must be lower than or equal to `ipv6_ra_valid_lifetime` - `ipv6_ra_priority` (String) IPv6 router advertisement priority. Must be one of either `high`, `medium`, or `low` - `ipv6_ra_valid_lifetime` (Number) Total lifetime in which the address can be used. Must be equal to or greater than `ipv6_ra_preferred_lifetime`. diff --git a/docs/resources/network.md b/docs/resources/network.md index 7c3a76ae6..df0a610e1 100644 --- a/docs/resources/network.md +++ b/docs/resources/network.md @@ -75,7 +75,7 @@ resource "unifi_network" "wan" { - `ipv6_pd_prefixid` (String) Specifies the IPv6 Prefix ID. - `ipv6_pd_start` (String) Start address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`. - `ipv6_pd_stop` (String) End address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`. -- `ipv6_ra_enable` (Boolean) Specifies whether to enable router advertisements or not. +- `ipv6_ra_enabled` (Boolean) Specifies whether to enable router advertisements or not. - `ipv6_ra_preferred_lifetime` (Number) Lifetime in which the address can be used. Address becomes deprecated afterwards. Must be lower than or equal to `ipv6_ra_valid_lifetime` Defaults to `14400`. - `ipv6_ra_priority` (String) IPv6 router advertisement priority. Must be one of either `high`, `medium`, or `low` - `ipv6_ra_valid_lifetime` (Number) Total lifetime in which the address can be used. Must be equal to or greater than `ipv6_ra_preferred_lifetime`. Defaults to `86400`. diff --git a/internal/provider/cidr.go b/internal/provider/cidr.go index 1d6da24a1..736a846e2 100644 --- a/internal/provider/cidr.go +++ b/internal/provider/cidr.go @@ -43,14 +43,3 @@ func cidrZeroBased(cidr string) string { return cidrNet.String() } - -func cidrOneBased(cidr string) string { - _, cidrNet, err := net.ParseCIDR(cidr) - if err != nil { - return "" - } - - cidrNet.IP[3]++ - - return cidrNet.String() -} diff --git a/internal/provider/data_network.go b/internal/provider/data_network.go index 0a184365a..181423923 100644 --- a/internal/provider/data_network.go +++ b/internal/provider/data_network.go @@ -76,7 +76,19 @@ func dataNetwork() *schema.Resource { Type: schema.TypeInt, Computed: true, }, - + "dhcpguard_enabled": { + Description: "Whether DHCP guarding is enabled or not on this network.", + Type: schema.TypeBool, + Computed: true, + }, + "dhcp_server_ips": { + Description: "IPv4 addresses of the DHCP servers on this network", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, "dhcp_dns": { Description: "IPv4 addresses for the DNS server to be returned from the DHCP " + "server.", @@ -86,7 +98,6 @@ func dataNetwork() *schema.Resource { Type: schema.TypeString, }, }, - "dhcpd_boot_enabled": { Description: "Toggles on the DHCP boot options. will be set to true if you have dhcpd_boot_filename, and dhcpd_boot_server set.", Type: schema.TypeBool, @@ -176,7 +187,7 @@ func dataNetwork() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "ipv6_ra_enable": { + "ipv6_ra_enabled": { Description: "Specifies whether to enable router advertisements or not.", Type: schema.TypeBool, Computed: true, @@ -321,14 +332,27 @@ func dataNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface } wanDNS = append(wanDNS, dns) } + dhcpdIPs := []string{} + for _, dhcpIP := range []string{ + n.DHCPDIP1, + n.DHCPDIP2, + n.DHCPDIP3, + } { + if dhcpIP == "" { + continue + } + dhcpdIPs = append(dhcpdIPs, dhcpIP) + } d.SetId(n.ID) d.Set("site", site) d.Set("name", n.Name) d.Set("purpose", n.Purpose) d.Set("vlan_id", n.VLAN) - d.Set("subnet", cidrZeroBased(n.IPSubnet)) + d.Set("subnet", n.IPSubnet) d.Set("network_group", n.NetworkGroup) + d.Set("dhcpguard_enabled", n.DHCPguardEnabled) + d.Set("dhcp_server_ips", dhcpdIPs) d.Set("dhcp_dns", dhcpDNS) d.Set("dhcp_start", n.DHCPDStart) d.Set("dhcp_stop", n.DHCPDStop) @@ -343,7 +367,7 @@ func dataNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface d.Set("ipv6_static_subnet", n.IPV6Subnet) d.Set("ipv6_pd_interface", n.IPV6PDInterface) d.Set("ipv6_pd_prefixid", n.IPV6PDPrefixid) - d.Set("ipv6_ra_enable", n.IPV6RaEnabled) + d.Set("ipv6_ra_enabled", n.IPV6RaEnabled) d.Set("multicast_dns", n.MdnsEnabled) d.Set("wan_ip", n.WANIP) d.Set("wan_netmask", n.WANNetmask) diff --git a/internal/provider/resource_network.go b/internal/provider/resource_network.go index 3faf0b8c7..f6b6afd7c 100644 --- a/internal/provider/resource_network.go +++ b/internal/provider/resource_network.go @@ -197,6 +197,25 @@ func resourceNetwork() *schema.Resource { Optional: true, ValidateFunc: validation.IsIPv6Address, }, + "dhcpguard_enabled": { + Description: "Whether DHCP guarding is enabled or not on this network.", + Type: schema.TypeBool, + Optional: true, + }, + "dhcp_server_ips": { + Description: "IPv4 addresses of the DHCP servers on this network", + Type: schema.TypeList, + Optional: true, + MaxItems: 3, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.IsIPv4Address, + // this doesn't let blank through + validation.StringLenBetween(1, 50), + ), + }, + }, "domain_name": { Description: "The domain name of this network.", Type: schema.TypeString, @@ -242,7 +261,7 @@ func resourceNetwork() *schema.Resource { Optional: true, ValidateFunc: validation.IsIPv6Address, }, - "ipv6_ra_enable": { + "ipv6_ra_enabled": { Description: "Specifies whether to enable router advertisements or not.", Type: schema.TypeBool, Optional: true, @@ -402,6 +421,7 @@ func resourceNetworkGetResourceData(d *schema.ResourceData, meta interface{}) (* vlan := d.Get("vlan_id").(int) dhcpDNS, err := listToStringSlice(d.Get("dhcp_dns").([]interface{})) + dhcpdIPs, err := listToStringSlice(d.Get("dhcp_server_ips").([]interface{})) if err != nil { return nil, fmt.Errorf("unable to convert dhcp_dns to string slice: %w", err) } @@ -418,7 +438,7 @@ func resourceNetworkGetResourceData(d *schema.ResourceData, meta interface{}) (* Name: d.Get("name").(string), Purpose: d.Get("purpose").(string), VLAN: vlan, - IPSubnet: cidrOneBased(d.Get("subnet").(string)), + IPSubnet: d.Get("subnet").(string), NetworkGroup: d.Get("network_group").(string), DHCPDStart: d.Get("dhcp_start").(string), DHCPDStop: d.Get("dhcp_stop").(string), @@ -428,6 +448,7 @@ func resourceNetworkGetResourceData(d *schema.ResourceData, meta interface{}) (* DHCPDBootServer: d.Get("dhcpd_boot_server").(string), DHCPDBootFilename: d.Get("dhcpd_boot_filename").(string), DHCPRelayEnabled: d.Get("dhcp_relay_enabled").(bool), + DHCPguardEnabled: d.Get("dhcpguard_enabled").(bool), DomainName: d.Get("domain_name").(string), IGMPSnooping: d.Get("igmp_snooping").(bool), MdnsEnabled: d.Get("multicast_dns").(bool), @@ -439,6 +460,11 @@ func resourceNetworkGetResourceData(d *schema.ResourceData, meta interface{}) (* DHCPDDNS3: append(dhcpDNS, "", "", "")[2], DHCPDDNS4: append(dhcpDNS, "", "", "", "")[3], + // More hackiness like the above + DHCPDIP1: append(dhcpdIPs, "")[0], + DHCPDIP2: append(dhcpdIPs, "", "")[1], + DHCPDIP3: append(dhcpdIPs, "", "", "")[2], + VLANEnabled: vlan != 0 && vlan != 1, Enabled: true, @@ -461,7 +487,7 @@ func resourceNetworkGetResourceData(d *schema.ResourceData, meta interface{}) (* IPV6PDPrefixid: d.Get("ipv6_pd_prefixid").(string), IPV6PDStart: d.Get("ipv6_pd_start").(string), IPV6PDStop: d.Get("ipv6_pd_stop").(string), - IPV6RaEnabled: d.Get("ipv6_ra_enable").(bool), + IPV6RaEnabled: d.Get("ipv6_ra_enabled").(bool), IPV6RaPreferredLifetime: d.Get("ipv6_ra_preferred_lifetime").(int), IPV6RaPriority: d.Get("ipv6_ra_priority").(string), IPV6RaValidLifetime: d.Get("ipv6_ra_valid_lifetime").(int), @@ -548,6 +574,18 @@ func resourceNetworkSetResourceData(resp *unifi.Network, d *schema.ResourceData, } } + dhcpdIPs := []string{} + for _, dhcpIP := range []string{ + resp.DHCPDIP1, + resp.DHCPDIP2, + resp.DHCPDIP3, + } { + if dhcpIP == "" { + continue + } + dhcpdIPs = append(dhcpdIPs, dhcpIP) + } + dhcpV6DNS := []string{} for _, dns := range []string{ resp.DHCPDV6DNS1, @@ -565,38 +603,50 @@ func resourceNetworkSetResourceData(resp *unifi.Network, d *schema.ResourceData, d.Set("name", resp.Name) d.Set("purpose", resp.Purpose) d.Set("vlan_id", vlan) - d.Set("subnet", cidrZeroBased(resp.IPSubnet)) + d.Set("subnet", resp.IPSubnet) d.Set("network_group", resp.NetworkGroup) d.Set("dhcp_dns", dhcpDNS) + d.Set("dhcp_server_ips", dhcpdIPs) d.Set("dhcp_enabled", resp.DHCPDEnabled) d.Set("dhcp_lease", dhcpLease) d.Set("dhcp_relay_enabled", resp.DHCPRelayEnabled) d.Set("dhcp_start", resp.DHCPDStart) d.Set("dhcp_stop", resp.DHCPDStop) - d.Set("dhcp_v6_dns_auto", resp.DHCPDV6DNSAuto) - d.Set("dhcp_v6_dns", dhcpV6DNS) - d.Set("dhcp_v6_enabled", resp.DHCPDV6Enabled) - d.Set("dhcp_v6_lease", resp.DHCPDV6LeaseTime) - d.Set("dhcp_v6_start", resp.DHCPDV6Start) - d.Set("dhcp_v6_stop", resp.DHCPDV6Stop) d.Set("dhcpd_boot_enabled", resp.DHCPDBootEnabled) d.Set("dhcpd_boot_filename", resp.DHCPDBootFilename) d.Set("dhcpd_boot_server", resp.DHCPDBootServer) + d.Set("dhcpguard_enabled", resp.DHCPguardEnabled) d.Set("domain_name", resp.DomainName) d.Set("igmp_snooping", resp.IGMPSnooping) d.Set("internet_access_enabled", resp.InternetAccessEnabled) d.Set("intra_network_access_enabled", resp.IntraNetworkAccessEnabled) d.Set("ipv6_interface_type", resp.IPV6InterfaceType) - d.Set("ipv6_pd_interface", resp.IPV6PDInterface) - d.Set("ipv6_pd_prefixid", resp.IPV6PDPrefixid) - d.Set("ipv6_pd_start", resp.IPV6PDStart) - d.Set("ipv6_pd_stop", resp.IPV6PDStop) - d.Set("ipv6_ra_enable", resp.IPV6RaEnabled) - d.Set("ipv6_ra_preferred_lifetime", resp.IPV6RaPreferredLifetime) - d.Set("ipv6_ra_priority", resp.IPV6RaPriority) - d.Set("ipv6_ra_valid_lifetime", resp.IPV6RaValidLifetime) - d.Set("ipv6_static_subnet", resp.IPV6Subnet) + + if resp.IPV6InterfaceType != "none" { + d.Set("dhcp_v6_dns_auto", resp.DHCPDV6DNSAuto) + d.Set("dhcp_v6_dns", dhcpV6DNS) + d.Set("dhcp_v6_enabled", resp.DHCPDV6Enabled) + d.Set("dhcp_v6_lease", resp.DHCPDV6LeaseTime) + d.Set("dhcp_v6_start", resp.DHCPDV6Start) + d.Set("dhcp_v6_stop", resp.DHCPDV6Stop) + d.Set("ipv6_ra_enabled", resp.IPV6RaEnabled) + d.Set("ipv6_ra_preferred_lifetime", resp.IPV6RaPreferredLifetime) + d.Set("ipv6_ra_priority", resp.IPV6RaPriority) + d.Set("ipv6_ra_valid_lifetime", resp.IPV6RaValidLifetime) + } + + if resp.IPV6InterfaceType == "pd" { + d.Set("ipv6_pd_interface", resp.IPV6PDInterface) + d.Set("ipv6_pd_prefixid", resp.IPV6PDPrefixid) + d.Set("ipv6_pd_start", resp.IPV6PDStart) + d.Set("ipv6_pd_stop", resp.IPV6PDStop) + } + + if resp.IPV6InterfaceType == "static" { + d.Set("ipv6_static_subnet", resp.IPV6Subnet) + } + d.Set("multicast_dns", resp.MdnsEnabled) d.Set("wan_dhcp_v6_pd_size", resp.WANDHCPv6PDSize) d.Set("wan_dns", wanDNS) diff --git a/internal/provider/resource_network_test.go b/internal/provider/resource_network_test.go index 7dfd97d75..4d39c7bc8 100644 --- a/internal/provider/resource_network_test.go +++ b/internal/provider/resource_network_test.go @@ -514,7 +514,7 @@ resource "unifi_network" "test" { ipv6_interface_type = "%[4]s" ipv6_static_subnet = "%[5]s" - ipv6_ra_enable = true + ipv6_ra_enabled = true } `, name, subnet, vlan, ipv6Type, ipv6Subnet) }