Make provider package internal

This commit is contained in:
Paul Tyng
2019-12-31 01:22:43 -05:00
parent 8f9d4f7762
commit 881eadcf21
16 changed files with 1 additions and 1 deletions

View File

@@ -0,0 +1,53 @@
package provider
import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func dataUserGroup() *schema.Resource {
return &schema.Resource{
Read: dataUserGroupRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
Default: "Default",
},
"qos_rate_max_down": {
Type: schema.TypeInt,
Computed: true,
},
"qos_rate_max_up": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}
func dataUserGroupRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
name := d.Get("name").(string)
groups, err := c.c.ListUserGroup(c.site)
if err != nil {
return err
}
for _, g := range groups {
if g.Name == name {
d.SetId(g.ID)
d.Set("qos_rate_max_down", g.QOSRateMaxDown)
d.Set("qos_rate_max_up", g.QOSRateMaxUp)
return nil
}
}
return fmt.Errorf("user group not found with name %s", name)
}

View File

@@ -0,0 +1,28 @@
package provider
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)
func TestAccDataUserGroup_default(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { preCheck(t) },
Providers: providers,
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccDataUserGroupConfig_default,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
},
})
}
const testAccDataUserGroupConfig_default = `
data "unifi_user_group" "default" {
}
`

View File

@@ -0,0 +1,40 @@
package provider
import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func dataWLANGroup() *schema.Resource {
return &schema.Resource{
Read: dataWLANGroupRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
Default: "Default",
},
},
}
}
func dataWLANGroupRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
name := d.Get("name").(string)
groups, err := c.c.ListWLANGroup(c.site)
if err != nil {
return err
}
for _, g := range groups {
if g.Name == name {
d.SetId(g.ID)
return nil
}
}
return fmt.Errorf("WLAN group not found with name %s", name)
}

View File

@@ -0,0 +1,28 @@
package provider
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)
func TestAccDataWLANGroup_default(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { preCheck(t) },
Providers: providers,
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccDataWLANGroupConfig_default,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
},
})
}
const testAccDataWLANGroupConfig_default = `
data "unifi_wlan_group" "default" {
}
`

View File

