feat: initialize Terraform Plugin Framework (#23)

* feat: initialize Terraform Plugin Framework

* fix docker-compose path for tests

* fix: ensure documentation can be generated with old provider SDK and new plugin framework

* lint
This commit is contained in:
Mateusz Filipowicz
2025-02-24 00:11:41 +01:00
committed by GitHub
parent ccde06a322
commit 325d7b7f20
91 changed files with 1005 additions and 705 deletions

View File

@@ -8,7 +8,7 @@ description: |-
# unifi_account (Data Source)
`unifi_account` data source can be used to retrieve RADIUS user accounts
unifi_account data source can be used to retrieve RADIUS user accounts
@@ -30,5 +30,3 @@ description: |-
- `password` (String, Sensitive) The password of the account.
- `tunnel_medium_type` (Number) See RFC2868 section 3.2
- `tunnel_type` (Number) See RFC2868 section 3.1

View File

@@ -28,5 +28,3 @@ data "unifi_ap_group" "default" {
### Read-Only
- `id` (String) The ID of this AP group.

View File

@@ -83,5 +83,3 @@ data "unifi_network" "my_network" {
- `wan_type_v6` (String) Specifies the IPV6 WAN connection type. Must be one of either `disabled`, `static`, or `dhcpv6`.
- `wan_username` (String) Specifies the IPV4 WAN username.
- `x_wan_password` (String) Specifies the IPV4 WAN password.

View File

@@ -28,5 +28,3 @@ data "unifi_port_profile" "all" {
### Read-Only
- `id` (String) The ID of this port profile.

View File

@@ -23,5 +23,3 @@ description: |-
### Read-Only
- `id` (String) The ID of this AP group.

View File

@@ -42,5 +42,3 @@ data "unifi_user" "client" {
- `network_id` (String) The network ID for this user.
- `note` (String) A note with additional information for the user.
- `user_group_id` (String) The user group ID for the user.

View File

@@ -25,5 +25,3 @@ description: |-
- `id` (String) The ID of this AP group.
- `qos_rate_max_down` (Number)
- `qos_rate_max_up` (Number)

View File

@@ -13,16 +13,14 @@ It is not recommended to use your own account for management of your controller.
Terraform is recommended. You can create a **Limited Admin** with **Local Access Only** and
provide that information for authentication. Two-factor authentication is not supported in the provider.
It is recommended to use API Key authentication, if you are on controller version 9.0.108 or higher.
## Example Usage
```terraform
provider "unifi" {
api_key = var.api_key # optionally use UNIFI_API_KEY env var
username = var.username # optionally use UNIFI_USERNAME env var
password = var.password # optionally use UNIFI_PASSWORD env var
api_url = var.api_url # optionally use UNIFI_API env var
api_key = var.api_key # optionally use UNIFI_API_KEY env var
api_url = var.api_url # optionally use UNIFI_API env var
# you may need to allow insecure TLS communications unless you have configured
# certificates for your controller
@@ -33,25 +31,14 @@ provider "unifi" {
}
```
### Obtaining an API Key
1. Open your Site in UniFi Site Manager
2. Click on Control Plane -> Admins & Users.
3. Select your Admin user.
4. Click Create API Key.
5. Add a name for your API Key.
6. Copy the key and store it securely, as it will only be displayed once.
7. Click Done to ensure the key is hashed and securely stored.
8. Use the API Key 🎉
<!-- schema generated by tfplugindocs -->
## Schema
### Optional
- `allow_insecure` (Boolean) Skip verification of TLS certificates of API requests. You may need to set this to `true` if you are using your local API without setting up a signed certificate. Can be specified with the `UNIFI_INSECURE` environment variable.
- `api_key` (String) API key for the user accessing the API. Can be specified with the `UNIFI_API_KEY` environment variable. Requires controller version 9.0.108 or higher and `username` and `password` to be empty
- `api_key` (String, Sensitive) API Key for the user accessing the API. Can be specified with the `UNIFI_API_KEY` environment variable. Controller version 9.0.108 or later is required.
- `api_url` (String) URL of the controller API. Can be specified with the `UNIFI_API` environment variable. You should **NOT** supply the path (`/api`), the SDK will discover the appropriate paths. This is to support UDM Pro style API paths as well as more standard controller paths.
- `password` (String) Password for the user accessing the API. Can be specified with the `UNIFI_PASSWORD` environment variable.
- `password` (String, Sensitive) Password for the user accessing the API. Can be specified with the `UNIFI_PASSWORD` environment variable.
- `site` (String) The site in the Unifi controller this provider will manage. Can be specified with the `UNIFI_SITE` environment variable. Default: `default`
- `username` (String) Local user name for the Unifi controller API. Can be specified with the `UNIFI_USERNAME` environment variable.

View File

@@ -41,5 +41,3 @@ NOTE: MAC-based authentication accounts can only be used for wireless and wired
### Read-Only
- `id` (String) The ID of the account.

View File

@@ -90,6 +90,5 @@ Optional:
- `aggregate_num_ports` (Number) Number of ports in the aggregate.
- `name` (String) Human-readable name of the port.
- `op_mode` (String) Operating mode of the port, valid values are `switch`, `mirror`, and `aggregate`. Defaults to `switch`.
- `poe_mode` (String) PoE mode of the port; valid values are `auto`, `pasv24`, `passthrough`, and `off`.
- `port_profile_id` (String) ID of the Port Profile used on this port.

View File

@@ -43,5 +43,3 @@ resource "unifi_dynamic_dns" "test" {
### Read-Only
- `id` (String) The ID of the dynamic DNS.

View File

@@ -41,5 +41,3 @@ resource "unifi_firewall_group" "can_print" {
### Read-Only
- `id` (String) The ID of the firewall group.

View File

@@ -67,9 +67,9 @@ resource "unifi_network" "wan" {
- `dhcpd_boot_filename` (String) Specifies the file to PXE boot from on the dhcpd_boot_server.
- `dhcpd_boot_server` (String) Specifies the IPv4 address of a TFTP server to network boot from.
- `domain_name` (String) The domain name of this network.
- `enabled` (Boolean) Specifies whether this network is enabled or not. Defaults to `true`.
- `igmp_snooping` (Boolean) Specifies whether IGMP snooping is enabled or not.
- `internet_access_enabled` (Boolean) Specifies whether this network should be allowed to access the internet or not. Defaults to `true`.
- `intra_network_access_enabled` (Boolean) Specifies whether this network should be allowed to access other local networks or not. Defaults to `true`.
- `ipv6_interface_type` (String) Specifies which type of IPv6 connection to use. Must be one of either `static`, `pd`, or `none`. Defaults to `none`.
- `ipv6_pd_interface` (String) Specifies which WAN interface to use for IPv6 PD. Must be one of either `wan` or `wan2`.
- `ipv6_pd_prefixid` (String) Specifies the IPv6 Prefix ID.
@@ -82,6 +82,7 @@ resource "unifi_network" "wan" {
- `ipv6_static_subnet` (String) Specifies the static IPv6 subnet when `ipv6_interface_type` is 'static'.
- `multicast_dns` (Boolean) Specifies whether Multicast DNS (mDNS) is enabled or not on the network (Controller >=v7).
- `network_group` (String) The group of the network. Defaults to `LAN`.
- `network_isolation_enabled` (Boolean) Specifies whether this network should be isolated from other networks or not. Defaults to `false`.
- `site` (String) The name of the site to associate the network with.
- `subnet` (String) The subnet of the network. Must be a valid CIDR address.
- `vlan_id` (Number) The VLAN ID of the network.

View File

@@ -31,5 +31,3 @@ description: |-
### Read-Only
- `id` (String) The ID of the port forwarding rule.

View File

@@ -46,6 +46,7 @@ resource "unifi_port_profile" "poe_disabled" {
- `dot1x_idle_timeout` (Number) The timeout, in seconds, to use when using the MAC Based 802.1X control. Can be between 0 and 65535 Defaults to `300`.
- `egress_rate_limit_kbps` (Number) The egress rate limit, in kpbs, for the port profile. Can be between `64` and `9999999`.
- `egress_rate_limit_kbps_enabled` (Boolean) Enable egress rate limiting for the port profile. Defaults to `false`.
- `excluded_network_ids` (Set of String) List of network IDs to exclude on the port profile when forward is set to customize.
- `forward` (String) The type forwarding to use for the port profile. Can be `all`, `native`, `customize` or `disabled`. Defaults to `native`.
- `full_duplex` (Boolean) Enable full duplex for the port profile. Defaults to `false`.
- `isolation` (Boolean) Enable port isolation for the port profile. Defaults to `false`.
@@ -62,7 +63,7 @@ resource "unifi_port_profile" "poe_disabled" {
- `priority_queue3_level` (Number) The priority queue 3 level for the port profile. Can be between 0 and 100.
- `priority_queue4_level` (Number) The priority queue 4 level for the port profile. Can be between 0 and 100.
- `site` (String) The name of the site to associate the port profile with.
- `speed` (Number) The link speed to set for the port profile. Can be one of `10`, `100`, `1000`, `2500`, `5000`, `10000`, `20000`, `25000`, `40000`, `50000` or `100000`
- `speed` (Number) The link speed to set for the port profile in Mbps. Can be one of `10`, `100`, `1000`, `2500`, `5000`, `10000`, `20000`, `25000`, `40000`, `50000` or `100000`. When `autoneg` is true, this setting is ignored.
- `stormctrl_bcast_enabled` (Boolean) Enable broadcast Storm Control for the port profile. Defaults to `false`.
- `stormctrl_bcast_level` (Number) The broadcast Storm Control level for the port profile. Can be between 0 and 100.
- `stormctrl_bcast_rate` (Number) The broadcast Storm Control rate for the port profile. Can be between 0 and 14880000.
@@ -74,11 +75,9 @@ resource "unifi_port_profile" "poe_disabled" {
- `stormctrl_ucast_level` (Number) The unknown unicast Storm Control level for the port profile. Can be between 0 and 100.
- `stormctrl_ucast_rate` (Number) The unknown unicast Storm Control rate for the port profile. Can be between 0 and 14880000.
- `stp_port_mode` (Boolean) Enable spanning tree protocol on the port profile. Defaults to `true`.
- `tagged_networkconf_ids` (Set of String) The IDs of networks to tag traffic with for the port profile.
- `tagged_vlan_mgmt` (String) The VLAN management type for the port profile. Can be one of 'auto', 'block_all', or 'custom'.
- `voice_networkconf_id` (String) The ID of network to use as the voice network on the port profile.
### Read-Only
- `id` (String) The ID of the port profile.

View File

@@ -60,5 +60,3 @@ Required:
Optional:
- `port` (Number) Port of authentication service. Defaults to `1812`.

View File

@@ -49,5 +49,3 @@ Optional:
- `comment` (String) Comment.
- `key` (String) Public SSH key.

View File

@@ -29,5 +29,3 @@ description: |-
### Read-Only
- `id` (String) The ID of the settings.

View File

@@ -18,14 +18,9 @@ description: |-
### Optional
- `dhcp_relay_servers` (List of String) The DHCP relay servers.
- `firewall_guest_default_log` (Boolean) Whether the guest firewall log is enabled.
- `firewall_lan_default_log` (Boolean) Whether the LAN firewall log is enabled.
- `firewall_wan_default_log` (Boolean) Whether the WAN firewall log is enabled.
- `multicast_dns_enabled` (Boolean) Whether multicast DNS is enabled.
- `site` (String) The name of the site to associate the settings with.
### Read-Only
- `id` (String) The ID of the settings.

View File

@@ -56,5 +56,3 @@ resource "unifi_static_route" "interface" {
### Read-Only
- `id` (String) The ID of the static route.

View File

@@ -52,5 +52,3 @@ resource "unifi_user" "test" {
- `hostname` (String) The hostname of the user.
- `id` (String) The ID of the user.
- `ip` (String) The IP address of the user.

View File

@@ -55,7 +55,7 @@ resource "unifi_wlan" "wifi" {
### Required
- `name` (String) The SSID of the network.
- `name` (String) The SSID of the network. SSID length must be between 1 and 32 characters.
- `security` (String) The type of WiFi security for this network. Valid values are: `wpapsk`, `wpaeap`, and `open`.
- `user_group_id` (String) ID of the user group to use for this network.

3
go.mod
View File

@@ -193,8 +193,11 @@ require (
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.22.0 // indirect
github.com/hashicorp/terraform-json v0.24.0 // indirect
github.com/hashicorp/terraform-plugin-framework v1.14.1 // indirect
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
github.com/hashicorp/terraform-plugin-mux v0.18.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.4 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect

6
go.sum
View File

@@ -492,10 +492,16 @@ github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4
github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow=
github.com/hashicorp/terraform-plugin-docs v0.20.1 h1:Fq7E/HrU8kuZu3hNliZGwloFWSYfWEOWnylFhYQIoys=
github.com/hashicorp/terraform-plugin-docs v0.20.1/go.mod h1:Yz6HoK7/EgzSrHPB9J/lWFzwl9/xep2OPnc5jaJDV90=
github.com/hashicorp/terraform-plugin-framework v1.14.1 h1:jaT1yvU/kEKEsxnbrn4ZHlgcxyIfjvZ41BLdlLk52fY=
github.com/hashicorp/terraform-plugin-framework v1.14.1/go.mod h1:xNUKmvTs6ldbwTuId5euAtg37dTxuyj3LHS3uj7BHQ4=
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0 h1:0uYQcqqgW3BMyyve07WJgpKorXST3zkpzvrOnf3mpbg=
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0/go.mod h1:VwdfgE/5Zxm43flraNa0VjcvKQOGVrcO4X8peIri0T0=
github.com/hashicorp/terraform-plugin-go v0.26.0 h1:cuIzCv4qwigug3OS7iKhpGAbZTiypAfFQmw8aE65O2M=
github.com/hashicorp/terraform-plugin-go v0.26.0/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-mux v0.18.0 h1:7491JFSpWyAe0v9YqBT+kel7mzHAbO5EpxxT0cUL/Ms=
github.com/hashicorp/terraform-plugin-mux v0.18.0/go.mod h1:Ho1g4Rr8qv0qTJlcRKfjjXTIO67LNbDtM6r+zHUNHJQ=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 h1:WNMsTLkZf/3ydlgsuXePa3jvZFwAJhruxTxP/c1Viuw=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1/go.mod h1:P6o64QS97plG44iFzSM6rAn6VJIC/Sy9a9IkEtl79K4=
github.com/hashicorp/terraform-plugin-testing v1.11.0 h1:MeDT5W3YHbONJt2aPQyaBsgQeAIckwPX41EUHXEn29A=

View File

@@ -1,56 +0,0 @@
package provider
import (
"fmt"
"net"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func cidrValidate(raw interface{}, key string) ([]string, []error) {
v, ok := raw.(string)
if !ok {
return nil, []error{fmt.Errorf("expected string, got %T", raw)}
}
_, _, err := net.ParseCIDR(v)
if err != nil {
return nil, []error{err}
}
return nil, nil
}
func cidrDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
_, oldNet, err := net.ParseCIDR(old)
if err != nil {
return false
}
_, newNet, err := net.ParseCIDR(new)
if err != nil {
return false
}
return oldNet.String() == newNet.String()
}
func cidrZeroBased(cidr string) string {
_, cidrNet, err := net.ParseCIDR(cidr)
if err != nil {
return ""
}
return cidrNet.String()
}
func cidrOneBased(cidr string) string {
_, cidrNet, err := net.ParseCIDR(cidr)
if err != nil {
return ""
}
cidrNet.IP[3]++
return cidrNet.String()
}

View File

@@ -0,0 +1,78 @@
package provider
import (
"errors"
"fmt"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/go-version"
"log"
"net/http"
"strings"
)
func IsServerErrorContains(err error, messageContains string) bool {
if err == nil {
return false
}
var se *unifi.ServerError
if errors.As(err, &se) {
if strings.Contains(se.Message, messageContains) {
return true
}
// check details
if se.Details != nil {
for _, m := range se.Details {
if strings.Contains(m.Message, messageContains) {
return true
}
}
}
}
return false
}
type ClientConfig struct {
Username string
Password string
ApiKey string
Url string
Site string
Insecure bool
HttpConfigurer func() http.RoundTripper
}
func NewClient(cfg *ClientConfig) (*Client, error) {
unifiClient, err := unifi.NewClient(&unifi.ClientConfig{
URL: cfg.Url,
User: cfg.Username,
Password: cfg.Password,
APIKey: cfg.ApiKey,
HttpRoundTripperProvider: cfg.HttpConfigurer,
ValidationMode: unifi.DisableValidation,
Logger: unifi.NewDefaultLogger(unifi.WarnLevel),
})
if err != nil {
return nil, err
}
err = CheckMinimumControllerVersion(unifiClient.Version())
log.Printf("[TRACE] Unifi controller version: %q", unifiClient.Version())
if err != nil {
return nil, err
}
c := &Client{
Client: unifiClient,
Site: cfg.Site,
Version: version.Must(version.NewVersion(unifiClient.Version())),
}
if cfg.ApiKey != "" && !c.SupportsApiKeyAuthentication() {
return nil, fmt.Errorf("API key authentication is not supported on this controller version: %s, you must be on %s or higher", c.Version, ControllerVersionApiKeyAuth)
}
return c, nil
}
type Client struct {
unifi.Client
Site string
Version *version.Version
}

View File

@@ -11,37 +11,37 @@ func asVersion(versionString string) *version.Version {
}
var (
controllerV6 = asVersion("6.0.0")
controllerV7 = asVersion("7.0.0")
controllerVersionApiKeyAuth = asVersion("9.0.108")
ControllerV6 = asVersion("6.0.0")
ControllerV7 = asVersion("7.0.0")
ControllerVersionApiKeyAuth = asVersion("9.0.108")
// https://community.ui.com/releases/UniFi-Network-Controller-6-1-61/62f1ad38-1ac5-430c-94b0-becbb8f71d7d
controllerVersionWPA3 = asVersion("6.1.61")
ControllerVersionWPA3 = asVersion("6.1.61")
)
func (c *client) IsControllerV6() bool {
return c.version.GreaterThanOrEqual(controllerV6)
func (c *Client) IsControllerV6() bool {
return c.Version.GreaterThanOrEqual(ControllerV6)
}
func (c *client) IsControllerV7() bool {
return c.version.GreaterThanOrEqual(controllerV7)
func (c *Client) IsControllerV7() bool {
return c.Version.GreaterThanOrEqual(ControllerV7)
}
func (c *client) SupportsApiKeyAuthentication() bool {
return c.version.GreaterThanOrEqual(controllerVersionApiKeyAuth)
func (c *Client) SupportsApiKeyAuthentication() bool {
return c.Version.GreaterThanOrEqual(ControllerVersionApiKeyAuth)
}
func (c *client) SupportsWPA3() bool {
return c.version.GreaterThanOrEqual(controllerVersionWPA3)
func (c *Client) SupportsWPA3() bool {
return c.Version.GreaterThanOrEqual(ControllerVersionWPA3)
}
func checkMinimumControllerVersion(versionString string) error {
func CheckMinimumControllerVersion(versionString string) error {
v, err := version.NewVersion(versionString)
if err != nil {
return err
}
if v.LessThan(controllerV6) {
return fmt.Errorf("Controller version %q or greater is required to use the provider, found %q.", controllerV6, v)
if v.LessThan(ControllerV6) {
return fmt.Errorf("Controller version %q or greater is required to use the provider, found %q.", ControllerV6, v)
}
return nil
}

View File

@@ -1,216 +1,13 @@
package provider
import (
"context"
"crypto/tls"
"errors"
"fmt"
"github.com/hashicorp/go-version"
"log"
"net"
"net/http"
"strings"
"time"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
const (
ProviderUsernameDescription = "Local user name for the Unifi controller API. Can be specified with the `UNIFI_USERNAME` environment variable."
ProviderPasswordDescription = "Password for the user accessing the API. Can be specified with the `UNIFI_PASSWORD` environment variable."
ProviderAPIKeyDescription = "API Key for the user accessing the API. Can be specified with the `UNIFI_API_KEY` environment variable. Controller version 9.0.108 or later is required."
ProviderAPIURLDescription = "URL of the controller API. Can be specified with the `UNIFI_API` environment variable. " +
"You should **NOT** supply the path (`/api`), the SDK will discover the appropriate paths. This is to support UDM Pro style API paths as well as more standard controller paths."
ProviderSiteDescription = "The site in the Unifi controller this provider will manage. Can be specified with the `UNIFI_SITE` environment variable. Default: `default`"
ProviderAllowInsecureDescription = "Skip verification of TLS certificates of API requests. You may need to set this to `true` " +
"if you are using your local API without setting up a signed certificate. Can be specified with the " +
"`UNIFI_INSECURE` environment variable."
)
func init() {
schema.DescriptionKind = schema.StringMarkdown
schema.SchemaDescriptionBuilder = func(s *schema.Schema) string {
desc := s.Description
if s.Default != nil {
desc += fmt.Sprintf(" Defaults to `%v`.", s.Default)
}
if s.Deprecated != "" {
desc += " " + s.Deprecated
}
return strings.TrimSpace(desc)
}
}
func New(version string) func() *schema.Provider {
return func() *schema.Provider {
p := &schema.Provider{
Schema: map[string]*schema.Schema{
"username": {
Description: "Local user name for the Unifi controller API. Can be specified with the `UNIFI_USERNAME` " +
"environment variable.",
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_USERNAME", ""),
},
"password": {
Description: "Password for the user accessing the API. Can be specified with the `UNIFI_PASSWORD` " +
"environment variable.",
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_PASSWORD", ""),
},
"api_key": {
Description: "API Key for the user accessing the API. Can be specified with the `UNIFI_API_KEY` " +
"environment variable. Controller version 9.0.108 or later is required.",
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API_KEY", ""),
},
"api_url": {
Description: "URL of the controller API. Can be specified with the `UNIFI_API` environment variable. " +
"You should **NOT** supply the path (`/api`), the SDK will discover the appropriate paths. This is " +
"to support UDM Pro style API paths as well as more standard controller paths.",
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API", ""),
},
"site": {
Description: "The site in the Unifi controller this provider will manage. Can be specified with " +
"the `UNIFI_SITE` environment variable. Default: `default`",
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_SITE", "default"),
},
"allow_insecure": {
Description: "Skip verification of TLS certificates of API requests. You may need to set this to `true` " +
"if you are using your local API without setting up a signed certificate. Can be specified with the " +
"`UNIFI_INSECURE` environment variable.",
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_INSECURE", false),
},
},
DataSourcesMap: map[string]*schema.Resource{
"unifi_ap_group": dataAPGroup(),
"unifi_network": dataNetwork(),
"unifi_port_profile": dataPortProfile(),
"unifi_radius_profile": dataRADIUSProfile(),
"unifi_user_group": dataUserGroup(),
"unifi_user": dataUser(),
"unifi_account": dataAccount(),
},
ResourcesMap: map[string]*schema.Resource{
// TODO: "unifi_ap_group"
"unifi_device": resourceDevice(),
"unifi_dynamic_dns": resourceDynamicDNS(),
"unifi_firewall_group": resourceFirewallGroup(),
"unifi_firewall_rule": resourceFirewallRule(),
"unifi_network": resourceNetwork(),
"unifi_port_forward": resourcePortForward(),
"unifi_port_profile": resourcePortProfile(),
"unifi_radius_profile": resourceRadiusProfile(),
"unifi_site": resourceSite(),
"unifi_static_route": resourceStaticRoute(),
"unifi_user_group": resourceUserGroup(),
"unifi_user": resourceUser(),
"unifi_wlan": resourceWLAN(),
"unifi_account": resourceAccount(),
"unifi_setting_mgmt": resourceSettingMgmt(),
"unifi_setting_radius": resourceSettingRadius(),
"unifi_setting_usg": resourceSettingUsg(),
},
}
p.ConfigureContextFunc = configure(version, p)
return p
}
}
func createHTTPTransport(insecure bool, subsystem string) http.RoundTripper {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
}
t := logging.NewSubsystemLoggingHTTPTransport(subsystem, transport)
return t
}
func configure(v string, p *schema.Provider) schema.ConfigureContextFunc {
return func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
user := d.Get("username").(string)
pass := d.Get("password").(string)
apiKey := d.Get("api_key").(string)
if apiKey != "" && (user != "" || pass != "") {
return nil, diag.FromErr(errors.New("only one of `username`/`password` or `api_key` can be set"))
} else if apiKey == "" && (user == "" || pass == "") {
return nil, diag.FromErr(errors.New("either `username` and `password` or `api_key` must be set"))
}
baseURL := d.Get("api_url").(string)
site := d.Get("site").(string)
insecure := d.Get("allow_insecure").(bool)
unifiClient, err := unifi.NewClient(&unifi.ClientConfig{
URL: baseURL,
User: user,
Password: pass,
APIKey: apiKey,
HttpRoundTripperProvider: func() http.RoundTripper {
return createHTTPTransport(insecure, "unifi")
},
ValidationMode: unifi.DisableValidation,
Logger: unifi.NewDefaultLogger(unifi.WarnLevel),
})
if err != nil {
return nil, diag.FromErr(err)
}
err = checkMinimumControllerVersion(unifiClient.Version())
log.Printf("[TRACE] Unifi controller version: %q", unifiClient.Version())
if err != nil {
return nil, diag.FromErr(err)
}
c := &client{
c: unifiClient,
site: site,
version: version.Must(version.NewVersion(unifiClient.Version())),
}
if apiKey != "" && !c.SupportsApiKeyAuthentication() {
return nil, diag.FromErr(fmt.Errorf("API key authentication is not supported on this controller version: %s, you must be on %s or higher", c.version, controllerVersionApiKeyAuth))
}
return c, nil
}
}
func IsServerErrorContains(err error, messageContains string) bool {
if err == nil {
return false
}
var se *unifi.ServerError
if errors.As(err, &se) {
if strings.Contains(se.Message, messageContains) {
return true
}
// check details
if se.Details != nil {
for _, m := range se.Details {
if strings.Contains(m.Message, messageContains) {
return true
}
}
}
}
return false
}
type client struct {
c unifi.Client
site string
version *version.Version
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"testing"

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -9,7 +10,7 @@ import (
func dataAccount() *schema.Resource {
return &schema.Resource{
Description: "`unifi_account` data source can be used to retrieve RADIUS user accounts",
Description: "unifi_account data source can be used to retrieve RADIUS user accounts",
ReadContext: dataAccountRead,
@@ -57,15 +58,15 @@ func dataAccount() *schema.Resource {
}
func dataAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
name := d.Get("name").(string)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
accounts, err := c.c.ListAccount(ctx, site)
accounts, err := c.ListAccount(ctx, site)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -35,15 +36,15 @@ func dataAPGroup() *schema.Resource {
}
func dataAPGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
name := d.Get("name").(string)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
groups, err := c.c.ListAPGroup(ctx, site)
groups, err := c.ListAPGroup(ctx, site)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"testing"

View File

@@ -1,7 +1,9 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -279,19 +281,19 @@ func dataNetwork() *schema.Resource {
}
func dataNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
name := d.Get("name").(string)
site := d.Get("site").(string)
id := d.Get("id").(string)
if site == "" {
site = c.site
site = c.Site
}
if (name == "" && id == "") || (name != "" && id != "") {
return diag.Errorf("One of 'name' OR 'id' is required")
}
networks, err := c.c.ListNetwork(ctx, site)
networks, err := c.ListNetwork(ctx, site)
if err != nil {
return diag.FromErr(err)
}
@@ -327,7 +329,7 @@ func dataNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface
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", utils.CidrZeroBased(n.IPSubnet))
d.Set("network_group", n.NetworkGroup)
d.Set("dhcp_dns", dhcpDNS)
d.Set("dhcp_start", n.DHCPDStart)

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"testing"
"github.com/hashicorp/go-version"
@@ -14,7 +15,7 @@ func TestAccDataNetwork_byName(t *testing.T) {
if err != nil {
t.Fatalf("error parsing version: %s", err)
}
if v.LessThan(controllerV7) {
if v.LessThan(provider.ControllerV7) {
defaultName = "LAN"
}
@@ -41,7 +42,7 @@ func TestAccDataNetwork_byID(t *testing.T) {
if err != nil {
t.Fatalf("error parsing version: %s", err)
}
if v.LessThan(controllerV7) {
if v.LessThan(provider.ControllerV7) {
defaultName = "LAN"
}

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -36,15 +37,15 @@ func dataPortProfile() *schema.Resource {
}
func dataPortProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
name := d.Get("name").(string)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
groups, err := c.c.ListPortProfile(ctx, site)
groups, err := c.ListPortProfile(ctx, site)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"testing"

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -36,15 +37,15 @@ func dataRADIUSProfile() *schema.Resource {
}
func dataRADIUSProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
name := d.Get("name").(string)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
profiles, err := c.c.ListRADIUSProfile(ctx, site)
profiles, err := c.ListRADIUSProfile(ctx, site)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -91,20 +92,20 @@ func dataUser() *schema.Resource {
}
func dataUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
mac := d.Get("mac").(string)
macResp, err := c.c.GetUserByMAC(ctx, site, strings.ToLower(mac))
macResp, err := c.GetUserByMAC(ctx, site, strings.ToLower(mac))
if err != nil {
return diag.FromErr(err)
}
resp, err := c.c.GetUser(ctx, site, macResp.ID)
resp, err := c.GetUser(ctx, site, macResp.ID)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"context"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -45,15 +46,15 @@ func dataUserGroup() *schema.Resource {
}
func dataUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
name := d.Get("name").(string)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
groups, err := c.c.ListUserGroup(ctx, site)
groups, err := c.ListUserGroup(ctx, site)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"testing"

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"context"

View File

@@ -0,0 +1,20 @@
package v1
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"net"
)
func cidrDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
_, oldNet, err := net.ParseCIDR(old)
if err != nil {
return false
}
_, newNet, err := net.ParseCIDR(new)
if err != nil {
return false
}
return oldNet.String() == newNet.String()
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"context"

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
mapset "github.com/deckarep/golang-set/v2"

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"regexp"

View File

@@ -0,0 +1,165 @@
package v1
import (
"context"
"crypto/tls"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"net"
"net/http"
"strings"
"time"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func init() {
schema.DescriptionKind = schema.StringMarkdown
schema.SchemaDescriptionBuilder = func(s *schema.Schema) string {
desc := s.Description
if s.Default != nil {
desc += fmt.Sprintf(" Defaults to `%v`.", s.Default)
}
if s.Deprecated != "" {
desc += " " + s.Deprecated
}
return strings.TrimSpace(desc)
}
}
func New(version string) func() *schema.Provider {
return func() *schema.Provider {
p := &schema.Provider{
Schema: map[string]*schema.Schema{
"username": {
Description: provider.ProviderUsernameDescription,
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_USERNAME", ""),
},
"password": {
Description: provider.ProviderPasswordDescription,
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_PASSWORD", ""),
},
"api_key": {
Description: provider.ProviderAPIKeyDescription,
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API_KEY", ""),
},
"api_url": {
Description: provider.ProviderAPIURLDescription,
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API", ""),
},
"site": {
Description: provider.ProviderSiteDescription,
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_SITE", "default"),
},
"allow_insecure": {
Description: provider.ProviderAllowInsecureDescription,
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_INSECURE", false),
},
},
DataSourcesMap: map[string]*schema.Resource{
"unifi_ap_group": dataAPGroup(),
"unifi_network": dataNetwork(),
"unifi_port_profile": dataPortProfile(),
"unifi_radius_profile": dataRADIUSProfile(),
"unifi_user_group": dataUserGroup(),
"unifi_user": dataUser(),
"unifi_account": dataAccount(),
},
ResourcesMap: map[string]*schema.Resource{
// TODO: "unifi_ap_group"
"unifi_device": resourceDevice(),
"unifi_dynamic_dns": resourceDynamicDNS(),
"unifi_firewall_group": resourceFirewallGroup(),
"unifi_firewall_rule": resourceFirewallRule(),
"unifi_network": resourceNetwork(),
"unifi_port_forward": resourcePortForward(),
"unifi_port_profile": resourcePortProfile(),
"unifi_radius_profile": resourceRadiusProfile(),
"unifi_site": resourceSite(),
"unifi_static_route": resourceStaticRoute(),
"unifi_user_group": resourceUserGroup(),
"unifi_user": resourceUser(),
"unifi_wlan": resourceWLAN(),
"unifi_account": resourceAccount(),
"unifi_setting_mgmt": resourceSettingMgmt(),
"unifi_setting_radius": resourceSettingRadius(),
"unifi_setting_usg": resourceSettingUsg(),
},
}
p.ConfigureContextFunc = configure(version, p)
return p
}
}
func createHTTPTransport(insecure bool, subsystem string) http.RoundTripper {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
}
t := logging.NewSubsystemLoggingHTTPTransport(subsystem, transport)
return t
}
func configure(v string, p *schema.Provider) schema.ConfigureContextFunc {
return func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
user := d.Get("username").(string)
pass := d.Get("password").(string)
apiKey := d.Get("api_key").(string)
if apiKey != "" && (user != "" || pass != "") {
return nil, diag.FromErr(errors.New("only one of `username`/`password` or `api_key` can be set"))
} else if apiKey == "" && (user == "" || pass == "") {
return nil, diag.FromErr(errors.New("either `username` and `password` or `api_key` must be set"))
}
baseURL := d.Get("api_url").(string)
site := d.Get("site").(string)
insecure := d.Get("allow_insecure").(bool)
c, err := provider.NewClient(&provider.ClientConfig{
Username: user,
Password: pass,
ApiKey: apiKey,
Url: baseURL,
Site: site,
HttpConfigurer: func() http.RoundTripper {
return createHTTPTransport(insecure, "unifi")
},
})
if err != nil {
return nil, diag.FromErr(err)
}
return c, nil
}
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"bytes"
@@ -38,7 +38,7 @@ func TestMain(m *testing.M) {
}
func runAcceptanceTests(m *testing.M) int {
dc, err := compose.NewDockerCompose("../../docker-compose.yaml")
dc, err := compose.NewDockerCompose("../../../docker-compose.yaml")
if err != nil {
panic(err)
}

View File

@@ -1,8 +1,9 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -74,7 +75,7 @@ func resourceAccount() *schema.Resource {
}
func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceAccountGetResourceData(d)
if err != nil {
@@ -83,10 +84,10 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta int
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateAccount(ctx, site, req)
resp, err := c.CreateAccount(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -97,11 +98,11 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta int
}
func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req, err := resourceAccountGetResourceData(d)
@@ -112,7 +113,7 @@ func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta int
req.ID = d.Id()
req.SiteID = site
resp, err := c.c.UpdateAccount(ctx, site, req)
resp, err := c.UpdateAccount(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -121,16 +122,16 @@ func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta int
}
func resourceAccountDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
//name := d.Get("name").(string)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
id := d.Id()
err := c.c.DeleteAccount(ctx, site, id)
err := c.DeleteAccount(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}
@@ -138,16 +139,16 @@ func resourceAccountDelete(ctx context.Context, d *schema.ResourceData, meta int
}
func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetAccount(ctx, site, id)
resp, err := c.GetAccount(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,9 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"strconv"
"strings"
"time"
@@ -138,11 +139,11 @@ func resourceDevice() *schema.Resource {
}
func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
if colons := strings.Count(id, ":"); colons == 1 || colons == 6 {
@@ -154,7 +155,7 @@ func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta inte
if macAddressRegexp.MatchString(id) {
// look up id by mac
mac := cleanMAC(id)
device, err := c.c.GetDeviceByMAC(ctx, site, mac)
device, err := c.GetDeviceByMAC(ctx, site, mac)
if err != nil {
return nil, err
@@ -174,11 +175,11 @@ func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta inte
}
func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
mac := d.Get("mac").(string)
@@ -187,7 +188,7 @@ func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta inte
}
mac = cleanMAC(mac)
device, err := c.c.GetDeviceByMAC(ctx, site, mac)
device, err := c.GetDeviceByMAC(ctx, site, mac)
if device == nil {
return diag.Errorf("device not found using mac %q", mac)
@@ -201,7 +202,7 @@ func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta inte
return diag.Errorf("Device must be adopted before it can be managed")
}
err := c.c.AdoptDevice(ctx, site, mac)
err := c.AdoptDevice(ctx, site, mac)
if err != nil {
return diag.FromErr(err)
}
@@ -217,11 +218,11 @@ func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta inte
}
func resourceDeviceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req, err := resourceDeviceGetResourceData(d)
@@ -232,7 +233,7 @@ func resourceDeviceUpdate(ctx context.Context, d *schema.ResourceData, meta inte
req.ID = d.Id()
req.SiteID = site
resp, err := c.c.UpdateDevice(ctx, site, req)
resp, err := c.UpdateDevice(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -246,7 +247,7 @@ func resourceDeviceUpdate(ctx context.Context, d *schema.ResourceData, meta inte
}
func resourceDeviceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
if !d.Get("forget_on_destroy").(bool) {
return nil
@@ -256,10 +257,10 @@ func resourceDeviceDelete(ctx context.Context, d *schema.ResourceData, meta inte
mac := d.Get("mac").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.ForgetDevice(ctx, site, mac)
err := c.ForgetDevice(ctx, site, mac)
if err != nil {
return diag.FromErr(err)
}
@@ -273,16 +274,16 @@ func resourceDeviceDelete(ctx context.Context, d *schema.ResourceData, meta inte
}
func resourceDeviceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetDevice(ctx, site, id)
resp, err := c.GetDevice(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -388,13 +389,13 @@ func fromPortOverride(po unifi.DevicePortOverrides) (map[string]interface{}, err
}
func waitForDeviceState(ctx context.Context, d *schema.ResourceData, meta interface{}, targetState unifi.DeviceState, pendingStates []unifi.DeviceState, timeout time.Duration) (*unifi.Device, error) {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
mac := d.Get("mac").(string)
if site == "" {
site = c.site
site = c.Site
}
// Always consider unknown to be a pending state.
@@ -409,7 +410,7 @@ func waitForDeviceState(ctx context.Context, d *schema.ResourceData, meta interf
Pending: pending,
Target: []string{targetState.String()},
Refresh: func() (interface{}, string, error) {
device, err := c.c.GetDeviceByMAC(ctx, site, mac)
device, err := c.GetDeviceByMAC(ctx, site, mac)
if errors.Is(err, unifi.ErrNotFound) {
err = nil

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"context"

View File

@@ -1,8 +1,9 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -75,7 +76,7 @@ func resourceDynamicDNS() *schema.Resource {
}
func resourceDynamicDNSCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceDynamicDNSGetResourceData(d)
if err != nil {
@@ -84,10 +85,10 @@ func resourceDynamicDNSCreate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateDynamicDNS(ctx, site, req)
resp, err := c.CreateDynamicDNS(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -126,16 +127,16 @@ func resourceDynamicDNSSetResourceData(resp *unifi.DynamicDNS, d *schema.Resourc
}
func resourceDynamicDNSRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetDynamicDNS(ctx, site, id)
resp, err := c.GetDynamicDNS(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -148,7 +149,7 @@ func resourceDynamicDNSRead(ctx context.Context, d *schema.ResourceData, meta in
}
func resourceDynamicDNSUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceDynamicDNSGetResourceData(d)
if err != nil {
@@ -159,11 +160,11 @@ func resourceDynamicDNSUpdate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateDynamicDNS(ctx, site, req)
resp, err := c.UpdateDynamicDNS(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -172,15 +173,15 @@ func resourceDynamicDNSUpdate(ctx context.Context, d *schema.ResourceData, meta
}
func resourceDynamicDNSDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteDynamicDNS(ctx, site, id)
err := c.DeleteDynamicDNS(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"testing"

View File

@@ -1,8 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -57,7 +59,7 @@ func resourceFirewallGroup() *schema.Resource {
}
func resourceFirewallGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceFirewallGroupGetResourceData(d)
if err != nil {
@@ -66,12 +68,12 @@ func resourceFirewallGroupCreate(ctx context.Context, d *schema.ResourceData, me
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateFirewallGroup(ctx, site, req)
resp, err := c.CreateFirewallGroup(ctx, site, req)
if err != nil {
if IsServerErrorContains(err, "api.err.FirewallGroupExisted") {
if provider.IsServerErrorContains(err, "api.err.FirewallGroupExisted") {
return diag.Errorf("firewall groups must have unique names: %s", err)
}
return diag.FromErr(err)
@@ -83,7 +85,7 @@ func resourceFirewallGroupCreate(ctx context.Context, d *schema.ResourceData, me
}
func resourceFirewallGroupGetResourceData(d *schema.ResourceData) (*unifi.FirewallGroup, error) {
members, err := setToStringSlice(d.Get("members").(*schema.Set))
members, err := utils.SetToStringSlice(d.Get("members").(*schema.Set))
if err != nil {
return nil, err
}
@@ -99,22 +101,22 @@ func resourceFirewallGroupSetResourceData(resp *unifi.FirewallGroup, d *schema.R
d.Set("site", site)
d.Set("name", resp.Name)
d.Set("type", resp.GroupType)
d.Set("members", stringSliceToSet(resp.GroupMembers))
d.Set("members", utils.StringSliceToSet(resp.GroupMembers))
return nil
}
func resourceFirewallGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetFirewallGroup(ctx, site, id)
resp, err := c.GetFirewallGroup(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -127,7 +129,7 @@ func resourceFirewallGroupRead(ctx context.Context, d *schema.ResourceData, meta
}
func resourceFirewallGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceFirewallGroupGetResourceData(d)
if err != nil {
@@ -138,11 +140,11 @@ func resourceFirewallGroupUpdate(ctx context.Context, d *schema.ResourceData, me
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateFirewallGroup(ctx, site, req)
resp, err := c.UpdateFirewallGroup(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -151,16 +153,16 @@ func resourceFirewallGroupUpdate(ctx context.Context, d *schema.ResourceData, me
}
func resourceFirewallGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteFirewallGroup(ctx, site, id)
err := c.DeleteFirewallGroup(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,8 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"regexp"
"github.com/filipowm/go-unifi/unifi"
@@ -210,7 +212,7 @@ func resourceFirewallRule() *schema.Resource {
}
func resourceFirewallRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceFirewallRuleGetResourceData(d)
if err != nil {
@@ -219,12 +221,12 @@ func resourceFirewallRuleCreate(ctx context.Context, d *schema.ResourceData, met
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateFirewallRule(ctx, site, req)
resp, err := c.CreateFirewallRule(ctx, site, req)
if err != nil {
if IsServerErrorContains(err, "api.err.FirewallGroupTypeExists") {
if provider.IsServerErrorContains(err, "api.err.FirewallGroupTypeExists") {
return diag.Errorf("firewall rule groups must be of different group types (ie. a port group and address group): %s", err)
}
@@ -237,12 +239,12 @@ func resourceFirewallRuleCreate(ctx context.Context, d *schema.ResourceData, met
}
func resourceFirewallRuleGetResourceData(d *schema.ResourceData) (*unifi.FirewallRule, error) {
srcFirewallGroupIDs, err := setToStringSlice(d.Get("src_firewall_group_ids").(*schema.Set))
srcFirewallGroupIDs, err := utils.SetToStringSlice(d.Get("src_firewall_group_ids").(*schema.Set))
if err != nil {
return nil, err
}
dstFirewallGroupIDs, err := setToStringSlice(d.Get("dst_firewall_group_ids").(*schema.Set))
dstFirewallGroupIDs, err := utils.SetToStringSlice(d.Get("dst_firewall_group_ids").(*schema.Set))
if err != nil {
return nil, err
}
@@ -300,7 +302,7 @@ func resourceFirewallRuleSetResourceData(resp *unifi.FirewallRule, d *schema.Res
d.Set("state_related", resp.StateRelated)
d.Set("src_network_type", resp.SrcNetworkType)
d.Set("src_firewall_group_ids", stringSliceToSet(resp.SrcFirewallGroupIDs))
d.Set("src_firewall_group_ids", utils.StringSliceToSet(resp.SrcFirewallGroupIDs))
d.Set("src_mac", resp.SrcMACAddress)
d.Set("src_address", resp.SrcAddress)
d.Set("src_address_ipv6", resp.SrcAddressIPV6)
@@ -308,7 +310,7 @@ func resourceFirewallRuleSetResourceData(resp *unifi.FirewallRule, d *schema.Res
d.Set("src_port", resp.SrcPort)
d.Set("dst_network_type", resp.DstNetworkType)
d.Set("dst_firewall_group_ids", stringSliceToSet(resp.DstFirewallGroupIDs))
d.Set("dst_firewall_group_ids", utils.StringSliceToSet(resp.DstFirewallGroupIDs))
d.Set("dst_address", resp.DstAddress)
d.Set("dst_address_ipv6", resp.DstAddressIPV6)
d.Set("dst_network_id", resp.DstNetworkID)
@@ -318,16 +320,16 @@ func resourceFirewallRuleSetResourceData(resp *unifi.FirewallRule, d *schema.Res
}
func resourceFirewallRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetFirewallRule(ctx, site, id)
resp, err := c.GetFirewallRule(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -340,7 +342,7 @@ func resourceFirewallRuleRead(ctx context.Context, d *schema.ResourceData, meta
}
func resourceFirewallRuleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceFirewallRuleGetResourceData(d)
if err != nil {
@@ -351,11 +353,11 @@ func resourceFirewallRuleUpdate(ctx context.Context, d *schema.ResourceData, met
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateFirewallRule(ctx, site, req)
resp, err := c.UpdateFirewallRule(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -364,15 +366,15 @@ func resourceFirewallRuleUpdate(ctx context.Context, d *schema.ResourceData, met
}
func resourceFirewallRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteFirewallRule(ctx, site, id)
err := c.DeleteFirewallRule(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,9 +1,11 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"regexp"
"strings"
@@ -90,7 +92,7 @@ func resourceNetwork() *schema.Resource {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: cidrDiffSuppress,
ValidateFunc: cidrValidate,
ValidateFunc: utils.CidrValidate,
},
"network_group": {
Description: "The group of the network.",
@@ -382,7 +384,7 @@ func resourceNetwork() *schema.Resource {
}
func resourceNetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceNetworkGetResourceData(d, meta)
if err != nil {
@@ -391,10 +393,10 @@ func resourceNetworkCreate(ctx context.Context, d *schema.ResourceData, meta int
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateNetwork(ctx, site, req)
resp, err := c.CreateNetwork(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -405,18 +407,18 @@ func resourceNetworkCreate(ctx context.Context, d *schema.ResourceData, meta int
}
func resourceNetworkGetResourceData(d *schema.ResourceData, meta interface{}) (*unifi.Network, error) {
// c := meta.(*client)
// c := meta.(*provider.Client)
vlan := d.Get("vlan_id").(int)
dhcpDNS, err := listToStringSlice(d.Get("dhcp_dns").([]interface{}))
dhcpDNS, err := utils.ListToStringSlice(d.Get("dhcp_dns").([]interface{}))
if err != nil {
return nil, fmt.Errorf("unable to convert dhcp_dns to string slice: %w", err)
}
dhcpV6DNS, err := listToStringSlice(d.Get("dhcp_v6_dns").([]interface{}))
dhcpV6DNS, err := utils.ListToStringSlice(d.Get("dhcp_v6_dns").([]interface{}))
if err != nil {
return nil, fmt.Errorf("unable to convert dhcp_v6_dns to string slice: %w", err)
}
wanDNS, err := listToStringSlice(d.Get("wan_dns").([]interface{}))
wanDNS, err := utils.ListToStringSlice(d.Get("wan_dns").([]interface{}))
if err != nil {
return nil, fmt.Errorf("unable to convert wan_dns to string slice: %w", err)
}
@@ -425,7 +427,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: utils.CidrOneBased(d.Get("subnet").(string)),
NetworkGroup: d.Get("network_group").(string),
DHCPDStart: d.Get("dhcp_start").(string),
DHCPDStop: d.Get("dhcp_stop").(string),
@@ -571,7 +573,7 @@ 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", utils.CidrZeroBased(resp.IPSubnet))
d.Set("network_group", resp.NetworkGroup)
d.Set("dhcp_dns", dhcpDNS)
@@ -624,16 +626,16 @@ func resourceNetworkSetResourceData(resp *unifi.Network, d *schema.ResourceData,
}
func resourceNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetNetwork(ctx, site, id)
resp, err := c.GetNetwork(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -646,7 +648,7 @@ func resourceNetworkRead(ctx context.Context, d *schema.ResourceData, meta inter
}
func resourceNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceNetworkGetResourceData(d, meta)
if err != nil {
@@ -656,11 +658,11 @@ func resourceNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta int
req.ID = d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateNetwork(ctx, site, req)
resp, err := c.UpdateNetwork(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -669,15 +671,15 @@ func resourceNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta int
}
func resourceNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
id := d.Id()
err := c.c.DeleteNetwork(ctx, site, id)
err := c.DeleteNetwork(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}
@@ -685,11 +687,11 @@ func resourceNetworkDelete(ctx context.Context, d *schema.ResourceData, meta int
}
func importNetwork(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
if strings.Contains(id, ":") {
@@ -701,7 +703,7 @@ func importNetwork(ctx context.Context, d *schema.ResourceData, meta interface{}
if strings.HasPrefix(id, "name=") {
targetName := strings.TrimPrefix(id, "name=")
var err error
if id, err = getNetworkIDByName(ctx, c.c, targetName, site); err != nil {
if id, err = getNetworkIDByName(ctx, c.Client, targetName, site); err != nil {
return nil, err
}
}

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"net"
"regexp"
"strconv"
@@ -412,7 +413,7 @@ func TestAccNetwork_mdns(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
preCheck(t)
preCheckMinVersion(t, controllerV7)
preCheckMinVersion(t, provider.ControllerV7)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: ,

View File

@@ -1,8 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -94,7 +96,7 @@ func resourcePortForward() *schema.Resource {
ValidateFunc: validation.Any(
validation.StringInSlice([]string{"any"}, false),
validation.IsIPv4Address,
cidrValidate,
utils.CidrValidate,
),
},
},
@@ -102,7 +104,7 @@ func resourcePortForward() *schema.Resource {
}
func resourcePortForwardCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourcePortForwardGetResourceData(d)
if err != nil {
@@ -111,9 +113,9 @@ func resourcePortForwardCreate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreatePortForward(ctx, site, req)
resp, err := c.CreatePortForward(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -153,15 +155,15 @@ func resourcePortForwardSetResourceData(resp *unifi.PortForward, d *schema.Resou
}
func resourcePortForwardRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetPortForward(ctx, site, id)
resp, err := c.GetPortForward(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -174,7 +176,7 @@ func resourcePortForwardRead(ctx context.Context, d *schema.ResourceData, meta i
}
func resourcePortForwardUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourcePortForwardGetResourceData(d)
if err != nil {
@@ -185,11 +187,11 @@ func resourcePortForwardUpdate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdatePortForward(ctx, site, req)
resp, err := c.UpdatePortForward(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -198,15 +200,15 @@ func resourcePortForwardUpdate(ctx context.Context, d *schema.ResourceData, meta
}
func resourcePortForwardDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeletePortForward(ctx, site, id)
err := c.DeletePortForward(ctx, site, id)
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,8 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -256,7 +258,7 @@ func resourcePortProfile() *schema.Resource {
}
func resourcePortProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourcePortProfileGetResourceData(d)
if err != nil {
@@ -265,9 +267,9 @@ func resourcePortProfileCreate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreatePortProfile(ctx, site, req)
resp, err := c.CreatePortProfile(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -278,12 +280,12 @@ func resourcePortProfileCreate(ctx context.Context, d *schema.ResourceData, meta
}
func resourcePortProfileGetResourceData(d *schema.ResourceData) (*unifi.PortProfile, error) {
portSecurityMacAddress, err := setToStringSlice(d.Get("port_security_mac_address").(*schema.Set))
portSecurityMacAddress, err := utils.SetToStringSlice(d.Get("port_security_mac_address").(*schema.Set))
if err != nil {
return nil, err
}
excludedNetworkIDs, err := setToStringSlice(d.Get("excluded_network_ids").(*schema.Set))
excludedNetworkIDs, err := utils.SetToStringSlice(d.Get("excluded_network_ids").(*schema.Set))
if err != nil {
return nil, err
}
@@ -334,7 +336,7 @@ func resourcePortProfileSetResourceData(resp *unifi.PortProfile, d *schema.Resou
d.Set("dot1x_idle_timeout", resp.Dot1XIDleTimeout)
d.Set("egress_rate_limit_kbps", resp.EgressRateLimitKbps)
d.Set("egress_rate_limit_kbps_enabled", resp.EgressRateLimitKbpsEnabled)
d.Set("excluded_network_ids", stringSliceToSet(resp.ExcludedNetworkIDs))
d.Set("excluded_network_ids", utils.StringSliceToSet(resp.ExcludedNetworkIDs))
d.Set("forward", resp.Forward)
d.Set("full_duplex", resp.FullDuplex)
d.Set("isolation", resp.Isolation)
@@ -345,7 +347,7 @@ func resourcePortProfileSetResourceData(resp *unifi.PortProfile, d *schema.Resou
d.Set("op_mode", resp.OpMode)
d.Set("poe_mode", resp.PoeMode)
d.Set("port_security_enabled", resp.PortSecurityEnabled)
d.Set("port_security_mac_address", stringSliceToSet(resp.PortSecurityMACAddress))
d.Set("port_security_mac_address", utils.StringSliceToSet(resp.PortSecurityMACAddress))
d.Set("priority_queue1_level", resp.PriorityQueue1Level)
d.Set("priority_queue2_level", resp.PriorityQueue2Level)
d.Set("priority_queue3_level", resp.PriorityQueue3Level)
@@ -369,15 +371,15 @@ func resourcePortProfileSetResourceData(resp *unifi.PortProfile, d *schema.Resou
}
func resourcePortProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetPortProfile(ctx, site, id)
resp, err := c.GetPortProfile(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -390,7 +392,7 @@ func resourcePortProfileRead(ctx context.Context, d *schema.ResourceData, meta i
}
func resourcePortProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourcePortProfileGetResourceData(d)
if err != nil {
@@ -401,11 +403,11 @@ func resourcePortProfileUpdate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdatePortProfile(ctx, site, req)
resp, err := c.UpdatePortProfile(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -414,15 +416,15 @@ func resourcePortProfileUpdate(ctx context.Context, d *schema.ResourceData, meta
}
func resourcePortProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeletePortProfile(ctx, site, id)
err := c.DeletePortProfile(ctx, site, id)
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,9 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"strings"
"github.com/filipowm/go-unifi/unifi"
@@ -234,7 +235,7 @@ func fromAcctServer(sshKey unifi.RADIUSProfileAcctServers) (map[string]interface
}
func resourceRadiusProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceRadiusProfileGetResourceData(d)
if err != nil {
return diag.FromErr(err)
@@ -242,9 +243,9 @@ func resourceRadiusProfileCreate(ctx context.Context, d *schema.ResourceData, me
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateRADIUSProfile(ctx, site, req)
resp, err := c.CreateRADIUSProfile(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -302,15 +303,15 @@ func resourceRadiusProfileSetResourceData(resp *unifi.RADIUSProfile, d *schema.R
}
func resourceRadiusProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetRADIUSProfile(ctx, site, id)
resp, err := c.GetRADIUSProfile(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -323,7 +324,7 @@ func resourceRadiusProfileRead(ctx context.Context, d *schema.ResourceData, meta
}
func resourceRadiusProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceRadiusProfileGetResourceData(d)
if err != nil {
@@ -334,11 +335,11 @@ func resourceRadiusProfileUpdate(ctx context.Context, d *schema.ResourceData, me
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateRADIUSProfile(ctx, site, req)
resp, err := c.UpdateRADIUSProfile(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -347,25 +348,25 @@ func resourceRadiusProfileUpdate(ctx context.Context, d *schema.ResourceData, me
}
func resourceRadiusProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteRADIUSProfile(ctx, site, id)
err := c.DeleteRADIUSProfile(ctx, site, id)
return diag.FromErr(err)
}
func importRadiusProfile(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
if strings.Contains(id, ":") {
@@ -377,7 +378,7 @@ func importRadiusProfile(ctx context.Context, d *schema.ResourceData, meta inter
if strings.HasPrefix(id, "name=") {
targetName := strings.TrimPrefix(id, "name=")
var err error
if id, err = getRadiusProfileIDByName(ctx, c.c, targetName, site); err != nil {
if id, err = getRadiusProfileIDByName(ctx, c.Client, targetName, site); err != nil {
return nil, err
}
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,9 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -141,7 +142,7 @@ func resourceSettingMgmtGetResourceData(d *schema.ResourceData, meta interface{}
}
func resourceSettingMgmtCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceSettingMgmtGetResourceData(d, meta)
if err != nil {
@@ -150,10 +151,10 @@ func resourceSettingMgmtCreate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.UpdateSettingMgmt(ctx, site, req)
resp, err := c.UpdateSettingMgmt(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -177,14 +178,14 @@ func resourceSettingMgmtSetResourceData(resp *unifi.SettingMgmt, d *schema.Resou
}
func resourceSettingMgmtRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetSettingMgmt(ctx, site)
resp, err := c.GetSettingMgmt(ctx, site)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -197,7 +198,7 @@ func resourceSettingMgmtRead(ctx context.Context, d *schema.ResourceData, meta i
}
func resourceSettingMgmtUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceSettingMgmtGetResourceData(d, meta)
if err != nil {
@@ -207,10 +208,10 @@ func resourceSettingMgmtUpdate(ctx context.Context, d *schema.ResourceData, meta
req.ID = d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.UpdateSettingMgmt(ctx, site, req)
resp, err := c.UpdateSettingMgmt(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"sync"

View File

@@ -1,8 +1,9 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -98,7 +99,7 @@ func resourceSettingRadiusGetResourceData(d *schema.ResourceData, meta interface
}
func resourceSettingRadiusCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceSettingRadiusGetResourceData(d, meta)
if err != nil {
@@ -107,10 +108,10 @@ func resourceSettingRadiusCreate(ctx context.Context, d *schema.ResourceData, me
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.UpdateSettingRadius(ctx, site, req)
resp, err := c.UpdateSettingRadius(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -133,14 +134,14 @@ func resourceSettingRadiusSetResourceData(resp *unifi.SettingRadius, d *schema.R
}
func resourceSettingRadiusRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetSettingRadius(ctx, site)
resp, err := c.GetSettingRadius(ctx, site)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -153,7 +154,7 @@ func resourceSettingRadiusRead(ctx context.Context, d *schema.ResourceData, meta
}
func resourceSettingRadiusUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceSettingRadiusGetResourceData(d, meta)
if err != nil {
@@ -163,10 +164,10 @@ func resourceSettingRadiusUpdate(ctx context.Context, d *schema.ResourceData, me
req.ID = d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.UpdateSettingRadius(ctx, site, req)
resp, err := c.UpdateSettingRadius(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"sync"

View File

@@ -1,9 +1,11 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"sync"
"github.com/filipowm/go-unifi/unifi"
@@ -73,18 +75,18 @@ func resourceSettingUsg() *schema.Resource {
}
func resourceSettingUsgUpdateResourceData(d *schema.ResourceData, meta interface{}, setting *unifi.SettingUsg) error {
c := meta.(*client)
c := meta.(*provider.Client)
//nolint // GetOkExists is deprecated, but using here:
if mdns, hasMdns := d.GetOkExists("multicast_dns_enabled"); hasMdns {
if c.IsControllerV7() {
return fmt.Errorf("multicast_dns_enabled is not supported on controller version %v", c.version)
return fmt.Errorf("multicast_dns_enabled is not supported on controller version %v", c.Version)
}
setting.MdnsEnabled = mdns.(bool)
}
dhcpRelay, err := listToStringSlice(d.Get("dhcp_relay_servers").([]interface{}))
dhcpRelay, err := utils.ListToStringSlice(d.Get("dhcp_relay_servers").([]interface{}))
if err != nil {
return fmt.Errorf("unable to convert dhcp_relay_servers to string slice: %w", err)
}
@@ -98,14 +100,14 @@ func resourceSettingUsgUpdateResourceData(d *schema.ResourceData, meta interface
}
func resourceSettingUsgUpsert(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req, err := c.c.GetSettingUsg(ctx, c.site)
req, err := c.GetSettingUsg(ctx, c.Site)
if err != nil {
return diag.FromErr(err)
}
@@ -115,7 +117,7 @@ func resourceSettingUsgUpsert(ctx context.Context, d *schema.ResourceData, meta
return diag.FromErr(err)
}
resp, err := c.c.UpdateSettingUsg(ctx, site, req)
resp, err := c.UpdateSettingUsg(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -147,14 +149,14 @@ func resourceSettingUsgSetResourceData(resp *unifi.SettingUsg, d *schema.Resourc
}
func resourceSettingUsgRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetSettingUsg(ctx, site)
resp, err := c.GetSettingUsg(ctx, site)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,9 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -43,10 +44,10 @@ func resourceSite() *schema.Resource {
}
func resourceSiteImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
_, err := c.c.GetSite(ctx, id)
_, err := c.GetSite(ctx, id)
if err != nil {
if !errors.Is(err, unifi.ErrNotFound) {
return nil, err
@@ -57,7 +58,7 @@ func resourceSiteImport(ctx context.Context, d *schema.ResourceData, meta interf
}
// lookup site by name
sites, err := c.c.ListSites(ctx)
sites, err := c.ListSites(ctx)
if err != nil {
return nil, err
}
@@ -73,11 +74,11 @@ func resourceSiteImport(ctx context.Context, d *schema.ResourceData, meta interf
}
func resourceSiteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
description := d.Get("description").(string)
resp, err := c.c.CreateSite(ctx, description)
resp, err := c.CreateSite(ctx, description)
if err != nil {
return diag.FromErr(err)
}
@@ -95,11 +96,11 @@ func resourceSiteSetResourceData(resp *unifi.Site, d *schema.ResourceData) diag.
}
func resourceSiteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site, err := c.c.GetSite(ctx, id)
site, err := c.GetSite(ctx, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -112,7 +113,7 @@ func resourceSiteRead(ctx context.Context, d *schema.ResourceData, meta interfac
}
func resourceSiteUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := &unifi.Site{
ID: d.Id(),
@@ -120,7 +121,7 @@ func resourceSiteUpdate(ctx context.Context, d *schema.ResourceData, meta interf
Description: d.Get("description").(string),
}
resp, err := c.c.UpdateSite(ctx, site.Name, site.Description)
resp, err := c.UpdateSite(ctx, site.Name, site.Description)
if err != nil {
return diag.FromErr(err)
}
@@ -129,8 +130,8 @@ func resourceSiteUpdate(ctx context.Context, d *schema.ResourceData, meta interf
}
func resourceSiteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
_, err := c.c.DeleteSite(ctx, id)
_, err := c.DeleteSite(ctx, id)
return diag.FromErr(err)
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"context"

View File

@@ -1,9 +1,11 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -46,7 +48,7 @@ func resourceStaticRoute() *schema.Resource {
Description: "The network subnet address.",
Type: schema.TypeString,
Required: true,
ValidateFunc: cidrValidate,
ValidateFunc: utils.CidrValidate,
DiffSuppressFunc: cidrDiffSuppress,
},
"type": {
@@ -77,7 +79,7 @@ func resourceStaticRoute() *schema.Resource {
}
func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceStaticRouteGetResourceData(d)
if err != nil {
@@ -86,10 +88,10 @@ func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateRouting(ctx, site, req)
resp, err := c.CreateRouting(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -107,7 +109,7 @@ func resourceStaticRouteGetResourceData(d *schema.ResourceData) (*unifi.Routing,
Type: "static-route",
Name: d.Get("name").(string),
StaticRouteNetwork: cidrZeroBased(d.Get("network").(string)),
StaticRouteNetwork: utils.CidrZeroBased(d.Get("network").(string)),
StaticRouteDistance: d.Get("distance").(int),
StaticRouteType: t,
}
@@ -128,7 +130,7 @@ func resourceStaticRouteGetResourceData(d *schema.ResourceData) (*unifi.Routing,
func resourceStaticRouteSetResourceData(resp *unifi.Routing, d *schema.ResourceData, site string) diag.Diagnostics {
d.Set("site", site)
d.Set("name", resp.Name)
d.Set("network", cidrZeroBased(resp.StaticRouteNetwork))
d.Set("network", utils.CidrZeroBased(resp.StaticRouteNetwork))
d.Set("distance", resp.StaticRouteDistance)
t := resp.StaticRouteType
@@ -152,16 +154,16 @@ func resourceStaticRouteSetResourceData(resp *unifi.Routing, d *schema.ResourceD
}
func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetRouting(ctx, site, id)
resp, err := c.GetRouting(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -174,7 +176,7 @@ func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, meta i
}
func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceStaticRouteGetResourceData(d)
if err != nil {
@@ -185,11 +187,11 @@ func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, meta
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateRouting(ctx, site, req)
resp, err := c.UpdateRouting(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -198,15 +200,15 @@ func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, meta
}
func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteRouting(ctx, site, id)
err := c.DeleteRouting(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,9 +1,10 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -118,7 +119,7 @@ func resourceUser() *schema.Resource {
}
func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceUserGetResourceData(d)
if err != nil {
@@ -129,18 +130,18 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateUser(ctx, site, req)
resp, err := c.CreateUser(ctx, site, req)
if err != nil {
if !IsServerErrorContains(err, "api.err.MacUsed") || !allowExisting {
if !provider.IsServerErrorContains(err, "api.err.MacUsed") || !allowExisting {
return diag.FromErr(err)
}
// mac in use, just absorb it
mac := d.Get("mac").(string)
existing, err := c.c.GetUserByMAC(ctx, site, mac)
existing, err := c.GetUserByMAC(ctx, site, mac)
if err != nil {
return diag.FromErr(err)
}
@@ -148,7 +149,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
req.ID = existing.ID
req.SiteID = existing.SiteID
resp, err = c.c.UpdateUser(ctx, site, req)
resp, err = c.UpdateUser(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -157,7 +158,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
d.SetId(resp.ID)
if d.Get("blocked").(bool) {
err := c.c.BlockUserByMAC(ctx, site, d.Get("mac").(string))
err := c.BlockUserByMAC(ctx, site, d.Get("mac").(string))
if err != nil {
return diag.FromErr(err)
}
@@ -167,7 +168,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
mac := d.Get("mac").(string)
device := d.Get("dev_id_override").(int)
err := c.c.OverrideUserFingerprint(context.TODO(), site, mac, device)
err := c.OverrideUserFingerprint(context.TODO(), site, mac, device)
if err != nil {
return diag.FromErr(err)
}
@@ -226,16 +227,16 @@ func resourceUserSetResourceData(resp *unifi.User, d *schema.ResourceData, site
}
func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetUser(ctx, site, id)
resp, err := c.GetUser(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -245,7 +246,7 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
}
// for some reason the IP address is only on this endpoint, so issue another request
macResp, err := c.c.GetUserByMAC(ctx, site, resp.MAC)
macResp, err := c.GetUserByMAC(ctx, site, resp.MAC)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -262,22 +263,22 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
}
func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
if d.HasChange("blocked") {
mac := d.Get("mac").(string)
if d.Get("blocked").(bool) {
err := c.c.BlockUserByMAC(ctx, site, mac)
err := c.BlockUserByMAC(ctx, site, mac)
if err != nil {
return diag.FromErr(err)
}
} else {
err := c.c.UnblockUserByMAC(ctx, site, mac)
err := c.UnblockUserByMAC(ctx, site, mac)
if err != nil {
return diag.FromErr(err)
}
@@ -288,7 +289,7 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
mac := d.Get("mac").(string)
device := d.Get("dev_id_override").(int)
err := c.c.OverrideUserFingerprint(context.TODO(), site, mac, device)
err := c.OverrideUserFingerprint(context.TODO(), site, mac, device)
if err != nil {
return diag.FromErr(err)
}
@@ -306,7 +307,7 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
req.ID = d.Id()
req.SiteID = site
resp, err := c.c.UpdateUser(ctx, site, req)
resp, err := c.UpdateUser(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -315,7 +316,7 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
}
func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
@@ -325,11 +326,11 @@ func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interf
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
// lookup MAC instead of trusting state
u, err := c.c.GetUser(ctx, site, id)
u, err := c.GetUser(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}
@@ -337,6 +338,6 @@ func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interf
return diag.FromErr(err)
}
err = c.c.DeleteUserByMAC(ctx, site, u.MAC)
err = c.DeleteUserByMAC(ctx, site, u.MAC)
return diag.FromErr(err)
}

View File

@@ -1,8 +1,9 @@
package provider
package v1
import (
"context"
"errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -59,7 +60,7 @@ func resourceUserGroup() *schema.Resource {
}
func resourceUserGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceUserGroupGetResourceData(d)
if err != nil {
@@ -68,10 +69,10 @@ func resourceUserGroupCreate(ctx context.Context, d *schema.ResourceData, meta i
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateUserGroup(context.TODO(), site, req)
resp, err := c.CreateUserGroup(context.TODO(), site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -98,16 +99,16 @@ func resourceUserGroupSetResourceData(resp *unifi.UserGroup, d *schema.ResourceD
}
func resourceUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetUserGroup(context.TODO(), site, id)
resp, err := c.GetUserGroup(context.TODO(), site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -120,7 +121,7 @@ func resourceUserGroupRead(ctx context.Context, d *schema.ResourceData, meta int
}
func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceUserGroupGetResourceData(d)
if err != nil {
@@ -131,11 +132,11 @@ func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta i
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateUserGroup(context.TODO(), site, req)
resp, err := c.UpdateUserGroup(context.TODO(), site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -144,15 +145,15 @@ func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta i
}
func resourceUserGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteUserGroup(context.TODO(), site, id)
err := c.DeleteUserGroup(context.TODO(), site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package provider
package v1
import (
"context"

View File

@@ -1,9 +1,11 @@
package provider
package v1
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -203,7 +205,7 @@ func resourceWLAN() *schema.Resource {
"minimum_data_rate_2g_kbps": {
Description: "Set minimum data rate control for 2G devices, in Kbps. " +
"Use `0` to disable minimum data rates. " +
"Valid values are: " + markdownValueListInt(wlanValidMinimumDataRate2g) + ".",
"Valid values are: " + utils.MarkdownValueListInt(wlanValidMinimumDataRate2g) + ".",
Type: schema.TypeInt,
Optional: true,
// TODO: this validation is from the UI, if other values work, perhaps remove this is set it to a range instead?
@@ -212,7 +214,7 @@ func resourceWLAN() *schema.Resource {
"minimum_data_rate_5g_kbps": {
Description: "Set minimum data rate control for 5G devices, in Kbps. " +
"Use `0` to disable minimum data rates. " +
"Valid values are: " + markdownValueListInt(wlanValidMinimumDataRate5g) + ".",
"Valid values are: " + utils.MarkdownValueListInt(wlanValidMinimumDataRate5g) + ".",
Type: schema.TypeInt,
Optional: true,
// TODO: this validation is from the UI, if other values work, perhaps remove this is set it to a range instead?
@@ -243,7 +245,7 @@ func resourceWLAN() *schema.Resource {
}
func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*unifi.WLAN, error) {
c := meta.(*client)
c := meta.(*provider.Client)
security := d.Get("security").(string)
passphrase := d.Get("passphrase").(string)
@@ -265,7 +267,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni
}
if !c.SupportsWPA3() {
if wpa3 || wpa3Transition {
return nil, fmt.Errorf("WPA 3 support is not available on controller version %q, you must be on %q or higher", c.version, controllerVersionWPA3)
return nil, fmt.Errorf("WPA 3 support is not available on controller version %q, you must be on %q or higher", c.Version, provider.ControllerVersionWPA3)
}
}
@@ -276,7 +278,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni
}
macFilterEnabled := d.Get("mac_filter_enabled").(bool)
macFilterList, err := setToStringSlice(d.Get("mac_filter_list").(*schema.Set))
macFilterList, err := utils.SetToStringSlice(d.Get("mac_filter_list").(*schema.Set))
if err != nil {
return nil, err
}
@@ -286,7 +288,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni
// version specific fields and validation
networkID := d.Get("network_id").(string)
apGroupIDs, err := setToStringSlice(d.Get("ap_group_ids").(*schema.Set))
apGroupIDs, err := utils.SetToStringSlice(d.Get("ap_group_ids").(*schema.Set))
if err != nil {
return nil, err
}
@@ -353,7 +355,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni
}
func resourceWLANCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceWLANGetResourceData(d, meta)
if err != nil {
@@ -362,10 +364,10 @@ func resourceWLANCreate(ctx context.Context, d *schema.ResourceData, meta interf
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.CreateWLAN(ctx, site, req)
resp, err := c.CreateWLAN(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -376,7 +378,7 @@ func resourceWLANCreate(ctx context.Context, d *schema.ResourceData, meta interf
}
func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData, meta interface{}, site string) diag.Diagnostics {
// c := meta.(*client)
// c := meta.(*provider.Client)
security := resp.Security
passphrase := resp.XPassphrase
wpa3 := false
@@ -393,11 +395,11 @@ func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData, meta
var macFilterList *schema.Set
macFilterPolicy := "deny"
if macFilterEnabled {
macFilterList = stringSliceToSet(resp.MACFilterList)
macFilterList = utils.StringSliceToSet(resp.MACFilterList)
macFilterPolicy = resp.MACFilterPolicy
}
apGroupIDs := stringSliceToSet(resp.ApGroupIDs)
apGroupIDs := utils.StringSliceToSet(resp.ApGroupIDs)
schedule := listFromSchedules(resp.ScheduleWithDuration)
@@ -441,15 +443,15 @@ func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData, meta
}
func resourceWLANRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
resp, err := c.c.GetWLAN(ctx, site, id)
resp, err := c.GetWLAN(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
d.SetId("")
return nil
@@ -462,7 +464,7 @@ func resourceWLANRead(ctx context.Context, d *schema.ResourceData, meta interfac
}
func resourceWLANUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
req, err := resourceWLANGetResourceData(d, meta)
if err != nil {
@@ -472,11 +474,11 @@ func resourceWLANUpdate(ctx context.Context, d *schema.ResourceData, meta interf
req.ID = d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
req.SiteID = site
resp, err := c.c.UpdateWLAN(ctx, site, req)
resp, err := c.UpdateWLAN(ctx, site, req)
if err != nil {
return diag.FromErr(err)
}
@@ -485,15 +487,15 @@ func resourceWLANUpdate(ctx context.Context, d *schema.ResourceData, meta interf
}
func resourceWLANDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*client)
c := meta.(*provider.Client)
id := d.Id()
site := d.Get("site").(string)
if site == "" {
site = c.site
site = c.Site
}
err := c.c.DeleteWLAN(ctx, site, id)
err := c.DeleteWLAN(ctx, site, id)
if errors.Is(err, unifi.ErrNotFound) {
return nil
}

View File

@@ -1,7 +1,8 @@
package provider
package v1
import (
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"net"
"testing"
@@ -331,7 +332,7 @@ func TestAccWLAN_wpa3(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
preCheck(t)
preCheckMinVersion(t, controllerVersionWPA3)
preCheckMinVersion(t, provider.ControllerVersionWPA3)
},
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {

View File

@@ -0,0 +1,172 @@
package v2
import (
"context"
up "github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &unifiProvider{
version: version,
}
}
}
type unifiProvider struct {
version string
}
type unifiProviderModel struct {
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
APIKey types.String `tfsdk:"api_key"`
APIUrl types.String `tfsdk:"api_url"`
Site types.String `tfsdk:"site"`
Insecure types.Bool `tfsdk:"allow_insecure"`
}
func (p *unifiProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "unifi"
resp.Version = p.version
}
func (p *unifiProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"username": schema.StringAttribute{
MarkdownDescription: up.ProviderUsernameDescription,
Optional: true,
},
"password": schema.StringAttribute{
MarkdownDescription: up.ProviderPasswordDescription,
Optional: true,
Sensitive: true,
},
"api_key": schema.StringAttribute{
MarkdownDescription: up.ProviderAPIKeyDescription,
Optional: true,
Sensitive: true,
},
"api_url": schema.StringAttribute{
MarkdownDescription: up.ProviderAPIURLDescription,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1), // workaround for `required: true`, because it fails on doc generation due to incorrectly detected difference between v1 and v2
},
Optional: true,
},
"site": schema.StringAttribute{
MarkdownDescription: up.ProviderSiteDescription,
Optional: true,
},
"allow_insecure": schema.BoolAttribute{
MarkdownDescription: up.ProviderAllowInsecureDescription,
Optional: true,
},
},
}
}
func (p *unifiProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
tflog.Info(ctx, "Configuring Unifi provider...")
// Retrieve provider data from the configuration
var cfg unifiProviderModel
diags := req.Config.Get(ctx, &cfg)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
// If practitioner provided a configuration value for any of the
// attributes, it must be a known value.
if cfg.APIUrl.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("api_url"),
"Unknown UniFi Controller API URL",
"The provider cannot create the UniFi Controller API client as there is an unknown configuration value "+
"for the API endpoint. Either target apply the source of the value first, set the value statically in "+
"the configuration, or use the UNIFI_API_URL environment variable.",
)
}
if resp.Diagnostics.HasError() {
return
}
// Default values to environment variables, but override
// with Terraform configuration value if set.
// Check environment variables
username := utils.GetAnyStringEnv("UNIFI_USERNAME")
password := utils.GetAnyStringEnv("UNIFI_PASSWORD")
apiKey := utils.GetAnyStringEnv("UNIFI_API_KEY")
apiUrl := utils.GetAnyStringEnv("UNIFI_API_URL")
site := utils.GetAnyStringEnv("UNIFI_SITE")
insecure := utils.GetAnyBoolEnv("UNIFI_INSECURE")
if !cfg.Username.IsNull() {
username = cfg.Username.ValueString()
}
if !cfg.Password.IsNull() {
password = cfg.Password.ValueString()
}
if !cfg.APIKey.IsNull() {
apiKey = cfg.APIKey.ValueString()
}
if !cfg.APIUrl.IsNull() {
apiUrl = cfg.APIUrl.ValueString()
}
if !cfg.Site.IsNull() {
site = cfg.Site.ValueString()
}
if !cfg.Insecure.IsNull() {
insecure = cfg.Insecure.ValueBool()
}
if apiKey != "" && (username != "" || password != "") {
resp.Diagnostics.AddAttributeError(path.Root("api_key"), "Two authentication methods configured", "Only one of `username`/`password` or `api_key` can be set")
} else if apiKey == "" && (username == "" || password == "") {
resp.Diagnostics.AddAttributeError(path.Root("api_key"), "Missing UniFi API credentials", "Either `username`/`password` or `api_key` must be set")
}
if apiUrl == "" {
resp.Diagnostics.AddAttributeError(path.Root("api_url"), "Missing UniFi API URL", "The `api_url` attribute must be set")
}
if resp.Diagnostics.HasError() {
return
}
if site == "" {
site = "default" // set default site if not provided
}
c, err := up.NewClient(&up.ClientConfig{
Username: username,
Password: password,
ApiKey: apiKey,
Url: apiUrl,
Site: site,
Insecure: insecure,
})
if err != nil {
resp.Diagnostics.AddError("Failed to create UniFi client", err.Error())
return
}
resp.ResourceData = c
resp.DataSourceData = c
}
func (p *unifiProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{}
}
func (p *unifiProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{}
}

40
internal/utils/cidr.go Normal file
View File

@@ -0,0 +1,40 @@
package utils
import (
"fmt"
"net"
)
func CidrValidate(raw interface{}, key string) ([]string, []error) {
v, ok := raw.(string)
if !ok {
return nil, []error{fmt.Errorf("expected string, got %T", raw)}
}
_, _, err := net.ParseCIDR(v)
if err != nil {
return nil, []error{err}
}
return nil, nil
}
func CidrZeroBased(cidr string) string {
_, cidrNet, err := net.ParseCIDR(cidr)
if err != nil {
return ""
}
return cidrNet.String()
}
func CidrOneBased(cidr string) string {
_, cidrNet, err := net.ParseCIDR(cidr)
if err != nil {
return ""
}
cidrNet.IP[3]++
return cidrNet.String()
}

View File

@@ -1,4 +1,4 @@
package provider
package utils
import (
"testing"
@@ -18,7 +18,7 @@ func TestCIDRValidate(t *testing.T) {
{"", "192.1.2.1/20"},
} {
t.Run(c.cidr, func(t *testing.T) {
_, actualErrs := cidrValidate(c.cidr, "key")
_, actualErrs := CidrValidate(c.cidr, "key")
switch len(actualErrs) {
case 0:
if c.expectedError != "" {

50
internal/utils/env.go Normal file
View File

@@ -0,0 +1,50 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package utils
import (
"os"
"strconv"
)
// GetAnyStringEnv returns the first non-empty string value from the environment variables.
func GetAnyStringEnv(ks ...string) string {
for _, k := range ks {
if v := os.Getenv(k); v != "" {
return v
}
}
return ""
}
// GetAnyBoolEnv returns the first non-empty boolean value from the environment variables.
func GetAnyBoolEnv(ks ...string) bool {
val := ""
for _, k := range ks {
if v := os.Getenv(k); v != "" {
val = v
break
}
}
return val == "true" || val == "1"
}
// GetAnyIntEnv returns the first non-empty integer value from the environment variables.
func GetAnyIntEnv(ks ...string) int {
for _, k := range ks {
if v := os.Getenv(k); v != "" {
if i, err := strconv.Atoi(v); err == nil {
return i
}
}
}
return 0
}

View File

@@ -1,8 +1,8 @@
package provider
package utils
import "strconv"
func markdownValueListInt(values []int) string {
func MarkdownValueListInt(values []int) string {
switch {
case len(values) == 0:
return ""

View File

@@ -1,4 +1,4 @@
package provider
package utils
import (
"fmt"
@@ -6,7 +6,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func listToStringSlice(src []interface{}) ([]string, error) {
func ListToStringSlice(src []interface{}) ([]string, error) {
dst := make([]string, 0, len(src))
for _, s := range src {
d, ok := s.(string)
@@ -18,11 +18,11 @@ func listToStringSlice(src []interface{}) ([]string, error) {
return dst, nil
}
func setToStringSlice(src *schema.Set) ([]string, error) {
return listToStringSlice(src.List())
func SetToStringSlice(src *schema.Set) ([]string, error) {
return ListToStringSlice(src.List())
}
func stringSliceToList(list []string) []interface{} {
func StringSliceToList(list []string) []interface{} {
vs := make([]interface{}, 0, len(list))
for _, v := range list {
vs = append(vs, v)
@@ -30,6 +30,6 @@ func stringSliceToList(list []string) []interface{} {
return vs
}
func stringSliceToSet(src []string) *schema.Set {
return schema.NewSet(schema.HashString, stringSliceToList(src))
func StringSliceToSet(src []string) *schema.Set {
return schema.NewSet(schema.HashString, StringSliceToList(src))
}

63
main.go
View File

@@ -1,16 +1,20 @@
package main // import "github.com/filipowm/terraform-provider-unifi"
import (
"context"
"flag"
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
v1 "github.com/filipowm/terraform-provider-unifi/internal/provider/v1"
v2 "github.com/filipowm/terraform-provider-unifi/internal/provider/v2"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server"
"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"log"
)
// Generate docs for website
//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
var (
// these will be set by the goreleaser configuration
// to appropriate values for the compiled binary
@@ -21,17 +25,50 @@ var (
)
func main() {
ctx := context.Background()
var debugMode bool
flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := &plugin.ServeOpts{ProviderFunc: provider.New(version)}
if debugMode {
opts.Debug = true
opts.ProviderAddr = "registry.terraform.io/filipowm/unifi"
p := v1.New(version)
upgradedSdkServer, err := tf5to6server.UpgradeServer(
ctx,
func() tfprotov5.ProviderServer {
return schema.NewGRPCProviderServer(p())
},
)
if err != nil {
log.Fatal(err)
}
plugin.Serve(opts)
providers := []func() tfprotov6.ProviderServer{
providerserver.NewProtocol6(v2.New(version)()),
func() tfprotov6.ProviderServer {
return upgradedSdkServer
},
}
muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)
if err != nil {
log.Fatal(err)
}
var serveOpts []tf6server.ServeOpt
if debugMode {
serveOpts = append(serveOpts, tf6server.WithManagedDebug())
}
// Remove any date and time prefix in log package function output to
// prevent duplicate timestamp and incorrect log level setting
log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))
err = tf6server.Serve(
"registry.terraform.io/filipowm/unifi",
muxServer.ProviderServer,
serveOpts...,
)
if err != nil {
log.Fatal(err)
}
}

View File

@@ -1,13 +1,13 @@
---
layout: ""
page_title: "Provider: Unifi"
page_title: "Provider: UniFi"
description: |-
The Unifi provider provides resources to interact with a Unifi controller API.
The Unifi provider provides resources to interact with a UniFi Controller API.
---
# Unifi Provider
The Unifi provider provides resources to interact with a Unifi controller API.
The Unifi provider provides resources to interact with a UniFi Controller API.
It is not recommended to use your own account for management of your controller. A user specific to
Terraform is recommended. You can create a **Limited Admin** with **Local Access Only** and

View File

@@ -7,3 +7,6 @@ import (
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
)
// Generate documentation.
//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-dir ../ --rendered-website-dir ./docs --provider-name "terraform-provider-unifi" --rendered-provider-name "terraform-provider-unifi" //nolint:lll