From f653ca03d90395e9b3e1df0e1147db9c57c08b73 Mon Sep 17 00:00:00 2001 From: Paul Tyng Date: Sun, 23 Oct 2022 09:00:07 -0400 Subject: [PATCH] Update schedule support for typed API field (#284) * Test removing schedule * Use new schedule API field * fix attribute name * Bump go-unifi --- docs/resources/network.md | 6 +- docs/resources/wlan.md | 9 +- go.mod | 4 +- go.sum | 4 +- internal/provider/resource_wlan.go | 111 ++++++++++++------------ internal/provider/resource_wlan_test.go | 30 ++++++- internal/provider/time.go | 27 ------ 7 files changed, 95 insertions(+), 96 deletions(-) delete mode 100644 internal/provider/time.go diff --git a/docs/resources/network.md b/docs/resources/network.md index 2fe3917..16c1be1 100644 --- a/docs/resources/network.md +++ b/docs/resources/network.md @@ -53,14 +53,14 @@ resource "unifi_network" "wan" { - `dhcp_dns` (List of String) Specifies the IPv4 addresses for the DNS server to be returned from the DHCP server. Leave blank to disable this feature. - `dhcp_enabled` (Boolean) Specifies whether DHCP is enabled or not on this network. -- `dhcp_lease` (Number) Specifies the lease time for DHCP addresses. Defaults to `86400`. +- `dhcp_lease` (Number) Specifies the lease time for DHCP addresses in seconds. Defaults to `86400`. - `dhcp_relay_enabled` (Boolean) Specifies whether DHCP relay is enabled or not on this network. - `dhcp_start` (String) The IPv4 address where the DHCP range of addresses starts. - `dhcp_stop` (String) The IPv4 address where the DHCP range of addresses stops. - `dhcp_v6_dns` (List of String) Specifies the IPv6 addresses for the DNS server to be returned from the DHCP server. Used if `dhcp_v6_dns_auto` is set to `false`. - `dhcp_v6_dns_auto` (Boolean) Specifies DNS source to propagate. If set `false` the entries in `dhcp_v6_dns` are used, the upstream entries otherwise Defaults to `true`. - `dhcp_v6_enabled` (Boolean) Enable stateful DHCPv6 for static configuration. -- `dhcp_v6_lease` (Number) Specifies the lease time for DHCPv6 addresses. Defaults to `86400`. +- `dhcp_v6_lease` (Number) Specifies the lease time for DHCPv6 addresses in seconds. Defaults to `86400`. - `dhcp_v6_start` (String) Start address of the DHCPv6 range. Used in static DHCPv6 configuration. - `dhcp_v6_stop` (String) End address of the DHCPv6 range. Used in static DHCPv6 configuration. - `dhcpd_boot_enabled` (Boolean) Toggles on the DHCP boot options. Should be set to true when you want to have dhcpd_boot_filename, and dhcpd_boot_server to take effect. @@ -78,7 +78,7 @@ resource "unifi_network" "wan" { - `ipv6_ra_enable` (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 adress can be used. Must be equal to or greater than `ipv6_ra_preferred_lifetime`. Defaults to `86400`. +- `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`. - `ipv6_static_subnet` (String) Specifies the static IPv6 subnet when `ipv6_interface_type` is 'static'. - `network_group` (String) The group of the network. Defaults to `LAN`. - `site` (String) The name of the site to associate the network with. diff --git a/docs/resources/wlan.md b/docs/resources/wlan.md index 8e27a20..1e21319 100644 --- a/docs/resources/wlan.md +++ b/docs/resources/wlan.md @@ -92,9 +92,14 @@ resource "unifi_wlan" "wifi" { Required: -- `block_end` (String) Time of day to end the block. -- `block_start` (String) Time of day to start the block. - `day_of_week` (String) Day of week for the block. Valid values are `sun`, `mon`, `tue`, `wed`, `thu`, `fri`, `sat`. +- `duration` (Number) Length of the block in minutes. +- `start_hour` (Number) Start hour for the block (0-23). + +Optional: + +- `name` (String) Name of the block. +- `start_minute` (Number) Start minute for the block (0-59). Defaults to `0`. ## Import diff --git a/go.mod b/go.mod index 65cfd3a..b189c9b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/paultyng/terraform-provider-unifi -go 1.18 +go 1.19 // replace github.com/paultyng/go-unifi => ../go-unifi // replace github.com/hashicorp/terraform-plugin-docs => ../../hashicorp/terraform-plugin-docs @@ -10,7 +10,7 @@ require ( github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/terraform-plugin-docs v0.13.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 - github.com/paultyng/go-unifi v1.27.0 + github.com/paultyng/go-unifi v1.28.0 ) require ( diff --git a/go.sum b/go.sum index 320eb06..0014569 100644 --- a/go.sum +++ b/go.sum @@ -207,8 +207,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/paultyng/go-unifi v1.27.0 h1:rCh3LgSDLfsYnlH67VWTN+j0lPCqM0bgSG0wYevPAuI= -github.com/paultyng/go-unifi v1.27.0/go.mod h1:X8D1nofAy/G171iLaId4TRkO/UApbkEMTR97o6ECgcg= +github.com/paultyng/go-unifi v1.28.0 h1:MeDgwVjWowysDwDesKdhOYMwcGTk1JfANyeSRSh4e6I= +github.com/paultyng/go-unifi v1.28.0/go.mod h1:X8D1nofAy/G171iLaId4TRkO/UApbkEMTR97o6ECgcg= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/internal/provider/resource_wlan.go b/internal/provider/resource_wlan.go index 888f3c2..db23776 100644 --- a/internal/provider/resource_wlan.go +++ b/internal/provider/resource_wlan.go @@ -3,8 +3,6 @@ package provider import ( "context" "fmt" - "log" - "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -137,19 +135,29 @@ func resourceWLAN() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice([]string{"sun", "mon", "tue", "wed", "thu", "fri", "sat", "sun"}, false), }, - "block_start": { - Description: "Time of day to start the block.", - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringMatch(timeOfDayRegexp, "Time of day is invalid"), - DiffSuppressFunc: timeOfDayDiffSuppress, + "start_hour": { + Description: "Start hour for the block (0-23).", + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 23), }, - "block_end": { - Description: "Time of day to end the block.", - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringMatch(timeOfDayRegexp, "Time of day is invalid"), - DiffSuppressFunc: timeOfDayDiffSuppress, + "start_minute": { + Description: "Start minute for the block (0-59).", + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 59), + }, + "duration": { + Description: "Length of the block in minutes.", + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "name": { + Description: "Name of the block.", + Type: schema.TypeString, + Optional: true, }, }, }, @@ -263,7 +271,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni } wlanBand := d.Get("wlan_band").(string) - schedule, err := listToScheduleStrings(d.Get("schedule").([]interface{})) + schedule, err := listToSchedules(d.Get("schedule").([]interface{})) if err != nil { return nil, fmt.Errorf("unable to process schedule block: %w", err) } @@ -293,7 +301,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni MACFilterList: macFilterList, MACFilterPolicy: d.Get("mac_filter_policy").(string), RADIUSProfileID: d.Get("radius_profile_id").(string), - Schedule: schedule, + ScheduleWithDuration: schedule, ScheduleEnabled: len(schedule) > 0, WLANBand: wlanBand, PMFMode: pmf, @@ -367,11 +375,7 @@ func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData, meta apGroupIDs := stringSliceToSet(resp.ApGroupIDs) - log.Printf("[TRACE] API Schedule: %#v", resp.Schedule) - schedule, err := listFromScheduleStrings(resp.Schedule) - if err != nil { - return diag.Errorf("unable to parse schedule: %s", err) - } + schedule := listFromSchedules(resp.ScheduleWithDuration) d.Set("site", site) d.Set("name", resp.Name) @@ -469,59 +473,54 @@ func resourceWLANDelete(ctx context.Context, d *schema.ResourceData, meta interf return diag.FromErr(err) } -func listToScheduleStrings(list []interface{}) ([]string, error) { - schedStrings := make([]string, 0, len(list)) +func listToSchedules(list []interface{}) ([]unifi.WLANScheduleWithDuration, error) { + schedules := make([]unifi.WLANScheduleWithDuration, 0, len(list)) for _, item := range list { data, ok := item.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected data in block") } - ss, err := toScheduleString(data) - if err != nil { - return nil, fmt.Errorf("unable to create schedule string: %w", err) - } - schedStrings = append(schedStrings, ss) + ss := toSchedule(data) + schedules = append(schedules, ss) } - return schedStrings, nil + return schedules, nil } -func toScheduleString(data map[string]interface{}) (string, error) { +func toSchedule(data map[string]interface{}) unifi.WLANScheduleWithDuration { // TODO: error check these? dow := data["day_of_week"].(string) - start := timeFromConfig(data["block_start"].(string)) - end := timeFromConfig(data["block_end"].(string)) + startHour := data["start_hour"].(int) + startMinute := data["start_minute"].(int) + duration := data["duration"].(int) + name := data["name"].(string) - return fmt.Sprintf("%s|%s-%s", dow, start, end), nil + return unifi.WLANScheduleWithDuration{ + StartDaysOfWeek: []string{dow}, + StartHour: startHour, + StartMinute: startMinute, + DurationMinutes: duration, + Name: name, + } } -func fromScheduleString(s string) (map[string]interface{}, error) { - parts := strings.Split(s, "|") - if len(parts) != 2 { - return nil, fmt.Errorf("malformed schedule string %q", s) - } - dow, times := parts[0], parts[1] - timeParts := strings.Split(times, "-") - if len(timeParts) != 2 { - return nil, fmt.Errorf("malformed schedule times %q", s) - } - - start, end := timeFromUnifi(timeParts[0]), timeFromUnifi(timeParts[1]) - +func fromSchedule(dow string, s unifi.WLANScheduleWithDuration) map[string]interface{} { return map[string]interface{}{ - "day_of_week": dow, - "block_start": start, - "block_end": end, - }, nil + "day_of_week": dow, + "start_hour": s.StartHour, + "start_minute": s.StartMinute, + "duration": s.DurationMinutes, + "name": s.Name, + } } -func listFromScheduleStrings(ss []string) ([]interface{}, error) { +func listFromSchedules(ss []unifi.WLANScheduleWithDuration) []interface{} { + // this explodes days of week lists in to individual schedules list := make([]interface{}, 0, len(ss)) for _, s := range ss { - v, err := fromScheduleString(s) - if err != nil { - return nil, fmt.Errorf("unable to parse schedule string %q: %w", s, err) + for _, dow := range s.StartDaysOfWeek { + v := fromSchedule(dow, s) + list = append(list, v) } - list = append(list, v) } - return list, nil + return list } diff --git a/internal/provider/resource_wlan_test.go b/internal/provider/resource_wlan_test.go index 6489308..7544ac3 100644 --- a/internal/provider/resource_wlan_test.go +++ b/internal/provider/resource_wlan_test.go @@ -179,6 +179,14 @@ func TestAccWLAN_schedule(t *testing.T) { ), }, importStep("unifi_wlan.test"), + // remove schedule + { + Config: testAccWLANConfig_open(vlanID), + Check: resource.ComposeTestCheckFunc( + // testCheckNetworkExists(t, "name"), + ), + }, + importStep("unifi_wlan.test"), }, }) } @@ -502,14 +510,28 @@ resource "unifi_wlan" "test" { schedule { day_of_week = "mon" - block_start = "03:00" - block_end = "9:00" + start_hour = 3 + duration = 60*6 } schedule { day_of_week = "wed" - block_start = "13:00" - block_end = "17:00" + start_hour = 13 + start_minute = 30 + duration = (60*3)+30 + name = "minute" + } + + schedule { + day_of_week = "thu" + start_hour = 19 + duration = 60*1 + } + + schedule { + day_of_week = "fri" + start_hour = 19 + duration = 60*1 } } `, vlanID) diff --git a/internal/provider/time.go b/internal/provider/time.go deleted file mode 100644 index 33d8d79..0000000 --- a/internal/provider/time.go +++ /dev/null @@ -1,27 +0,0 @@ -package provider - -import ( - "regexp" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var timeOfDayRegexp = regexp.MustCompile(`^\d{1,2}:\d{2}$`) - -func timeOfDayDiffSuppress(k, old, new string, d *schema.ResourceData) bool { - return timeFromConfig(old) == timeFromConfig(new) -} - -func timeFromConfig(t string) string { - if len(t) == 0 { - return "" - } - s := "0" + strings.ReplaceAll(t, ":", "") - return s[len(s)-4:] -} - -func timeFromUnifi(t string) string { - i := len(t) - 2 - return strings.TrimPrefix(t[0:i], "0") + ":" + t[i:] -}