@@ -0,0 +1,111 @@
package provider
import (
"sync"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
type lazyClient struct {
baseURL string
user string
pass string
once sync.Once
inner *unifi.Client
}
func (c *lazyClient) init() error {
var err error
c.once.Do(func() {
c.inner = &unifi.Client{}
err = c.inner.SetBaseURL(c.baseURL)
if err != nil {
return
}
err = c.inner.Login(c.user, c.pass)
})
return err
}
func (c *lazyClient) ListUserGroup(site string) ([]unifi.UserGroup, error) {
c.init()
return c.inner.ListUserGroup(site)
}
func (c *lazyClient) ListWLANGroup(site string) ([]unifi.WLANGroup, error) {
c.init()
return c.inner.ListWLANGroup(site)
}
func (c *lazyClient) DeleteNetwork(site, id, name string) error {
c.init()
return c.inner.DeleteNetwork(site, id, name)
}
func (c *lazyClient) CreateNetwork(site string, d *unifi.Network) (*unifi.Network, error) {
c.init()
return c.inner.CreateNetwork(site, d)
}
func (c *lazyClient) GetNetwork(site, id string) (*unifi.Network, error) {
c.init()
return c.inner.GetNetwork(site, id)
}
func (c *lazyClient) UpdateNetwork(site string, d *unifi.Network) (*unifi.Network, error) {
c.init()
return c.inner.UpdateNetwork(site, d)
}
func (c *lazyClient) DeleteWLAN(site, id string) error {
c.init()
return c.inner.DeleteWLAN(site, id)
}
func (c *lazyClient) CreateWLAN(site string, d *unifi.WLAN) (*unifi.WLAN, error) {
c.init()
return c.inner.CreateWLAN(site, d)
}
func (c *lazyClient) GetWLAN(site, id string) (*unifi.WLAN, error) {
c.init()
return c.inner.GetWLAN(site, id)
}
func (c *lazyClient) DeleteUserGroup(site, id string) error {
c.init()
return c.inner.DeleteUserGroup(site, id)
}
func (c *lazyClient) CreateUserGroup(site string, d *unifi.UserGroup) (*unifi.UserGroup, error) {
c.init()
return c.inner.CreateUserGroup(site, d)
}
func (c *lazyClient) GetUserGroup(site, id string) (*unifi.UserGroup, error) {
c.init()
return c.inner.GetUserGroup(site, id)
}
func (c *lazyClient) UpdateUserGroup(site string, d *unifi.UserGroup) (*unifi.UserGroup, error) {
c.init()
return c.inner.UpdateUserGroup(site, d)
}
func (c *lazyClient) GetUser(site, id string) (*unifi.User, error) {
c.init()
return c.inner.GetUser(site, id)
}
func (c *lazyClient) GetUserByMAC(site, mac string) (*unifi.User, error) {
c.init()
return c.inner.GetUserByMAC(site, mac)
}
func (c *lazyClient) CreateUser(site string, d *unifi.User) (*unifi.User, error) {
c.init()
return c.inner.CreateUser(site, d)
}
func (c *lazyClient) UpdateUser(site string, d *unifi.User) (*unifi.User, error) {
c.init()
return c.inner.UpdateUser(site, d)
}
func (c *lazyClient) DeleteUserByMAC(site, mac string) error {
c.init()
return c.inner.DeleteUserByMAC(site, mac)
}
func (c *lazyClient) BlockUserByMAC(site, mac string) error {
c.init()
return c.inner.BlockUserByMAC(site, mac)
}
func (c *lazyClient) UnblockUserByMAC(site, mac string) error {
c.init()
return c.inner.UnblockUserByMAC(site, mac)
}

View File

@@ -0,0 +1,107 @@
package provider
import (
// "fmt"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func Provider() terraform.ResourceProvider {
p := &schema.Provider{
Schema: map[string]*schema.Schema{
"username": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_USERNAME", ""),
},
"password": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_PASSWORD", ""),
},
"api_url": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API", ""),
},
"site": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_SITE", "default"),
},
// "allow_insecure": {
// Type: schema.TypeBool,
// Optional: true,
// Default: false,
// },
},
DataSourcesMap: map[string]*schema.Resource{
"unifi_user_group": dataUserGroup(),
"unifi_wlan_group": dataWLANGroup(),
},
ResourcesMap: map[string]*schema.Resource{
"unifi_network": resourceNetwork(),
"unifi_user_group": resourceUserGroup(),
"unifi_user": resourceUser(),
"unifi_wlan": resourceWLAN(),
},
}
p.ConfigureFunc = configure(p)
return p
}
func configure(p *schema.Provider) schema.ConfigureFunc {
return func(d *schema.ResourceData) (interface{}, error) {
user := d.Get("username").(string)
pass := d.Get("password").(string)
baseURL := d.Get("api_url").(string)
site := d.Get("site").(string)
//insecure := d.Get("allow_insecure").(bool)
c := &client{
c: &lazyClient{
user: user,
pass: pass,
baseURL: baseURL,
},
site: site,
}
return c, nil
}
}
type unifiClient interface {
ListUserGroup(site string) ([]unifi.UserGroup, error)
DeleteUserGroup(site, id string) error
CreateUserGroup(site string, d *unifi.UserGroup) (*unifi.UserGroup, error)
GetUserGroup(site, id string) (*unifi.UserGroup, error)
UpdateUserGroup(site string, d *unifi.UserGroup) (*unifi.UserGroup, error)
ListWLANGroup(site string) ([]unifi.WLANGroup, error)
DeleteNetwork(site, id, name string) error
CreateNetwork(site string, d *unifi.Network) (*unifi.Network, error)
GetNetwork(site, id string) (*unifi.Network, error)
UpdateNetwork(site string, d *unifi.Network) (*unifi.Network, error)
DeleteWLAN(site, id string) error
CreateWLAN(site string, d *unifi.WLAN) (*unifi.WLAN, error)
GetWLAN(site, id string) (*unifi.WLAN, error)
GetUser(site, id string) (*unifi.User, error)
GetUserByMAC(site, mac string) (*unifi.User, error)
CreateUser(site string, d *unifi.User) (*unifi.User, error)
BlockUserByMAC(site, mac string) error
UnblockUserByMAC(site, mac string) error
UpdateUser(site string, d *unifi.User) (*unifi.User, error)
DeleteUserByMAC(site, mac string) error
}
type client struct {
c unifiClient
site string
}

View File

@@ -0,0 +1,74 @@
package provider
import (
"os"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
var providers map[string]terraform.ResourceProvider
var testClient *unifi.Client
func TestMain(m *testing.M) {
if os.Getenv("TF_ACC") == "" {
// short circuit non acceptance test runs
os.Exit(m.Run())
}
providers = map[string]terraform.ResourceProvider{
"unifi": Provider(),
}
user := os.Getenv("UNIFI_USERNAME")
pass := os.Getenv("UNIFI_PASSWORD")
baseURL := os.Getenv("UNIFI_API")
testClient = &unifi.Client{}
testClient.SetBaseURL(baseURL)
err := testClient.Login(user, pass)
if err != nil {
panic(err)
}
os.Exit(m.Run())
}
func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
t.Fatalf("err: %s", err)
}
}
func importStep(name string, ignore ...string) resource.TestStep {
step := resource.TestStep{
ResourceName: name,
ImportState: true,
ImportStateVerify: true,
}
if len(ignore) > 0 {
step.ImportStateVerifyIgnore = ignore
}
return step
}
func preCheck(t *testing.T) {
variables := []string{
"UNIFI_USERNAME",
"UNIFI_PASSWORD",
"UNIFI_API",
}
for _, variable := range variables {
value := os.Getenv(variable)
if value == "" {
t.Fatalf("`%s` must be set for acceptance tests!", variable)
}
}
}

View File

@@ -0,0 +1,185 @@
package provider
import (
"fmt"
"strconv"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func resourceNetwork() *schema.Resource {
return &schema.Resource{
Create: resourceNetworkCreate,
Read: resourceNetworkRead,
Update: resourceNetworkUpdate,
Delete: resourceNetworkDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"purpose": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"corporate", "guest", "vlan-only"}, false),
},
"vlan_id": {
Type: schema.TypeInt,
Optional: true,
},
"subnet": {
Type: schema.TypeString,
Optional: true,
},
"network_group": {
Type: schema.TypeString,
Optional: true,
Default: "LAN",
},
"dhcp_start": {
Type: schema.TypeString,
Optional: true,
},
"dhcp_stop": {
Type: schema.TypeString,
Optional: true,
},
"dhcp_enabled": {
Type: schema.TypeBool,
Optional: true,
},
"dhcp_lease": {
Type: schema.TypeInt,
Optional: true,
Default: 86400,
},
},
}
}
func resourceNetworkCreate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
req, err := resourceNetworkGetResourceData(d)
if err != nil {
return err
}
resp, err := c.c.CreateNetwork(c.site, req)
if err != nil {
return err
}
d.SetId(resp.ID)
return resourceNetworkSetResourceData(resp, d)
}
func resourceNetworkGetResourceData(d *schema.ResourceData) (*unifi.Network, error) {
vlan := d.Get("vlan_id").(int)
return &unifi.Network{
Name: d.Get("name").(string),
Purpose: d.Get("purpose").(string),
VLAN: fmt.Sprintf("%d", d.Get("vlan_id").(int)),
IPSubnet: d.Get("subnet").(string),
NetworkGroup: d.Get("network_group").(string),
DHCPDStart: d.Get("dhcp_start").(string),
DHCPDStop: d.Get("dhcp_stop").(string),
DHCPDEnabled: d.Get("dhcp_enabled").(bool),
DHCPDLeaseTime: d.Get("dhcp_lease").(int),
VLANEnabled: vlan != 0 && vlan != 1,
Enabled: true,
IPV6InterfaceType: "none",
// IPV6InterfaceType string `json:"ipv6_interface_type"` // "none"
// IPV6PDStart string `json:"ipv6_pd_start"` // "::2"
// IPV6PDStop string `json:"ipv6_pd_stop"` // "::7d1"
}, nil
}
func resourceNetworkSetResourceData(resp *unifi.Network, d *schema.ResourceData) error {
var err error
vlan := 0
if resp.VLANEnabled {
vlan, err = strconv.Atoi(resp.VLAN)
if err != nil {
return err
}
}
dhcpLease := resp.DHCPDLeaseTime
if resp.DHCPDEnabled && dhcpLease == 0 {
dhcpLease = 86400
}
d.Set("name", resp.Name)
d.Set("purpose", resp.Purpose)
d.Set("vlan_id", vlan)
d.Set("subnet", resp.IPSubnet)
d.Set("network_group", resp.NetworkGroup)
d.Set("dhcp_start", resp.DHCPDStart)
d.Set("dhcp_stop", resp.DHCPDStop)
d.Set("dhcp_enabled", resp.DHCPDEnabled)
d.Set("dhcp_lease", dhcpLease)
return nil
}
func resourceNetworkRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
resp, err := c.c.GetNetwork(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
d.SetId("")
return nil
}
if err != nil {
return err
}
return resourceNetworkSetResourceData(resp, d)
}
func resourceNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
req, err := resourceNetworkGetResourceData(d)
if err != nil {
return err
}
req.ID = d.Id()
req.SiteID = c.site
resp, err := c.c.UpdateNetwork(c.site, req)
if err != nil {
return err
}
return resourceNetworkSetResourceData(resp, d)
}
func resourceNetworkDelete(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
name := d.Get("name").(string)
id := d.Id()
err := c.c.DeleteNetwork(c.site, id, name)
if _, ok := err.(*unifi.NotFoundError); ok {
return nil
}
return err
}

View File

@@ -0,0 +1,78 @@
package provider
import (
"fmt"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func TestAccNetwork_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() { preCheck(t) },
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccNetworkConfig("10.0.202.1/24", 202),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_network.test", "subnet", "10.0.202.1/24"),
resource.TestCheckResourceAttr("unifi_network.test", "vlan_id", "202"),
),
},
importStep("unifi_network.test"),
{
Config: testAccNetworkConfig("10.0.203.1/24", 203),
Check: resource.ComposeTestCheckFunc(
testCheckNetworkExists(t, "tfacc", nil),
resource.TestCheckResourceAttr("unifi_network.test", "subnet", "10.0.203.1/24"),
resource.TestCheckResourceAttr("unifi_network.test", "vlan_id", "203"),
),
},
importStep("unifi_network.test"),
},
})
}
func testCheckNetworkExists(t *testing.T, name string, network *unifi.Network) resource.TestCheckFunc {
return func(s *terraform.State) error {
networks, err := testClient.ListNetwork("default")
if err != nil {
return err
}
for _, net := range networks {
if net.Name == name {
if network != nil {
*network = net
}
return nil
}
}
return fmt.Errorf("unable to find network %q", name)
}
}
func testAccNetworkConfig(subnet string, vlan int) string {
return fmt.Sprintf(`
variable "subnet" {
default = "%s"
}
resource "unifi_network" "test" {
name = "tfacc"
purpose = "corporate"
subnet = var.subnet
vlan_id = %d
dhcp_start = cidrhost(var.subnet, 6)
dhcp_stop = cidrhost(var.subnet, 254)
dhcp_enabled = true
}
`, subnet, vlan)
}

View File

@@ -0,0 +1,223 @@
package provider
import (
"strings"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func resourceUser() *schema.Resource {
return &schema.Resource{
Create: resourceUserCreate,
Read: resourceUserRead,
Update: resourceUserUpdate,
Delete: resourceUserDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"mac": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
old = strings.TrimSpace(strings.ReplaceAll(strings.ToLower(old), "-", ":"))
new = strings.TrimSpace(strings.ReplaceAll(strings.ToLower(new), "-", ":"))
return old == new
},
// Validation:
},
"name": {
Type: schema.TypeString,
Required: true,
},
"user_group_id": {
Type: schema.TypeString,
Optional: true,
},
"note": {
Type: schema.TypeString,
Optional: true,
},
"fixed_ip": {
Type: schema.TypeString,
Optional: true,
// TODO: Validate
},
"network_id": {
Type: schema.TypeString,
Optional: true,
},
"blocked": {
Type: schema.TypeBool,
Optional: true,
},
// these are "meta" attributes that control TF UX
"allow_existing": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"skip_forget_on_destroy": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}
func resourceUserCreate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
req, err := resourceUserGetResourceData(d)
if err != nil {
return err
}
allowExisting := d.Get("allow_existing").(bool)
resp, err := c.c.CreateUser(c.site, req)
if err != nil {
apiErr, ok := err.(*unifi.APIError)
if !ok || (apiErr.Message != "api.err.MacUsed" || !allowExisting) {
return err
}
// mac in use, just absorb it
mac := d.Get("mac").(string)
existing, err := c.c.GetUserByMAC(c.site, mac)
if err != nil {
return err
}
req.ID = existing.ID
req.SiteID = existing.SiteID
resp, err = c.c.UpdateUser(c.site, req)
if err != nil {
return err
}
}
d.SetId(resp.ID)
if d.Get("blocked").(bool) {
err := c.c.BlockUserByMAC(c.site, d.Get("mac").(string))
if err != nil {
return err
}
}
return resourceUserSetResourceData(resp, d)
}
func resourceUserGetResourceData(d *schema.ResourceData) (*unifi.User, error) {
fixedIP := d.Get("fixed_ip").(string)
return &unifi.User{
MAC: d.Get("mac").(string),
Name: d.Get("name").(string),
UserGroupID: d.Get("user_group_id").(string),
Note: d.Get("note").(string),
FixedIP: fixedIP,
UseFixedIP: fixedIP != "",
NetworkID: d.Get("network_id").(string),
// not sure if this matters/works
Blocked: d.Get("blocked").(bool),
}, nil
}
func resourceUserSetResourceData(resp *unifi.User, d *schema.ResourceData) error {
fixedIP := ""
if resp.UseFixedIP {
fixedIP = resp.FixedIP
}
d.Set("mac", resp.MAC)
d.Set("name", resp.Name)
d.Set("user_group_id", resp.UserGroupID)
d.Set("note", resp.Note)
d.Set("fixed_ip", fixedIP)
d.Set("network_id", resp.NetworkID)
d.Set("blocked", resp.Blocked)
return nil
}
func resourceUserRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
resp, err := c.c.GetUser(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
d.SetId("")
return nil
}
if err != nil {
return err
}
return resourceUserSetResourceData(resp, d)
}
func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
if d.HasChange("blocked") {
mac := d.Get("mac").(string)
if d.Get("blocked").(bool) {
err := c.c.BlockUserByMAC(c.site, mac)
if err != nil {
return err
}
} else {
err := c.c.UnblockUserByMAC(c.site, mac)
if err != nil {
return err
}
}
}
req, err := resourceUserGetResourceData(d)
if err != nil {
return err
}
req.ID = d.Id()
req.SiteID = c.site
resp, err := c.c.UpdateUser(c.site, req)
if err != nil {
return err
}
return resourceUserSetResourceData(resp, d)
}
func resourceUserDelete(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
if d.Get("skip_forget_on_destroy").(bool) {
return nil
}
// lookup MAC instead of trusting state
u, err := c.c.GetUser(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
return nil
}
if err != nil {
return err
}
err = c.c.DeleteUserByMAC(c.site, u.MAC)
return err
}

View File

@@ -0,0 +1,120 @@
package provider
import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func resourceUserGroup() *schema.Resource {
return &schema.Resource{
Create: resourceUserGroupCreate,
Read: resourceUserGroupRead,
Update: resourceUserGroupUpdate,
Delete: resourceUserGroupDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"qos_rate_max_down": {
Type: schema.TypeInt,
Optional: true,
Default: -1,
// TODO: validate does not equal 0,1
},
"qos_rate_max_up": {
Type: schema.TypeInt,
Optional: true,
Default: -1,
// TODO: validate does not equal 0,1
},
},
}
}
func resourceUserGroupCreate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
req, err := resourceUserGroupGetResourceData(d)
if err != nil {
return err
}
resp, err := c.c.CreateUserGroup(c.site, req)
if err != nil {
return err
}
d.SetId(resp.ID)
return resourceUserGroupSetResourceData(resp, d)
}
func resourceUserGroupGetResourceData(d *schema.ResourceData) (*unifi.UserGroup, error) {
return &unifi.UserGroup{
Name: d.Get("name").(string),
QOSRateMaxDown: d.Get("qos_rate_max_down").(int),
QOSRateMaxUp: d.Get("qos_rate_max_up").(int),
}, nil
}
func resourceUserGroupSetResourceData(resp *unifi.UserGroup, d *schema.ResourceData) error {
d.Set("name", resp.Name)
d.Set("qos_rate_max_down", resp.QOSRateMaxDown)
d.Set("qos_rate_max_up", resp.QOSRateMaxUp)
return nil
}
func resourceUserGroupRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
resp, err := c.c.GetUserGroup(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
d.SetId("")
return nil
}
if err != nil {
return err
}
return resourceUserGroupSetResourceData(resp, d)
}
func resourceUserGroupUpdate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
req, err := resourceUserGroupGetResourceData(d)
if err != nil {
return err
}
req.ID = d.Id()
req.SiteID = c.site
resp, err := c.c.UpdateUserGroup(c.site, req)
if err != nil {
return err
}
return resourceUserGroupSetResourceData(resp, d)
}
func resourceUserGroupDelete(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
err := c.c.DeleteUserGroup(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
return nil
}
return err
}

View File

@@ -0,0 +1,46 @@
package provider
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)
func TestAccUserGroup_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() { preCheck(t) },
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccUserGroupConfig,
// Check: resource.ComposeTestCheckFunc(
// // testCheckUserGroupExists(t, "name"),
// ),
},
{
Config: testAccUserGroupConfig_qos,
},
importStep("unifi_user_group.test"),
{
Config: testAccUserGroupConfig,
},
importStep("unifi_user_group.test"),
},
})
}
const testAccUserGroupConfig = `
resource "unifi_user_group" "test" {
name = "tfacc"
}
`
const testAccUserGroupConfig_qos = `
resource "unifi_user_group" "test" {
name = "tfacc"
qos_rate_max_up = 2000
qos_rate_max_down = 50
}
`

View File

@@ -0,0 +1,245 @@
package provider
import (
"fmt"
"regexp"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func userImportStep(name string) resource.TestStep {
return importStep(name, "allow_existing", "skip_forget_on_destroy")
}
// for test MAC addresses, see https://tools.ietf.org/html/rfc7042#section-2.1.2
func TestAccUser_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() { preCheck(t) },
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccUserConfig("00:00:5E:00:53:00", "tfacc", "tfacc note"),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "note", "tfacc note"),
),
},
userImportStep("unifi_user.test"),
{
Config: testAccUserConfig("00:00:5E:00:53:00", "tfacc-2", "tfacc note 2"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("unifi_user.test", "note", "tfacc note 2"),
),
},
userImportStep("unifi_user.test"),
},
})
}
func TestAccUser_fixed_ip(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() { preCheck(t) },
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccUserConfig("00:00:5E:00:53:10", "tfacc", "tfacc fixed ip"),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "fixed_ip", ""),
),
},
userImportStep("unifi_user.test"),
{
Config: testAccUserConfig_fixedIP("00:00:5E:00:53:10"),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "fixed_ip", "10.1.10.50"),
),
},
userImportStep("unifi_user.test"),
{
// this passes the network again even though its not used
// to avoid a destroy order of operations issue, can
// maybe work it out some other way
Config: testAccUserConfig_network + testAccUserConfig("00:00:5E:00:53:10", "tfacc", "tfacc fixed ip"),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "fixed_ip", ""),
),
},
userImportStep("unifi_user.test"),
},
})
}
func TestAccUser_blocking(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() { preCheck(t) },
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccUserConfig_block("00:00:5E:00:53:20", false),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "blocked", "false"),
),
},
userImportStep("unifi_user.test"),
{
Config: testAccUserConfig_block("00:00:5E:00:53:20", true),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "blocked", "true"),
),
},
userImportStep("unifi_user.test"),
{
Config: testAccUserConfig_block("00:00:5E:00:53:20", false),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "blocked", "false"),
),
},
userImportStep("unifi_user.test"),
},
})
}
func TestAccUser_existing_mac_allow(t *testing.T) {
testMAC := "00:00:5e:00:53:30"
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() {
preCheck(t)
_, err := testClient.CreateUser("default", &unifi.User{
MAC: testMAC,
Name: "tfacc-existing",
Note: "tfacc-existing",
})
if err != nil {
t.Fatal(err)
}
},
CheckDestroy: func(*terraform.State) error {
// TODO: CheckDestroy: ,
return testClient.DeleteUserByMAC("default", testMAC)
},
Steps: []resource.TestStep{
{
Config: testAccUserConfig_existing(testMAC, "tfacc", "tfacc note", true, true),
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
resource.TestCheckResourceAttr("unifi_user.test", "note", "tfacc note"),
),
},
userImportStep("unifi_user.test"),
},
})
}
func TestAccUser_existing_mac_deny(t *testing.T) {
testMAC := "00:00:5e:00:53:40"
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() {
preCheck(t)
_, err := testClient.CreateUser("default", &unifi.User{
MAC: testMAC,
Name: "tfacc-existing",
Note: "tfacc-existing",
})
if err != nil {
t.Fatal(err)
}
},
CheckDestroy: func(*terraform.State) error {
// TODO: CheckDestroy: ,
return testClient.DeleteUserByMAC("default", testMAC)
},
Steps: []resource.TestStep{
{
Config: testAccUserConfig_existing(testMAC, "tfacc", "tfacc note", false, false),
ExpectError: regexp.MustCompile("api\\.err\\.MacUsed"),
},
},
})
}
func testAccUserConfig(mac, name, note string) string {
return fmt.Sprintf(`
resource "unifi_user" "test" {
mac = "%s"
name = "%s"
note = "%s"
}
`, mac, name, note)
}
const testAccUserConfig_network = `
variable "subnet" {
default = "10.1.10.1/24"
}
resource "unifi_network" "test" {
name = "tfaccfixedip"
purpose = "corporate"
vlan_id = 66
subnet = var.subnet
dhcp_start = cidrhost(var.subnet, 6)
dhcp_stop = cidrhost(var.subnet, 254)
dhcp_enabled = true
}
`
func testAccUserConfig_fixedIP(mac string) string {
return fmt.Sprintf(testAccUserConfig_network+`
resource "unifi_user" "test" {
mac = "%s"
name = "tfacc"
note = "tfacc fixed ip"
fixed_ip = "10.1.10.50"
network_id = unifi_network.test.id
}
`, mac)
}
func testAccUserConfig_block(mac string, blocked bool) string {
return fmt.Sprintf(`
resource "unifi_user" "test" {
mac = "%s"
name = "tfacc"
note = "tfacc block %t"
blocked = %t
}
`, mac, blocked, blocked)
}
func testAccUserConfig_existing(mac, name, note string, allow, skip bool) string {
return fmt.Sprintf(`
resource "unifi_user" "test" {
mac = "%s"
name = "%s"
note = "%s"
allow_existing = %t
skip_forget_on_destroy = %t
}
`, mac, name, note, allow, skip)
}

View File

@@ -0,0 +1,156 @@
package provider
import (
"fmt"
"strconv"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/paultyng/terraform-provider-unifi/unifi"
)
func resourceWLAN() *schema.Resource {
return &schema.Resource{
Create: resourceWLANCreate,
Read: resourceWLANRead,
Update: resourceWLANUpdate,
Delete: resourceWLANDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"vlan_id": {
Type: schema.TypeInt,
Optional: true,
Default: 1,
},
"wlan_group_id": {
Type: schema.TypeString,
Required: true,
},
"user_group_id": {
Type: schema.TypeString,
Required: true,
},
"security": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"wpapsk", "wpaeap", "open"}, false),
},
"passphrase": {
Type: schema.TypeString,
// only required if security != open
Optional: true,
Sensitive: true,
},
"hide_ssid": {
Type: schema.TypeBool,
Optional: true,
},
"is_guest": {
Type: schema.TypeBool,
Optional: true,
},
},
}
}
func resourceWLANCreate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
vlan := d.Get("vlan_id").(int)
req := &unifi.WLAN{
Name: d.Get("name").(string),
VLAN: fmt.Sprintf("%d", vlan),
XPassphrase: d.Get("passphrase").(string),
HideSSID: d.Get("hide_ssid").(bool),
IsGuest: d.Get("is_guest").(bool),
WLANGroupID: d.Get("wlan_group_id").(string),
UserGroupID: d.Get("user_group_id").(string),
Security: d.Get("security").(string),
VLANEnabled: vlan != 0 && vlan != 1,
// TODO: add to schema
WPAEnc: "ccmp",
WPAMode: "wpa2",
Enabled: true,
NameCombineEnabled: true,
GroupRekey: 3600,
DTIMMode: "default",
No2GhzOui: true,
MinrateNgCckRatesEnabled: true,
}
resp, err := c.c.CreateWLAN(c.site, req)
if err != nil {
return err
}
d.SetId(resp.ID)
return resourceWLANSetResourceData(resp, d)
}
func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData) error {
var err error
vlan := 0
if resp.VLANEnabled {
vlan, err = strconv.Atoi(resp.VLAN)
if err != nil {
return err
}
}
d.Set("name", resp.Name)
d.Set("vlan_id", vlan)
d.Set("passphrase", resp.XPassphrase)
d.Set("hide_ssid", resp.HideSSID)
d.Set("is_guest", resp.IsGuest)
d.Set("wlan_group_id", resp.WLANGroupID)
d.Set("user_group_id", resp.UserGroupID)
d.Set("security", resp.Security)
return nil
}
func resourceWLANRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
resp, err := c.c.GetWLAN(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
d.SetId("")
return nil
}
if err != nil {
return err
}
return resourceWLANSetResourceData(resp, d)
}
func resourceWLANUpdate(d *schema.ResourceData, meta interface{}) error {
panic("not implemented")
}
func resourceWLANDelete(d *schema.ResourceData, meta interface{}) error {
c := meta.(*client)
id := d.Id()
err := c.c.DeleteWLAN(c.site, id)
if _, ok := err.(*unifi.NotFoundError); ok {
return nil
}
return err
}

View File

@@ -0,0 +1,110 @@
package provider
import (
"os"
"strconv"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
)
var wlanConcurrency chan struct{}
func init() {
wcs := os.Getenv("UNIFI_ACC_WLAN_CONCURRENCY")
if wcs == "" {
// default concurrent SSIDs
wcs = "1"
}
wc, err := strconv.Atoi(wcs)
if err != nil {
panic(err)
}
wlanConcurrency = make(chan struct{}, wc)
}
func TestAccWLAN_wpapsk(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() {
preCheck(t)
wlanConcurrency <- struct{}{}
},
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
<-wlanConcurrency
return nil
},
Steps: []resource.TestStep{
{
Config: testAccWLANConfig_wpapsk,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
importStep("unifi_wlan.test"),
},
})
}
func TestAccWLAN_open(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers,
PreCheck: func() {
preCheck(t)
wlanConcurrency <- struct{}{}
},
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
<-wlanConcurrency
return nil
},
Steps: []resource.TestStep{
{
Config: testAccWLANConfig_open,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
importStep("unifi_wlan.test"),
},
})
}
const testAccWLANConfig_wpapsk = `
data "unifi_wlan_group" "default" {
}
data "unifi_user_group" "default" {
}
resource "unifi_wlan" "test" {
name = "tfacc-wpapsk"
vlan_id = 202
passphrase = "12345678"
wlan_group_id = data.unifi_wlan_group.default.id
user_group_id = data.unifi_user_group.default.id
security = "wpapsk"
}
`
const testAccWLANConfig_open = `
data "unifi_wlan_group" "default" {
}
data "unifi_user_group" "default" {
}
resource "unifi_wlan" "test" {
name = "tfacc-open"
vlan_id = 202
wlan_group_id = data.unifi_wlan_group.default.id
user_group_id = data.unifi_user_group.default.id
security = "open"
}
`