feat: add DNS record resource and datasources (#25)

* add DNS record

* revamp tests

* lint

* cleanup

* feat dns test

* chore: add DNS Record tests

* linting

* f
This commit is contained in:
Mateusz Filipowicz
2025-02-26 01:17:59 +01:00
committed by GitHub
parent 325d7b7f20
commit e7164c0460
82 changed files with 2488 additions and 1274 deletions

View File

@@ -1,7 +1,7 @@
TEST ?= ./... TEST ?= ./...
TESTARGS ?= TESTARGS ?=
TEST_COUNT ?= 1 TEST_COUNT ?= 1
TEST_TIMEOUT ?= 10m TEST_TIMEOUT ?= 20m
.PHONY: default .PHONY: default
default: build default: build

View File

@@ -0,0 +1,11 @@
resource "unifi_dns_record" "a_record" {
name = "example.mydomain.com"
type = "A"
record = "192.168.1.190"
}
resource "unifi_dns_record" "cname_record" {
name = "example.mydomain.com"
type = "CNAME"
record = "example.com"
}

26
go.mod
View File

@@ -13,6 +13,11 @@ require (
github.com/golangci/golangci-lint v1.64.5 github.com/golangci/golangci-lint v1.64.5
github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/terraform-plugin-docs v0.20.1 github.com/hashicorp/terraform-plugin-docs v0.20.1
github.com/hashicorp/terraform-plugin-framework v1.14.1
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0
github.com/hashicorp/terraform-plugin-go v0.26.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-mux v0.18.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1
github.com/hashicorp/terraform-plugin-testing v1.11.0 github.com/hashicorp/terraform-plugin-testing v1.11.0
github.com/testcontainers/testcontainers-go v0.35.0 github.com/testcontainers/testcontainers-go v0.35.0
@@ -34,7 +39,7 @@ require (
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/Crocmagnon/fatcontext v0.7.1 // indirect github.com/Crocmagnon/fatcontext v0.7.1 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect
@@ -193,11 +198,6 @@ require (
github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.22.0 // indirect github.com/hashicorp/terraform-exec v0.22.0 // indirect
github.com/hashicorp/terraform-json v0.24.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-registry-address v0.2.4 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect
@@ -229,7 +229,7 @@ require (
github.com/ldez/usetesting v0.4.2 // indirect github.com/ldez/usetesting v0.4.2 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect github.com/leonklingele/grouper v1.1.2 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect github.com/lufia/plan9stats v0.0.0-20250224150550-a661cff19cfb // indirect
github.com/macabu/inamedparam v0.1.3 // indirect github.com/macabu/inamedparam v0.1.3 // indirect
github.com/magiconair/properties v1.8.9 // indirect github.com/magiconair/properties v1.8.9 // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect
@@ -297,7 +297,7 @@ require (
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc // indirect github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a // indirect github.com/rogpeppe/go-internal v1.14.0 // indirect
github.com/ryancurrah/gomodguard v1.3.5 // indirect github.com/ryancurrah/gomodguard v1.3.5 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect
@@ -388,12 +388,12 @@ require (
go.uber.org/mock v0.5.0 // indirect go.uber.org/mock v0.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.34.0 // indirect golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
golang.org/x/exp/typeparams v0.0.0-20250218142911-aa4b98e5adaa // indirect golang.org/x/exp/typeparams v0.0.0-20250218142911-aa4b98e5adaa // indirect
golang.org/x/mod v0.23.0 // indirect golang.org/x/mod v0.23.0 // indirect
golang.org/x/net v0.35.0 // indirect golang.org/x/net v0.35.0 // indirect
golang.org/x/oauth2 v0.26.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect
golang.org/x/sync v0.11.0 // indirect golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect golang.org/x/term v0.29.0 // indirect
@@ -401,8 +401,8 @@ require (
golang.org/x/time v0.10.0 // indirect golang.org/x/time v0.10.0 // indirect
golang.org/x/tools v0.30.0 // indirect golang.org/x/tools v0.30.0 // indirect
google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 // indirect
google.golang.org/grpc v1.70.0 // indirect google.golang.org/grpc v1.70.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
@@ -423,5 +423,5 @@ require (
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect
tags.cncf.io/container-device-interface v0.8.0 // indirect tags.cncf.io/container-device-interface v0.8.1 // indirect
) )

33
go.sum
View File

@@ -31,8 +31,8 @@ github.com/Crocmagnon/fatcontext v0.7.1 h1:SC/VIbRRZQeQWj/TcQBS6JmrXcfA+BU4OGSVU
github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU= github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU=
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 h1:Sz1JIXEcSfhz7fUi7xHnhpIE0thVASYjvosApmHuD2k=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1/go.mod h1:n/LSCXNuIYqVfBlVXyHfMQkZDdp1/mmxfSjADd3z1Zg=
github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0= github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0=
github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc= github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
@@ -411,7 +411,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -599,8 +598,8 @@ github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjS
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0= github.com/lufia/plan9stats v0.0.0-20250224150550-a661cff19cfb h1:YU0XAr3+rMpM8fP80KEesn32Qa9qkbquokvuwzWyYuA=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/lufia/plan9stats v0.0.0-20250224150550-a661cff19cfb/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -806,8 +805,8 @@ github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtz
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM= github.com/rogpeppe/go-internal v1.14.0 h1:unbRd941gNa8SS77YznHXOYVBDgWcF9xhzECdm8juZc=
github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY= github.com/rogpeppe/go-internal v1.14.0/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
@@ -1064,8 +1063,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.34.0 h1:+/C6tk6rf/+t5DhUketUbD1aNGqiSX3j15Z6xuIDlBA= golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.34.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
@@ -1106,8 +1105,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1218,10 +1217,10 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2 h1:35ZFtrCgaAjF7AFAK0+lRSf+4AyYnWRbH7og13p7rZ4= google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 h1:ilJhrCga0AptpJZXmUYG4MCrx/zf3l1okuYz7YK9PPw=
google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:W9ynFDP/shebLB1Hl/ESTOap2jHd6pmLXPNZC7SVDbA= google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 h1:DMTIbak9GhdaSxEjvVzAeNZvyc03I61duqNbnm3SU0M= google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 h1:ZSlhAUqC4r8TPzqLXQ0m3upBNZeF+Y8jQ3c4CR3Ujms=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
@@ -1288,7 +1287,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf
sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc= tags.cncf.io/container-device-interface v0.8.1 h1:c0jN4Mt6781jD67NdPajmZlD1qrqQyov/Xfoab37lj0=
tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y= tags.cncf.io/container-device-interface v0.8.1/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA= tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA=
tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws= tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws=

View File

@@ -1,4 +1,4 @@
package v1 package acctest
import ( import (
"testing" "testing"
@@ -6,7 +6,7 @@ import (
"github.com/hashicorp/go-version" "github.com/hashicorp/go-version"
) )
func preCheckMinVersion(t *testing.T, min *version.Version) { func PreCheckMinVersion(t *testing.T, min *version.Version) {
v, err := version.NewVersion(testClient.Version()) v, err := version.NewVersion(testClient.Version())
if err != nil { if err != nil {
t.Fatalf("error parsing version: %s", err) t.Fatalf("error parsing version: %s", err)
@@ -16,7 +16,7 @@ func preCheckMinVersion(t *testing.T, min *version.Version) {
} }
} }
func preCheckVersionConstraint(t *testing.T, cs string) { func PreCheckVersionConstraint(t *testing.T, cs string) {
v, err := version.NewVersion(testClient.Version()) v, err := version.NewVersion(testClient.Version())
if err != nil { if err != nil {
t.Fatalf("Error parsing version: %s", err) t.Fatalf("Error parsing version: %s", err)

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
"testing" "testing"
@@ -9,11 +10,7 @@ import (
func TestAccDataAccount_default(t *testing.T) { func TestAccDataAccount_default(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -25,15 +22,10 @@ func TestAccDataAccount_default(t *testing.T) {
} }
func TestAccDataAccount_mac(t *testing.T) { func TestAccDataAccount_mac(t *testing.T) {
mac, unallocateMac := allocateTestMac(t) mac, unallocateMac := pt.AllocateTestMac(t)
defer unallocateMac() defer unallocateMac()
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccDataAccountConfig(mac, mac), Config: testAccDataAccountConfig(mac, mac),

View File

@@ -1,18 +1,12 @@
package v1 package acctest
import ( import (
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
"testing"
) )
func TestAccDataAPGroup_default(t *testing.T) { func TestAccDataAPGroup_default(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccDataAPGroupConfig_default, Config: testAccDataAPGroupConfig_default,

View File

@@ -1,12 +1,11 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"testing"
"github.com/hashicorp/go-version" "github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
"testing"
) )
func TestAccDataNetwork_byName(t *testing.T) { func TestAccDataNetwork_byName(t *testing.T) {
@@ -15,15 +14,10 @@ func TestAccDataNetwork_byName(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("error parsing version: %s", err) t.Fatalf("error parsing version: %s", err)
} }
if v.LessThan(provider.ControllerV7) { if v.LessThan(base.ControllerV7) {
defaultName = "LAN" defaultName = "LAN"
} }
AcceptanceTest(t, AcceptanceTestCase{
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -42,15 +36,11 @@ func TestAccDataNetwork_byID(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("error parsing version: %s", err) t.Fatalf("error parsing version: %s", err)
} }
if v.LessThan(provider.ControllerV7) { if v.LessThan(base.ControllerV7) {
defaultName = "LAN" defaultName = "LAN"
} }
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {

View File

@@ -0,0 +1,25 @@
package acctest
import (
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
func TestAccDataPortProfile_default(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
VersionConstraint: "< 7.4",
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccDataPortProfileConfig_default,
Check: resource.ComposeTestCheckFunc(),
},
},
})
}
const testAccDataPortProfileConfig_default = `
data "unifi_port_profile" "default" {
}
`

View File

@@ -0,0 +1,26 @@
package acctest
import (
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
func TestAccDataUserGroup_default(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccDataUserGroupConfig_default,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
},
})
}
const testAccDataUserGroupConfig_default = `
data "unifi_user_group" "default" {
}
`

View File

@@ -1,4 +1,4 @@
package v1 package acctest
import ( import (
"context" "context"
@@ -7,18 +7,17 @@ import (
"testing" "testing"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
) )
func TestAccDataUser_default(t *testing.T) { func TestAccDataUser_default(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { PreCheck: func() {
//preCheck(t)
_, err := testClient.CreateUser(context.Background(), "default", &unifi.User{ _, err := testClient.CreateUser(context.Background(), "default", &unifi.User{
MAC: mac, MAC: mac,
Name: name, Name: name,
@@ -28,8 +27,6 @@ func TestAccDataUser_default(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
}, },
//PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccDataUserConfig_default(mac), Config: testAccDataUserConfig_default(mac),

View File

@@ -0,0 +1,106 @@
package acctest
import (
"fmt"
"regexp"
"testing"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
const testDnsRecordDataSourceName = "data.unifi_dns_record.test"
func TestDNSRecordDataSource_basic(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
record string
recordType string
filterByName bool
}{
{
name: "filter by name",
record: "192.168.1.100",
recordType: "A",
filterByName: true,
},
{
name: "filter by record",
record: "192.168.1.200",
recordType: "A",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
recordName := pt.RandHostname()
r := dnsRecordTestCase{
recordName: recordName,
record: tc.record,
recordType: tc.recordType,
}
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
Steps: Steps{
{
Config: pt.ComposeConfig(testAccDnsRecordConfig(r), testAccDnsRecordDataSourceConfig(r, tc.filterByName)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(testDnsRecordDataSourceName, "name", recordName),
resource.TestCheckResourceAttr(testDnsRecordDataSourceName, "record", tc.record),
resource.TestCheckResourceAttr(testDnsRecordDataSourceName, "type", tc.recordType),
),
},
},
})
})
}
}
var (
dnsDataSourceFilterErrorRegex = regexp.MustCompile(`[filter.name,filter.record]`)
)
func TestDNSRecordDataSource_failWithoutFilter(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
Steps: Steps{
{
Config: testAccDnsRecordDataSourceWithoutFilter(),
ExpectError: dnsDataSourceFilterErrorRegex,
},
},
})
}
func testAccDnsRecordDataSourceConfig(tc dnsRecordTestCase, filterByName bool) string {
filter := ""
if filterByName {
filter = "name = \"" + tc.recordName + "\""
} else {
filter = "record = \"" + tc.record + "\""
}
return fmt.Sprintf(`
data "unifi_dns_record" "test" {
filter {
%s
}
depends_on = [unifi_dns_record.test]
}`, filter)
}
func testAccDnsRecordDataSourceWithoutFilter() string {
return `
data "unifi_dns_record" "test" {
filter {
}
}`
}

View File

@@ -0,0 +1,88 @@
package acctest
import (
"fmt"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"strings"
"testing"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
const testDnsRecordsDataSourceName = "data.unifi_dns_records.test"
func TestDNSRecordsDataSource_basic(t *testing.T) {
records := []*dnsRecordTestCase{
{
name: "test1",
record: "192.168.1.100",
recordType: "A",
},
{
name: "test2",
record: "192.168.1.200",
recordType: "A",
},
{
name: "mail",
record: "mail.example.com",
recordType: "MX",
priority: intPtr(10),
},
}
var configs []string
var dependencies []string
for _, record := range records {
record.recordName = pt.RandHostname()
resourceName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
configs = append(configs, testAccDnsRecordConfigWithResourceName(resourceName, *record))
dependencies = append(dependencies, fmt.Sprintf("unifi_dns_record.%s", resourceName))
}
configs = append(configs, testAccDnsRecordsDataSourceConfig(dependencies))
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
Steps: Steps{
{
Config: pt.ComposeConfig(configs...),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(testDnsRecordsDataSourceName, "result.#", "3"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.0.name"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.0.record"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.0.type"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.1.name"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.1.record"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.1.type"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.2.name"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.2.record"),
resource.TestCheckResourceAttrSet(testDnsRecordsDataSourceName, "result.2.type"),
),
},
},
})
}
func TestDNSRecordsDataSource_noRecords(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
Steps: Steps{
{
Config: testAccDnsRecordsDataSourceConfig(nil),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(testDnsRecordsDataSourceName, "result.#", "0"),
),
},
},
})
}
func testAccDnsRecordsDataSourceConfig(deps []string) string {
return `
data "unifi_dns_records" "test" {
depends_on = [
` + strings.Join(deps, ",") + `
]
}`
}

View File

@@ -0,0 +1,94 @@
package acctest
import (
"context"
"fmt"
"github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/go-version"
"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-mux/tf5to6server"
"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"os"
"testing"
)
type providersMap map[string]func() (tfprotov6.ProviderServer, error)
var (
providers = createProviders()
testClient unifi.Client
)
type Steps []resource.TestStep
type AcceptanceTestCase struct {
CheckDestroy resource.TestCheckFunc
VersionConstraint string
MinVersion *version.Version
PreCheck func()
Steps Steps
}
func AcceptanceTest(t *testing.T, testCase AcceptanceTestCase) {
t.Helper()
if len(testCase.Steps) == 0 {
t.Fatal("missing test steps")
}
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
pt.PreCheck(t)
if testCase.VersionConstraint != "" {
PreCheckVersionConstraint(t, testCase.VersionConstraint)
}
if testCase.MinVersion != nil {
PreCheckMinVersion(t, testCase.MinVersion)
}
if testCase.PreCheck != nil {
testCase.PreCheck()
}
},
ProtoV6ProviderFactories: providers,
CheckDestroy: testCase.CheckDestroy,
Steps: testCase.Steps,
})
}
func TestMain(m *testing.M) {
providers = createProviders()
os.Exit(pt.Run(m, func(env *pt.TestEnvironment) {
testClient = env.Client
}))
}
func createProviders() providersMap {
ctx := context.Background()
// Init mux servers
return map[string]func() (tfprotov6.ProviderServer, error){
"unifi": func() (tfprotov6.ProviderServer, error) {
return tf6muxserver.NewMuxServer(ctx,
providerserver.NewProtocol6(provider.NewV2("acctestv2")()),
func() tfprotov6.ProviderServer {
sdkV2Provider, err := tf5to6server.UpgradeServer(
ctx,
func() tfprotov5.ProviderServer {
return schema.NewGRPCProviderServer(
provider.New("acctestv1")(),
)
},
)
if err != nil {
panic(fmt.Errorf("failed to create test providers: %w", err))
}
return sdkV2Provider
},
)
},
}
}

View File

@@ -1,18 +1,17 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"testing" "testing"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
) )
func TestAccAccount_basic(t *testing.T) { func TestAccAccount_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -22,17 +21,15 @@ func TestAccAccount_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_account.test", "name", name), resource.TestCheckResourceAttr("unifi_account.test", "name", name),
), ),
}, },
importStep("unifi_account.test"), pt.ImportStep("unifi_account.test"),
}, },
}) })
} }
func TestAccAccount_mac(t *testing.T) { func TestAccAccount_mac(t *testing.T) {
mac, unallocateMac := allocateTestMac(t) mac, unallocateMac := pt.AllocateTestMac(t)
defer unallocateMac() defer unallocateMac()
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -43,7 +40,7 @@ func TestAccAccount_mac(t *testing.T) {
resource.TestCheckResourceAttr("unifi_account.test", "password", mac), resource.TestCheckResourceAttr("unifi_account.test", "password", mac),
), ),
}, },
importStep("unifi_account.test"), pt.ImportStep("unifi_account.test"),
}, },
}) })
} }

View File

@@ -1,4 +1,4 @@
package v1 package acctest
import ( import (
"context" "context"
@@ -11,6 +11,7 @@ import (
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/terraform"
@@ -22,6 +23,7 @@ var (
) )
func allocateDevice(t *testing.T) (*unifi.Device, func()) { func allocateDevice(t *testing.T) (*unifi.Device, func()) {
pt.MarkAccTest(t)
ctx := context.Background() ctx := context.Background()
deviceInit.Do(func() { deviceInit.Do(func() {
@@ -175,10 +177,8 @@ func preCheckDeviceExists(t *testing.T, site, mac string) {
} }
func TestAccDevice_empty(t *testing.T) { func TestAccDevice_empty(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) }, CheckDestroy: testAccCheckDeviceDestroy,
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckDeviceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccDeviceConfigEmpty(), Config: testAccDeviceConfigEmpty(),
@@ -198,13 +198,11 @@ func TestAccDevice_switch_basic(t *testing.T) {
importStateVerifyIgnore := []string{"allow_adoption", "forget_on_destroy", "name"} importStateVerifyIgnore := []string{"allow_adoption", "forget_on_destroy", "name"}
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t)
preCheckDeviceExists(t, site, device.MAC) preCheckDeviceExists(t, site, device.MAC)
}, },
ProviderFactories: providerFactories, CheckDestroy: testAccCheckDeviceDestroy,
CheckDestroy: testAccCheckDeviceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccDeviceConfig(device.MAC), Config: testAccDeviceConfig(device.MAC),
@@ -253,14 +251,12 @@ func TestAccDevice_switch_portOverrides(t *testing.T) {
device, unallocateDevice := allocateDevice(t) device, unallocateDevice := allocateDevice(t)
defer unallocateDevice() defer unallocateDevice()
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
VersionConstraint: "< 7.4",
PreCheck: func() { PreCheck: func() {
preCheck(t)
preCheckDeviceExists(t, site, device.MAC) preCheckDeviceExists(t, site, device.MAC)
preCheckVersionConstraint(t, "< 7.4")
}, },
ProviderFactories: providerFactories, CheckDestroy: testAccCheckDeviceDestroy,
CheckDestroy: testAccCheckDeviceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccDeviceConfig_withPortOverrides(device.MAC), Config: testAccDeviceConfig_withPortOverrides(device.MAC),

View File

@@ -0,0 +1,318 @@
package acctest
import (
"context"
"fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"strconv"
"strings"
"testing"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)
const testDnsRecordResourceName = "unifi_dns_record.test"
type dnsRecordTestCase struct {
name string
recordName string
record string
recordType string
ttl *int
enabled *bool
priority *int
port *int
weight *int
}
func TestDNSRecord_basic(t *testing.T) {
t.Parallel()
testCases := []dnsRecordTestCase{
{
name: "A record",
recordName: "test.com",
record: "192.168.0.128",
recordType: "A",
},
{
name: "AAAA record",
recordName: "ipv6.test.com",
record: "2001:db8::1",
recordType: "AAAA",
},
{
name: "CNAME record",
recordName: "alias.test.com",
record: "target.test.com",
recordType: "CNAME",
},
{
name: "NS record",
recordName: "ns.test.com",
record: "127.0.0.1",
recordType: "NS",
},
{
name: "MX record with priority",
recordName: "mail.test.com",
record: "mx.test.com",
recordType: "MX",
priority: intPtr(10),
},
{
name: "disabled A record",
recordName: "disabled.test.com",
record: "192.168.1.100",
recordType: "A",
enabled: boolPtr(false),
},
{
name: "A record with TTL",
recordName: "ttl.test.com",
record: "192.168.1.100",
recordType: "A",
ttl: intPtr(3600),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
steps := []resource.TestStep{
{
Config: testAccDnsRecordConfig(tc),
Check: testAccDnsRecordCheckAttrs(tc),
},
pt.ImportStep(testDnsRecordResourceName),
}
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
Steps: steps,
CheckDestroy: testAccCheckDNSRecordDestroy,
})
})
}
}
func TestDNSRecord_SRV(t *testing.T) {
t.Parallel()
testCases := []dnsRecordTestCase{
{
name: "SRV record with all fields",
recordName: "_sip._tcp.test.com",
record: "sip.test.com",
recordType: "SRV",
port: intPtr(5060),
priority: intPtr(10),
weight: intPtr(20),
},
{
name: "SRV record with minimal fields",
recordName: "_ldap._tcp.test.com",
record: "ldap.test.com",
recordType: "SRV",
port: intPtr(389),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
CheckDestroy: testAccCheckDNSRecordDestroy,
Steps: Steps{
{
Config: testAccDnsRecordConfig(tc),
Check: testAccDnsRecordCheckAttrs(tc),
},
},
})
})
}
}
func TestDNSRecord_Update(t *testing.T) {
initial := dnsRecordTestCase{
name: "initial",
recordName: "update.test.com",
record: "192.168.1.100",
recordType: "A",
ttl: intPtr(3600),
}
updated := dnsRecordTestCase{
name: "updated",
recordName: "update.test.com",
record: "192.168.1.200",
recordType: "A",
ttl: intPtr(7200),
}
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
CheckDestroy: testAccCheckDNSRecordDestroy,
Steps: Steps{
{
Config: testAccDnsRecordConfig(initial),
Check: testAccDnsRecordCheckAttrs(initial),
},
{
Config: testAccDnsRecordConfig(updated),
Check: testAccDnsRecordCheckAttrs(updated),
ConfigPlanChecks: pt.CheckResourceAction(testDnsRecordResourceName, plancheck.ResourceActionUpdate),
},
},
})
}
func TestDNSRecord_MissingAttributes(t *testing.T) {
t.Parallel()
testCases := map[string]func() string{
"name": testAccDnsRecordConfigMissingName,
"record": testAccDnsRecordConfigMissingRecord,
"type": testAccDnsRecordConfigMissingType,
}
for k, v := range testCases {
t.Run(fmt.Sprintf("missing %s", k), func(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
MinVersion: base.ControllerVersionDnsRecords,
Steps: Steps{
{
Config: v(),
ExpectError: pt.MissingArgumentErrorRegex(k),
},
},
})
})
}
}
func testAccCheckDNSRecordDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "unifi_dns_record" {
continue
}
_, err := testClient.GetDNSRecord(context.Background(), "default", rs.Primary.ID)
if err == nil {
return fmt.Errorf("DNS Record %s still exists", rs.Primary.ID)
}
// If we get a 404 error, that means the resource was deleted
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
continue
}
// For any other error, return it
return err
}
return nil
}
func testAccDnsRecordConfig(tc dnsRecordTestCase) string {
return testAccDnsRecordConfigWithResourceName("test", tc)
}
func testAccDnsRecordConfigMissingName() string {
return `
resource "unifi_dns_record" "test" {
record = "127.0.0.1"
type = "A"
}
`
}
func testAccDnsRecordConfigMissingRecord() string {
return `
resource "unifi_dns_record" "test" {
name = "test.com"
type = "A"
}
`
}
func testAccDnsRecordConfigMissingType() string {
return `
resource "unifi_dns_record" "test" {
name = "test.com"
record = "127.0.0.1"
}
`
}
func testAccDnsRecordConfigWithResourceName(resourceName string, tc dnsRecordTestCase) string {
var attrs string
if tc.ttl != nil {
attrs += fmt.Sprintf("\tttl = %d\n", *tc.ttl)
}
if tc.enabled != nil {
attrs += fmt.Sprintf("\tenabled = %t\n", *tc.enabled)
}
if tc.priority != nil {
attrs += fmt.Sprintf("\tpriority = %d\n", *tc.priority)
}
if tc.port != nil {
attrs += fmt.Sprintf("\tport = %d\n", *tc.port)
}
if tc.weight != nil {
attrs += fmt.Sprintf("\tweight = %d\n", *tc.weight)
}
return fmt.Sprintf(`
resource "unifi_dns_record" "%s" {
name = "%s"
record = "%s"
type = "%s"
%s}
`, resourceName, tc.recordName, tc.record, tc.recordType, attrs)
}
func testAccDnsRecordCheckAttrs(tc dnsRecordTestCase) resource.TestCheckFunc {
// expected default values
var (
ttl = 0
enabled = true
priority = 0
port = 0
weight = 0
)
if tc.ttl != nil {
ttl = *tc.ttl
}
if tc.enabled != nil {
enabled = *tc.enabled
}
if tc.priority != nil {
priority = *tc.priority
}
if tc.port != nil {
port = *tc.port
}
if tc.weight != nil {
weight = *tc.weight
}
checks := []resource.TestCheckFunc{
resource.TestCheckResourceAttr(testDnsRecordResourceName, "name", tc.recordName),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "record", tc.record),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "type", tc.recordType),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "ttl", strconv.Itoa(ttl)),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "enabled", strconv.FormatBool(enabled)),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "priority", strconv.Itoa(priority)),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "port", strconv.Itoa(port)),
resource.TestCheckResourceAttr(testDnsRecordResourceName, "weight", strconv.Itoa(weight)),
}
return resource.ComposeTestCheckFunc(checks...)
}
func intPtr(i int) *int {
return &i
}
func boolPtr(b bool) *bool {
return &b
}

View File

@@ -1,15 +1,14 @@
package v1 package acctest
import ( import (
"testing" "testing"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
) )
func TestAccDynamicDNS_dyndns(t *testing.T) { func TestAccDynamicDNS_dyndns(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -18,7 +17,7 @@ func TestAccDynamicDNS_dyndns(t *testing.T) {
// // testCheckFirewallGroupExists(t, "name"), // // testCheckFirewallGroupExists(t, "name"),
// ), // ),
}, },
importStep("unifi_dynamic_dns.test"), pt.ImportStep("unifi_dynamic_dns.test"),
}, },
}) })
} }

View File

@@ -1,4 +1,4 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
@@ -7,14 +7,13 @@ import (
"strings" "strings"
"testing" "testing"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
) )
func TestAccFirewallGroup_port_group(t *testing.T) { func TestAccFirewallGroup_port_group(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -23,20 +22,18 @@ func TestAccFirewallGroup_port_group(t *testing.T) {
// // testCheckFirewallGroupExists(t, "name"), // // testCheckFirewallGroupExists(t, "name"),
// ), // ),
}, },
importStep("unifi_firewall_group.test"), pt.ImportStep("unifi_firewall_group.test"),
{ {
Config: testAccFirewallGroupConfig(name, "port-group", []string{"80", "443"}), Config: testAccFirewallGroupConfig(name, "port-group", []string{"80", "443"}),
}, },
importStep("unifi_firewall_group.test"), pt.ImportStep("unifi_firewall_group.test"),
}, },
}) })
} }
func TestAccFirewallGroup_address_group(t *testing.T) { func TestAccFirewallGroup_address_group(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -45,23 +42,21 @@ func TestAccFirewallGroup_address_group(t *testing.T) {
// // testCheckFirewallGroupExists(t, "name"), // // testCheckFirewallGroupExists(t, "name"),
// ), // ),
}, },
importStep("unifi_firewall_group.test"), pt.ImportStep("unifi_firewall_group.test"),
{ {
Config: testAccFirewallGroupConfig(name, "address-group", []string{"10.0.0.1", "10.0.0.2"}), Config: testAccFirewallGroupConfig(name, "address-group", []string{"10.0.0.1", "10.0.0.2"}),
}, },
importStep("unifi_firewall_group.test"), pt.ImportStep("unifi_firewall_group.test"),
{ {
Config: testAccFirewallGroupConfig(name, "address-group", []string{"10.0.0.0/24"}), Config: testAccFirewallGroupConfig(name, "address-group", []string{"10.0.0.0/24"}),
}, },
importStep("unifi_firewall_group.test"), pt.ImportStep("unifi_firewall_group.test"),
}, },
}) })
} }
func TestAccFirewallGroup_same_name(t *testing.T) { func TestAccFirewallGroup_same_name(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {

View File

@@ -1,10 +1,11 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"testing" "testing"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
) )
@@ -12,9 +13,7 @@ import (
func TestAccFirewallRule_basic(t *testing.T) { func TestAccFirewallRule_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -24,14 +23,14 @@ func TestAccFirewallRule_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_firewall_rule.test", "enabled", "true"), resource.TestCheckResourceAttr("unifi_firewall_rule.test", "enabled", "true"),
), ),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
{ {
Config: testAccFirewallRuleConfig(name, false), Config: testAccFirewallRuleConfig(name, false),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("unifi_firewall_rule.test", "enabled", "false"), resource.TestCheckResourceAttr("unifi_firewall_rule.test", "enabled", "false"),
), ),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
}, },
}) })
} }
@@ -39,9 +38,7 @@ func TestAccFirewallRule_basic(t *testing.T) {
func TestAccFirewallRule_port(t *testing.T) { func TestAccFirewallRule_port(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccFirewallRuleConfigWithPort(name), Config: testAccFirewallRuleConfigWithPort(name),
@@ -50,7 +47,7 @@ func TestAccFirewallRule_port(t *testing.T) {
resource.TestCheckResourceAttr("unifi_firewall_rule.test", "dst_port", "53"), resource.TestCheckResourceAttr("unifi_firewall_rule.test", "dst_port", "53"),
), ),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
}, },
}) })
} }
@@ -58,14 +55,12 @@ func TestAccFirewallRule_port(t *testing.T) {
func TestAccFirewallRule_icmp(t *testing.T) { func TestAccFirewallRule_icmp(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccFirewallRuleConfigWithICMP(name), Config: testAccFirewallRuleConfigWithICMP(name),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
}, },
}) })
} }
@@ -73,9 +68,7 @@ func TestAccFirewallRule_icmp(t *testing.T) {
func TestAccFirewallRule_multiple_address_groups(t *testing.T) { func TestAccFirewallRule_multiple_address_groups(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -89,9 +82,7 @@ func TestAccFirewallRule_multiple_address_groups(t *testing.T) {
func TestAccFirewallRule_multiple_port_groups(t *testing.T) { func TestAccFirewallRule_multiple_port_groups(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -105,9 +96,7 @@ func TestAccFirewallRule_multiple_port_groups(t *testing.T) {
func TestAccFirewallRule_address_and_port_group(t *testing.T) { func TestAccFirewallRule_address_and_port_group(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -116,7 +105,7 @@ func TestAccFirewallRule_address_and_port_group(t *testing.T) {
// // testCheckFirewallGroupExists(t, "name"), // // testCheckFirewallGroupExists(t, "name"),
// ), // ),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
}, },
}) })
} }
@@ -124,15 +113,13 @@ func TestAccFirewallRule_address_and_port_group(t *testing.T) {
func TestAccFirewallRule_IPv6_basic(t *testing.T) { func TestAccFirewallRule_IPv6_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccFirewallRuleConfigIPv6(name), Config: testAccFirewallRuleConfigIPv6(name),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
}, },
}) })
} }
@@ -140,14 +127,12 @@ func TestAccFirewallRule_IPv6_basic(t *testing.T) {
func TestAccFirewallRule_IPv6_dst_port(t *testing.T) { func TestAccFirewallRule_IPv6_dst_port(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccFirewallRuleConfigIPv6WithPort(name), Config: testAccFirewallRuleConfigIPv6WithPort(name),
}, },
importStep("unifi_firewall_rule.test"), pt.ImportStep("unifi_firewall_rule.test"),
}, },
}) })
} }

View File

@@ -1,8 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"net" "net"
"regexp" "regexp"
"strconv" "strconv"
@@ -15,12 +15,10 @@ import (
func TestAccNetwork_basic(t *testing.T) { func TestAccNetwork_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet1, vlan1 := getTestVLAN(t) subnet1, vlan1 := pt.GetTestVLAN(t)
subnet2, vlan2 := getTestVLAN(t) subnet2, vlan2 := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -31,7 +29,7 @@ func TestAccNetwork_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "igmp_snooping", "true"), resource.TestCheckResourceAttr("unifi_network.test", "igmp_snooping", "true"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfig(name, subnet2, vlan2, false, nil), Config: testAccNetworkConfig(name, subnet2, vlan2, false, nil),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
@@ -39,12 +37,12 @@ func TestAccNetwork_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "igmp_snooping", "false"), resource.TestCheckResourceAttr("unifi_network.test", "igmp_snooping", "false"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
// re-test import here with default site, but full ID string // re-test import here with default site, but full ID string
{ {
ResourceName: "unifi_network.test", ResourceName: "unifi_network.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_network.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_network.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },
@@ -53,11 +51,9 @@ func TestAccNetwork_basic(t *testing.T) {
func TestAccNetwork_weird_cidr(t *testing.T) { func TestAccNetwork_weird_cidr(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -66,18 +62,16 @@ func TestAccNetwork_weird_cidr(t *testing.T) {
// TODO: ... // TODO: ...
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
}, },
}) })
} }
func TestAccNetwork_dhcp_dns(t *testing.T) { func TestAccNetwork_dhcp_dns(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -86,7 +80,7 @@ func TestAccNetwork_dhcp_dns(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "dhcp_dns.0", "192.168.1.101"), resource.TestCheckResourceAttr("unifi_network.test", "dhcp_dns.0", "192.168.1.101"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfig(name, subnet, vlan, true, []string{"192.168.1.101", "192.168.1.102"}), Config: testAccNetworkConfig(name, subnet, vlan, true, []string{"192.168.1.101", "192.168.1.102"}),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
@@ -94,7 +88,7 @@ func TestAccNetwork_dhcp_dns(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "dhcp_dns.1", "192.168.1.102"), resource.TestCheckResourceAttr("unifi_network.test", "dhcp_dns.1", "192.168.1.102"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfig(name, subnet, vlan, true, nil), Config: testAccNetworkConfig(name, subnet, vlan, true, nil),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
@@ -113,11 +107,9 @@ func TestAccNetwork_dhcp_dns(t *testing.T) {
func TestAccNetwork_dhcp_boot(t *testing.T) { func TestAccNetwork_dhcp_boot(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -126,7 +118,7 @@ func TestAccNetwork_dhcp_boot(t *testing.T) {
// TODO: ... // TODO: ...
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
}, },
}) })
} }
@@ -135,13 +127,11 @@ func TestAccNetwork_v6(t *testing.T) {
t.Skip("FIXME") t.Skip("FIXME")
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet1, vlan1 := getTestVLAN(t) subnet1, vlan1 := pt.GetTestVLAN(t)
subnet2, vlan2 := getTestVLAN(t) subnet2, vlan2 := pt.GetTestVLAN(t)
subnet3, vlan3 := getTestVLAN(t) subnet3, vlan3 := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -152,7 +142,7 @@ func TestAccNetwork_v6(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "ipv6_static_subnet", "fd6a:37be:e362::1/64"), resource.TestCheckResourceAttr("unifi_network.test", "ipv6_static_subnet", "fd6a:37be:e362::1/64"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfigV6(name, subnet2, vlan2, "static", "fd6a:37be:e363::1/64"), Config: testAccNetworkConfigV6(name, subnet2, vlan2, "static", "fd6a:37be:e363::1/64"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
@@ -160,7 +150,7 @@ func TestAccNetwork_v6(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "ipv6_static_subnet", "fd6a:37be:e363::1/64"), resource.TestCheckResourceAttr("unifi_network.test", "ipv6_static_subnet", "fd6a:37be:e363::1/64"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfigDhcpV6( Config: testAccNetworkConfigDhcpV6(
name, name,
@@ -195,9 +185,7 @@ func TestAccNetwork_v6(t *testing.T) {
func TestAccNetwork_wan(t *testing.T) { func TestAccNetwork_wan(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -214,7 +202,7 @@ func TestAccNetwork_wan(t *testing.T) {
resource.TestCheckOutput("wan_dns2", "4.4.4.4"), resource.TestCheckOutput("wan_dns2", "4.4.4.4"),
), ),
}, },
importStep("unifi_network.wan_test"), pt.ImportStep("unifi_network.wan_test"),
// remove qos // remove qos
{ {
Config: testWanNetworkConfig(name, "WAN", "pppoe", "192.168.1.1", 0, "username", "password", "8.8.8.8", "4.4.4.4"), Config: testWanNetworkConfig(name, "WAN", "pppoe", "192.168.1.1", 0, "username", "password", "8.8.8.8", "4.4.4.4"),
@@ -230,7 +218,7 @@ func TestAccNetwork_wan(t *testing.T) {
resource.TestCheckOutput("wan_dns2", "4.4.4.4"), resource.TestCheckOutput("wan_dns2", "4.4.4.4"),
), ),
}, },
importStep("unifi_network.wan_test"), pt.ImportStep("unifi_network.wan_test"),
{ {
Config: testWanNetworkConfig(name, "WAN", "pppoe", "192.168.1.1", 1, "username", "password", "8.8.8.8", "4.4.4.4"), Config: testWanNetworkConfig(name, "WAN", "pppoe", "192.168.1.1", 1, "username", "password", "8.8.8.8", "4.4.4.4"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
@@ -245,7 +233,7 @@ func TestAccNetwork_wan(t *testing.T) {
resource.TestCheckOutput("wan_dns2", "4.4.4.4"), resource.TestCheckOutput("wan_dns2", "4.4.4.4"),
), ),
}, },
importStep("unifi_network.wan_test"), pt.ImportStep("unifi_network.wan_test"),
{ {
Config: testWanV6NetworkConfig(name, "dhcpv6", 47), Config: testWanV6NetworkConfig(name, "dhcpv6", 47),
ExpectError: regexp.MustCompile(regexp.QuoteMeta("expected wan_dhcp_v6_pd_size to be in the range (48 - 64)")), ExpectError: regexp.MustCompile(regexp.QuoteMeta("expected wan_dhcp_v6_pd_size to be in the range (48 - 64)")),
@@ -267,12 +255,10 @@ func TestAccNetwork_wan(t *testing.T) {
func TestAccNetwork_differentSite(t *testing.T) { func TestAccNetwork_differentSite(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet1, vlan1 := getTestVLAN(t) subnet1, vlan1 := pt.GetTestVLAN(t)
subnet2, vlan2 := getTestVLAN(t) subnet2, vlan2 := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -284,7 +270,7 @@ func TestAccNetwork_differentSite(t *testing.T) {
{ {
ResourceName: "unifi_network.test", ResourceName: "unifi_network.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_network.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_network.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
{ {
@@ -296,7 +282,7 @@ func TestAccNetwork_differentSite(t *testing.T) {
{ {
ResourceName: "unifi_network.test", ResourceName: "unifi_network.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_network.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_network.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },
@@ -305,13 +291,11 @@ func TestAccNetwork_differentSite(t *testing.T) {
func TestAccNetwork_importByName(t *testing.T) { func TestAccNetwork_importByName(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet1, vlan1 := getTestVLAN(t) subnet1, vlan1 := pt.GetTestVLAN(t)
subnet2, vlan2 := getTestVLAN(t) subnet2, vlan2 := pt.GetTestVLAN(t)
subnet3, vlan3 := getTestVLAN(t) subnet3, vlan3 := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
// Apply and import network by name. // Apply and import network by name.
{ {
@@ -352,13 +336,9 @@ func TestAccNetwork_importByName(t *testing.T) {
func TestAccNetwork_dhcpRelay(t *testing.T) { func TestAccNetwork_dhcpRelay(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -367,27 +347,23 @@ func TestAccNetwork_dhcpRelay(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "dhcp_relay_enabled", "true"), resource.TestCheckResourceAttr("unifi_network.test", "dhcp_relay_enabled", "true"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfigDHCPRelay(name, subnet, vlan, false), Config: testAccNetworkConfigDHCPRelay(name, subnet, vlan, false),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("unifi_network.test", "dhcp_relay_enabled", "false"), resource.TestCheckResourceAttr("unifi_network.test", "dhcp_relay_enabled", "false"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
}, },
}) })
} }
func TestAccNetwork_vlanOnly(t *testing.T) { func TestAccNetwork_vlanOnly(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
_, vlan := getTestVLAN(t) _, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() {
preCheck(t)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -399,7 +375,7 @@ func TestAccNetwork_vlanOnly(t *testing.T) {
{ {
ResourceName: "unifi_network.test", ResourceName: "unifi_network.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_network.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_network.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },
@@ -408,14 +384,10 @@ func TestAccNetwork_vlanOnly(t *testing.T) {
func TestAccNetwork_mdns(t *testing.T) { func TestAccNetwork_mdns(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { VersionConstraint: "> 7.0",
preCheck(t)
preCheckMinVersion(t, provider.ControllerV7)
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -424,14 +396,14 @@ func TestAccNetwork_mdns(t *testing.T) {
resource.TestCheckResourceAttr("unifi_network.test", "multicast_dns", "true"), resource.TestCheckResourceAttr("unifi_network.test", "multicast_dns", "true"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
{ {
Config: testAccNetworkConfigMDNS(name, subnet, vlan, false), Config: testAccNetworkConfigMDNS(name, subnet, vlan, false),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("unifi_network.test", "multicast_dns", "false"), resource.TestCheckResourceAttr("unifi_network.test", "multicast_dns", "false"),
), ),
}, },
importStep("unifi_network.test"), pt.ImportStep("unifi_network.test"),
}, },
}) })
} }

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"testing" "testing"
@@ -12,9 +13,7 @@ func TestAccPortForward_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
name2 := acctest.RandomWithPrefix("tfacc") name2 := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -24,7 +23,7 @@ func TestAccPortForward_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_port_forward.test", "dst_port", "22"), resource.TestCheckResourceAttr("unifi_port_forward.test", "dst_port", "22"),
), ),
}, },
importStep("unifi_port_forward.test"), pt.ImportStep("unifi_port_forward.test"),
{ {
Config: testAccPortForwardConfig("22", false, "10.1.1.2", "8022", name), Config: testAccPortForwardConfig("22", false, "10.1.1.2", "8022", name),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
@@ -32,23 +31,21 @@ func TestAccPortForward_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_port_forward.test", "fwd_ip", "10.1.1.2"), resource.TestCheckResourceAttr("unifi_port_forward.test", "fwd_ip", "10.1.1.2"),
), ),
}, },
importStep("unifi_port_forward.test"), pt.ImportStep("unifi_port_forward.test"),
{ {
Config: testAccPortForwardConfig("22", false, "10.1.1.1", "22", name2), Config: testAccPortForwardConfig("22", false, "10.1.1.1", "22", name2),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("unifi_port_forward.test", "name", name2), resource.TestCheckResourceAttr("unifi_port_forward.test", "name", name2),
), ),
}, },
importStep("unifi_port_forward.test"), pt.ImportStep("unifi_port_forward.test"),
}, },
}) })
} }
func TestAccPortForward_src_ip(t *testing.T) { func TestAccPortForward_src_ip(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -58,16 +55,14 @@ func TestAccPortForward_src_ip(t *testing.T) {
resource.TestCheckResourceAttr("unifi_port_forward.test", "dst_port", "22"), resource.TestCheckResourceAttr("unifi_port_forward.test", "dst_port", "22"),
), ),
}, },
importStep("unifi_port_forward.test"), pt.ImportStep("unifi_port_forward.test"),
}, },
}) })
} }
func TestAccPortForward_src_cidr(t *testing.T) { func TestAccPortForward_src_cidr(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -77,7 +72,7 @@ func TestAccPortForward_src_cidr(t *testing.T) {
resource.TestCheckResourceAttr("unifi_port_forward.test", "dst_port", "22"), resource.TestCheckResourceAttr("unifi_port_forward.test", "dst_port", "22"),
), ),
}, },
importStep("unifi_port_forward.test"), pt.ImportStep("unifi_port_forward.test"),
}, },
}) })
} }

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"testing" "testing"
@@ -10,12 +11,8 @@ import (
func TestAccPortProfile_basic(t *testing.T) { func TestAccPortProfile_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { VersionConstraint: "< 7.4",
preCheck(t)
preCheckVersionConstraint(t, "< 7.4")
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -25,7 +22,7 @@ func TestAccPortProfile_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_port_profile.test", "name", name), resource.TestCheckResourceAttr("unifi_port_profile.test", "name", name),
), ),
}, },
importStep("unifi_port_profile.test"), pt.ImportStep("unifi_port_profile.test"),
}, },
}) })
} }

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"testing" "testing"
@@ -10,9 +11,7 @@ import (
func TestAccRadiusProfile_basic(t *testing.T) { func TestAccRadiusProfile_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -21,16 +20,14 @@ func TestAccRadiusProfile_basic(t *testing.T) {
resource.TestCheckResourceAttr("unifi_radius_profile.test", "name", name), resource.TestCheckResourceAttr("unifi_radius_profile.test", "name", name),
), ),
}, },
importStep("unifi_radius_profile.test"), pt.ImportStep("unifi_radius_profile.test"),
}, },
}) })
} }
func TestAccRadiusProfile_servers(t *testing.T) { func TestAccRadiusProfile_servers(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -39,15 +36,13 @@ func TestAccRadiusProfile_servers(t *testing.T) {
resource.TestCheckResourceAttr("unifi_radius_profile.test", "name", name), resource.TestCheckResourceAttr("unifi_radius_profile.test", "name", name),
), ),
}, },
importStep("unifi_radius_profile.test"), pt.ImportStep("unifi_radius_profile.test"),
}, },
}) })
} }
func TestAccRadiusProfile_importByName(t *testing.T) { func TestAccRadiusProfile_importByName(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
// Apply and import network by name. // Apply and import network by name.
{ {

View File

@@ -1,6 +1,7 @@
package v1 package acctest
import ( import (
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"sync" "sync"
"testing" "testing"
@@ -12,19 +13,19 @@ var settingMgmtLock = sync.Mutex{}
func TestAccSettingMgmt_basic(t *testing.T) { func TestAccSettingMgmt_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingMgmtLock.Lock() settingMgmtLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingMgmtLock.Unlock() settingMgmtLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingMgmtConfig_basic(), Config: testAccSettingMgmtConfig_basic(),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_mgmt.test"), pt.ImportStep("unifi_setting_mgmt.test"),
}, },
}) })
} }
@@ -32,13 +33,13 @@ func TestAccSettingMgmt_basic(t *testing.T) {
func TestAccSettingMgmt_site(t *testing.T) { func TestAccSettingMgmt_site(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingMgmtLock.Lock() settingMgmtLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingMgmtLock.Unlock() settingMgmtLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingMgmtConfig_site(), Config: testAccSettingMgmtConfig_site(),
@@ -47,7 +48,7 @@ func TestAccSettingMgmt_site(t *testing.T) {
{ {
ResourceName: "unifi_setting_mgmt.test", ResourceName: "unifi_setting_mgmt.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_setting_mgmt.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_setting_mgmt.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },
@@ -57,13 +58,13 @@ func TestAccSettingMgmt_site(t *testing.T) {
func TestAccSettingMgmt_sshKeys(t *testing.T) { func TestAccSettingMgmt_sshKeys(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingMgmtLock.Lock() settingMgmtLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingMgmtLock.Unlock() settingMgmtLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingMgmtConfig_sshKeys(), Config: testAccSettingMgmtConfig_sshKeys(),
@@ -72,7 +73,7 @@ func TestAccSettingMgmt_sshKeys(t *testing.T) {
{ {
ResourceName: "unifi_setting_mgmt.test", ResourceName: "unifi_setting_mgmt.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_setting_mgmt.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_setting_mgmt.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },

View File

@@ -1,6 +1,7 @@
package v1 package acctest
import ( import (
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"sync" "sync"
"testing" "testing"
@@ -12,19 +13,19 @@ var settingRadiusLock = sync.Mutex{}
func TestAccSettingRadius_basic(t *testing.T) { func TestAccSettingRadius_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingRadiusLock.Lock() settingRadiusLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingRadiusLock.Unlock() settingRadiusLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingRadiusConfig_basic(), Config: testAccSettingRadiusConfig_basic(),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_radius.test"), pt.ImportStep("unifi_setting_radius.test"),
}, },
}) })
} }
@@ -32,13 +33,13 @@ func TestAccSettingRadius_basic(t *testing.T) {
func TestAccSettingRadius_site(t *testing.T) { func TestAccSettingRadius_site(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingRadiusLock.Lock() settingRadiusLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingRadiusLock.Unlock() settingRadiusLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingRadiusConfig_site(), Config: testAccSettingRadiusConfig_site(),
@@ -47,7 +48,7 @@ func TestAccSettingRadius_site(t *testing.T) {
{ {
ResourceName: "unifi_setting_radius.test", ResourceName: "unifi_setting_radius.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_setting_radius.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_setting_radius.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },
@@ -57,13 +58,13 @@ func TestAccSettingRadius_site(t *testing.T) {
func TestAccSettingRadius_full(t *testing.T) { func TestAccSettingRadius_full(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingRadiusLock.Lock() settingRadiusLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingRadiusLock.Unlock() settingRadiusLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingRadiusConfig_full(), Config: testAccSettingRadiusConfig_full(),
@@ -72,7 +73,7 @@ func TestAccSettingRadius_full(t *testing.T) {
{ {
ResourceName: "unifi_setting_radius.test", ResourceName: "unifi_setting_radius.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_setting_radius.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_setting_radius.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },
@@ -82,19 +83,19 @@ func TestAccSettingRadius_full(t *testing.T) {
func TestAccSettingRadius_vlan(t *testing.T) { func TestAccSettingRadius_vlan(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingRadiusLock.Lock() settingRadiusLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingRadiusLock.Unlock() settingRadiusLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingRadiusConfig_vlan(), Config: testAccSettingRadiusConfig_vlan(),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_radius.test"), pt.ImportStep("unifi_setting_radius.test"),
}, },
}) })
} }

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"regexp" "regexp"
"sync" "sync"
"testing" "testing"
@@ -15,30 +16,30 @@ var settingUsgLock = sync.Mutex{}
func TestAccSettingUsg_mdns_v6(t *testing.T) { func TestAccSettingUsg_mdns_v6(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
preCheckVersionConstraint(t, "< 7") PreCheckVersionConstraint(t, "< 7")
settingUsgLock.Lock() settingUsgLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingUsgLock.Unlock() settingUsgLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingUsgConfig_mdns(true), Config: testAccSettingUsgConfig_mdns(true),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_usg.test"), pt.ImportStep("unifi_setting_usg.test"),
{ {
Config: testAccSettingUsgConfig_mdns(false), Config: testAccSettingUsgConfig_mdns(false),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_usg.test"), pt.ImportStep("unifi_setting_usg.test"),
{ {
Config: testAccSettingUsgConfig_mdns(true), Config: testAccSettingUsgConfig_mdns(true),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_usg.test"), pt.ImportStep("unifi_setting_usg.test"),
}, },
}) })
} }
@@ -46,14 +47,14 @@ func TestAccSettingUsg_mdns_v6(t *testing.T) {
func TestAccSettingUsg_mdns_v7(t *testing.T) { func TestAccSettingUsg_mdns_v7(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
preCheckVersionConstraint(t, ">= 7") PreCheckVersionConstraint(t, ">= 7")
settingUsgLock.Lock() settingUsgLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingUsgLock.Unlock() settingUsgLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingUsgConfig_mdns(true), Config: testAccSettingUsgConfig_mdns(true),
@@ -66,19 +67,19 @@ func TestAccSettingUsg_mdns_v7(t *testing.T) {
func TestAccSettingUsg_dhcpRelay(t *testing.T) { func TestAccSettingUsg_dhcpRelay(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingUsgLock.Lock() settingUsgLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingUsgLock.Unlock() settingUsgLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingUsgConfig_dhcpRelay(), Config: testAccSettingUsgConfig_dhcpRelay(),
Check: resource.ComposeTestCheckFunc(), Check: resource.ComposeTestCheckFunc(),
}, },
importStep("unifi_setting_usg.test"), pt.ImportStep("unifi_setting_usg.test"),
}, },
}) })
} }
@@ -86,13 +87,13 @@ func TestAccSettingUsg_dhcpRelay(t *testing.T) {
func TestAccSettingUsg_site(t *testing.T) { func TestAccSettingUsg_site(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{ resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t) pt.PreCheck(t)
settingUsgLock.Lock() settingUsgLock.Lock()
t.Cleanup(func() { t.Cleanup(func() {
settingUsgLock.Unlock() settingUsgLock.Unlock()
}) })
}, },
ProviderFactories: providerFactories, ProtoV6ProviderFactories: providers,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccSettingUsgConfig_site(), Config: testAccSettingUsgConfig_site(),
@@ -101,7 +102,7 @@ func TestAccSettingUsg_site(t *testing.T) {
{ {
ResourceName: "unifi_setting_usg.test", ResourceName: "unifi_setting_usg.test",
ImportState: true, ImportState: true,
ImportStateIdFunc: siteAndIDImportStateIDFunc("unifi_setting_usg.test"), ImportStateIdFunc: pt.SiteAndIDImportStateIDFunc("unifi_setting_usg.test"),
ImportStateVerify: true, ImportStateVerify: true,
}, },
}, },

View File

@@ -1,8 +1,9 @@
package v1 package acctest
import ( import (
"context" "context"
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"strings" "strings"
"testing" "testing"
@@ -13,9 +14,7 @@ import (
func TestAccSite_basic(t *testing.T) { func TestAccSite_basic(t *testing.T) {
var siteName string var siteName string
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// FIXME causes flaky tests. See: https://github.com/paultyng/terraform-provider-unifi/issues/480 // FIXME causes flaky tests. See: https://github.com/paultyng/terraform-provider-unifi/issues/480
//CheckDestroy: testAccCheckSiteResourceDestroy, //CheckDestroy: testAccCheckSiteResourceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
@@ -31,14 +30,14 @@ func TestAccSite_basic(t *testing.T) {
}, },
), ),
}, },
importStep("unifi_site.test"), pt.ImportStep("unifi_site.test"),
{ {
Config: testAccSiteConfig("tfacc-desc2"), Config: testAccSiteConfig("tfacc-desc2"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("unifi_site.test", "description", "tfacc-desc2"), resource.TestCheckResourceAttr("unifi_site.test", "description", "tfacc-desc2"),
), ),
}, },
importStep("unifi_site.test"), pt.ImportStep("unifi_site.test"),
// test importing from name, not id // test importing from name, not id
{ {

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"net" "net"
"strconv" "strconv"
"testing" "testing"
@@ -19,9 +20,7 @@ func TestAccStaticRoute_nextHop(t *testing.T) {
distance := 1 distance := 1
nextHop := net.IPv4(172, 16, 0, 1).To4() nextHop := net.IPv4(172, 16, 0, 1).To4()
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -34,7 +33,7 @@ func TestAccStaticRoute_nextHop(t *testing.T) {
resource.TestCheckResourceAttr("unifi_static_route.test", "next_hop", nextHop.String()), resource.TestCheckResourceAttr("unifi_static_route.test", "next_hop", nextHop.String()),
), ),
}, },
importStep("unifi_static_route.test"), pt.ImportStep("unifi_static_route.test"),
}, },
}) })
} }
@@ -48,9 +47,7 @@ func TestAccStaticRoute_nextHop_ipv6(t *testing.T) {
distance := 1 distance := 1
nextHop := net.IP{0xfd, 0x6a, 0x37, 0xbe, 0xe3, 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1} nextHop := net.IP{0xfd, 0x6a, 0x37, 0xbe, 0xe3, 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -63,7 +60,7 @@ func TestAccStaticRoute_nextHop_ipv6(t *testing.T) {
resource.TestCheckResourceAttr("unifi_static_route.test", "next_hop", nextHop.String()), resource.TestCheckResourceAttr("unifi_static_route.test", "next_hop", nextHop.String()),
), ),
}, },
importStep("unifi_static_route.test"), pt.ImportStep("unifi_static_route.test"),
}, },
}) })
} }
@@ -76,9 +73,7 @@ func TestAccStaticRoute_blackhole(t *testing.T) {
} }
distance := 1 distance := 1
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -90,7 +85,7 @@ func TestAccStaticRoute_blackhole(t *testing.T) {
resource.TestCheckResourceAttr("unifi_static_route.test", "distance", strconv.Itoa(distance)), resource.TestCheckResourceAttr("unifi_static_route.test", "distance", strconv.Itoa(distance)),
), ),
}, },
importStep("unifi_static_route.test"), pt.ImportStep("unifi_static_route.test"),
}, },
}) })
} }
@@ -103,9 +98,7 @@ func TestAccStaticRoute_blackhole_ipv6(t *testing.T) {
} }
distance := 1 distance := 1
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -117,7 +110,7 @@ func TestAccStaticRoute_blackhole_ipv6(t *testing.T) {
resource.TestCheckResourceAttr("unifi_static_route.test", "distance", strconv.Itoa(distance)), resource.TestCheckResourceAttr("unifi_static_route.test", "distance", strconv.Itoa(distance)),
), ),
}, },
importStep("unifi_static_route.test"), pt.ImportStep("unifi_static_route.test"),
}, },
}) })
} }
@@ -131,9 +124,7 @@ func TestAccStaticRoute_interface(t *testing.T) {
distance := 1 distance := 1
networkInterface := "WAN2" networkInterface := "WAN2"
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -146,7 +137,7 @@ func TestAccStaticRoute_interface(t *testing.T) {
resource.TestCheckResourceAttr("unifi_static_route.test", "interface", networkInterface), resource.TestCheckResourceAttr("unifi_static_route.test", "interface", networkInterface),
), ),
}, },
importStep("unifi_static_route.test"), pt.ImportStep("unifi_static_route.test"),
}, },
}) })
} }
@@ -160,9 +151,7 @@ func TestAccStaticRoute_interface_ipv6(t *testing.T) {
distance := 1 distance := 1
networkInterface := "WAN2" networkInterface := "WAN2"
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -175,7 +164,7 @@ func TestAccStaticRoute_interface_ipv6(t *testing.T) {
resource.TestCheckResourceAttr("unifi_static_route.test", "interface", networkInterface), resource.TestCheckResourceAttr("unifi_static_route.test", "interface", networkInterface),
), ),
}, },
importStep("unifi_static_route.test"), pt.ImportStep("unifi_static_route.test"),
}, },
}) })
} }

View File

@@ -1,7 +1,8 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"testing" "testing"
@@ -10,9 +11,7 @@ import (
func TestAccUserGroup_basic(t *testing.T) { func TestAccUserGroup_basic(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -24,11 +23,11 @@ func TestAccUserGroup_basic(t *testing.T) {
{ {
Config: testAccUserGroupConfig_qos(name), Config: testAccUserGroupConfig_qos(name),
}, },
importStep("unifi_user_group.test"), pt.ImportStep("unifi_user_group.test"),
{ {
Config: testAccUserGroupConfig(name), Config: testAccUserGroupConfig(name),
}, },
importStep("unifi_user_group.test"), pt.ImportStep("unifi_user_group.test"),
}, },
}) })
} }

View File

@@ -1,9 +1,10 @@
package v1 package acctest
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"net" "net"
"regexp" "regexp"
@@ -17,16 +18,14 @@ import (
) )
func userImportStep(name string) resource.TestStep { func userImportStep(name string) resource.TestStep {
return importStep(name, "allow_existing", "skip_forget_on_destroy") return pt.ImportStep(name, "allow_existing", "skip_forget_on_destroy")
} }
func TestAccUser_basic(t *testing.T) { func TestAccUser_basic(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -56,19 +55,17 @@ func TestAccUser_basic(t *testing.T) {
} }
func TestAccUser_fixed_ip(t *testing.T) { func TestAccUser_fixed_ip(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
ip, err := cidr.Host(subnet, 1) ip, err := cidr.Host(subnet, 1)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -103,13 +100,11 @@ func TestAccUser_fixed_ip(t *testing.T) {
} }
func TestAccUser_blocking(t *testing.T) { func TestAccUser_blocking(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: , // TODO: CheckDestroy: ,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
@@ -141,14 +136,12 @@ func TestAccUser_blocking(t *testing.T) {
} }
func TestAccUser_existing_mac_allow(t *testing.T) { func TestAccUser_existing_mac_allow(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { PreCheck: func() {
preCheck(t)
_, err := testClient.CreateUser(context.Background(), "default", &unifi.User{ _, err := testClient.CreateUser(context.Background(), "default", &unifi.User{
MAC: mac, MAC: mac,
Name: name, Name: name,
@@ -158,10 +151,7 @@ func TestAccUser_existing_mac_allow(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
}, },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error { CheckDestroy: func(*terraform.State) error {
// TODO: CheckDestroy: ,
return testClient.DeleteUserByMAC(context.Background(), "default", mac) return testClient.DeleteUserByMAC(context.Background(), "default", mac)
}, },
Steps: []resource.TestStep{ Steps: []resource.TestStep{
@@ -178,7 +168,7 @@ func TestAccUser_existing_mac_allow(t *testing.T) {
} }
func TestAccUser_existing_mac_deny(t *testing.T) { func TestAccUser_existing_mac_deny(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
_, err := testClient.CreateUser(context.Background(), "default", &unifi.User{ _, err := testClient.CreateUser(context.Background(), "default", &unifi.User{
@@ -199,9 +189,7 @@ func TestAccUser_existing_mac_deny(t *testing.T) {
unallocateTestMac() unallocateTestMac()
}() }()
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccUserConfig_existing(mac, name, "tfacc note", false, false), Config: testAccUserConfig_existing(mac, name, "tfacc note", false, false),
@@ -212,13 +200,12 @@ func TestAccUser_existing_mac_deny(t *testing.T) {
} }
func TestAccUser_fingerprint(t *testing.T) { func TestAccUser_fingerprint(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
ProviderFactories: providerFactories, CheckDestroy: testCheckUserDestroy,
CheckDestroy: testCheckUserDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccUserConfig_fingerprint(mac, name, 123), Config: testAccUserConfig_fingerprint(mac, name, 123),
@@ -246,23 +233,19 @@ func TestAccUser_fingerprint(t *testing.T) {
} }
func TestAccUser_localdns(t *testing.T) { func TestAccUser_localdns(t *testing.T) {
mac, unallocateTestMac := allocateTestMac(t) mac, unallocateTestMac := pt.AllocateTestMac(t)
defer unallocateTestMac() defer unallocateTestMac()
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
ip, err := cidr.Host(subnet, 1) ip, err := cidr.Host(subnet, 1)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { VersionConstraint: ">= 7.2.91",
preCheck(t)
preCheckVersionConstraint(t, ">= 7.2.91")
},
ProviderFactories: providerFactories,
CheckDestroy: testCheckUserDestroy, CheckDestroy: testCheckUserDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {

View File

@@ -1,28 +1,21 @@
package v1 package acctest
import ( import (
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"net" "net"
"testing" "testing"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
) )
func TestAccWLAN_wpapsk(t *testing.T) { func TestAccWLAN_wpapsk(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "disabled"), Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "disabled"),
@@ -30,23 +23,16 @@ func TestAccWLAN_wpapsk(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_open(t *testing.T) { func TestAccWLAN_open(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_open(name, subnet, vlan), Config: testAccWLANConfig_open(name, subnet, vlan),
@@ -54,37 +40,30 @@ func TestAccWLAN_open(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_open_mac_filter(name, subnet, vlan), Config: testAccWLANConfig_open_mac_filter(name, subnet, vlan),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_open(name, subnet, vlan), Config: testAccWLANConfig_open(name, subnet, vlan),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_change_security_and_pmf(t *testing.T) { func TestAccWLAN_change_security_and_pmf(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "disabled"), Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "disabled"),
@@ -92,51 +71,44 @@ func TestAccWLAN_change_security_and_pmf(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_open(name, subnet, vlan), Config: testAccWLANConfig_open(name, subnet, vlan),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "optional"), Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "optional"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "required"), Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "required"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "disabled"), Config: testAccWLANConfig_wpapsk(name, subnet, vlan, "disabled"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_schedule(t *testing.T) { func TestAccWLAN_schedule(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_schedule(name, subnet, vlan), Config: testAccWLANConfig_schedule(name, subnet, vlan),
@@ -144,7 +116,7 @@ func TestAccWLAN_schedule(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
// remove schedule // remove schedule
{ {
Config: testAccWLANConfig_open(name, subnet, vlan), Config: testAccWLANConfig_open(name, subnet, vlan),
@@ -152,23 +124,16 @@ func TestAccWLAN_schedule(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_wpaeap(t *testing.T) { func TestAccWLAN_wpaeap(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_wpaeap(name, subnet, vlan), Config: testAccWLANConfig_wpaeap(name, subnet, vlan),
@@ -176,23 +141,16 @@ func TestAccWLAN_wpaeap(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_wlan_band(t *testing.T) { func TestAccWLAN_wlan_band(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_wlan_band(name, subnet, vlan), Config: testAccWLANConfig_wlan_band(name, subnet, vlan),
@@ -200,23 +158,16 @@ func TestAccWLAN_wlan_band(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_no2ghz_oui(t *testing.T) { func TestAccWLAN_no2ghz_oui(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_no2ghz_oui(name, subnet, vlan), Config: testAccWLANConfig_no2ghz_oui(name, subnet, vlan),
@@ -224,23 +175,16 @@ func TestAccWLAN_no2ghz_oui(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_proxy_arp(t *testing.T) { func TestAccWLAN_proxy_arp(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_proxy_arp(name, subnet, vlan, true), Config: testAccWLANConfig_proxy_arp(name, subnet, vlan, true),
@@ -248,23 +192,16 @@ func TestAccWLAN_proxy_arp(t *testing.T) {
resource.TestCheckResourceAttr("unifi_wlan.test", "proxy_arp", "true"), resource.TestCheckResourceAttr("unifi_wlan.test", "proxy_arp", "true"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_bss_transition(t *testing.T) { func TestAccWLAN_bss_transition(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_bss_transition(name, subnet, vlan, false), Config: testAccWLANConfig_bss_transition(name, subnet, vlan, false),
@@ -272,23 +209,16 @@ func TestAccWLAN_bss_transition(t *testing.T) {
resource.TestCheckResourceAttr("unifi_wlan.test", "bss_transition", "false"), resource.TestCheckResourceAttr("unifi_wlan.test", "bss_transition", "false"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_uapsd(t *testing.T) { func TestAccWLAN_uapsd(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_uapsd(name, subnet, vlan), Config: testAccWLANConfig_uapsd(name, subnet, vlan),
@@ -296,23 +226,16 @@ func TestAccWLAN_uapsd(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_fast_roaming_enabled(t *testing.T) { func TestAccWLAN_fast_roaming_enabled(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_fast_roaming_enabled(name, subnet, vlan, true), Config: testAccWLANConfig_fast_roaming_enabled(name, subnet, vlan, true),
@@ -320,26 +243,17 @@ func TestAccWLAN_fast_roaming_enabled(t *testing.T) {
resource.TestCheckResourceAttr("unifi_wlan.test", "fast_roaming_enabled", "true"), resource.TestCheckResourceAttr("unifi_wlan.test", "fast_roaming_enabled", "true"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_wpa3(t *testing.T) { func TestAccWLAN_wpa3(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { MinVersion: base.ControllerVersionWPA3,
preCheck(t)
preCheckMinVersion(t, provider.ControllerVersionWPA3)
},
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_wpa3(name, subnet, vlan, false, "required"), Config: testAccWLANConfig_wpa3(name, subnet, vlan, false, "required"),
@@ -347,37 +261,30 @@ func TestAccWLAN_wpa3(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_wpa3(name, subnet, vlan, true, "optional"), Config: testAccWLANConfig_wpa3(name, subnet, vlan, true, "optional"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_wpa3(name, subnet, vlan, false, "required"), Config: testAccWLANConfig_wpa3(name, subnet, vlan, false, "required"),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }
func TestAccWLAN_minimum_data_rate(t *testing.T) { func TestAccWLAN_minimum_data_rate(t *testing.T) {
name := acctest.RandomWithPrefix("tfacc") name := acctest.RandomWithPrefix("tfacc")
subnet, vlan := getTestVLAN(t) subnet, vlan := pt.GetTestVLAN(t)
resource.ParallelTest(t, resource.TestCase{ AcceptanceTest(t, AcceptanceTestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: func(*terraform.State) error {
// TODO: actual CheckDestroy
return nil
},
Steps: []resource.TestStep{ Steps: []resource.TestStep{
{ {
Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 5500, 18000), Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 5500, 18000),
@@ -385,35 +292,35 @@ func TestAccWLAN_minimum_data_rate(t *testing.T) {
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 1000, 18000), Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 1000, 18000),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 0, 0), Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 0, 0),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 6000, 9000), Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 6000, 9000),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
{ {
Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 18000, 6000), Config: testAccWLANConfig_minimum_data_rate(name, subnet, vlan, 18000, 6000),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"), // testCheckNetworkExists(t, "name"),
), ),
}, },
importStep("unifi_wlan.test"), pt.ImportStep("unifi_wlan.test"),
}, },
}) })
} }

View File

@@ -1,18 +1,17 @@
package v1 package apgroup
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func dataAPGroup() *schema.Resource { func DataAPGroup() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_ap_group` data source can be used to retrieve the ID for an AP group by name.", Description: "`unifi_ap_group` data source can be used to retrieve the ID for an AP group by name.",
ReadContext: dataAPGroupRead, ReadContext: DataAPGroupRead,
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"id": { "id": {
@@ -35,8 +34,8 @@ func dataAPGroup() *schema.Resource {
} }
} }
func dataAPGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func DataAPGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
name := d.Get("name").(string) name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -0,0 +1,45 @@
package base
import (
"fmt"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/resource"
)
type BaseData interface {
SetClient(client *Client)
}
func ConfigureDatasource(base BaseData, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
cfg, ok := req.ProviderData.(*Client)
if !ok {
resp.Diagnostics.AddError("Unexpected Datasource Configure Type", fmt.Sprintf("Expected provider.Client, got: %T", req.ProviderData))
return
}
if cfg == nil {
resp.Diagnostics.AddError("Empty configuration", "provider.Client is nil")
return
}
base.SetClient(cfg)
}
func ConfigureResource(base BaseData, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
cfg, ok := req.ProviderData.(*Client)
if !ok {
resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected provider.Client, got: %T", req.ProviderData))
return
}
if cfg == nil {
resp.Diagnostics.AddError("Empty configuration", "provider.Client is nil")
return
}
base.SetClient(cfg)
}

View File

@@ -1,13 +1,16 @@
package provider package base
import ( import (
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/go-version" "github.com/hashicorp/go-version"
"log" "log"
"net"
"net/http" "net/http"
"strings" "strings"
"time"
) )
func IsServerErrorContains(err error, messageContains string) bool { func IsServerErrorContains(err error, messageContains string) bool {
@@ -76,3 +79,21 @@ type Client struct {
Site string Site string
Version *version.Version Version *version.Version
} }
func CreateHttpTransport(insecure bool) http.RoundTripper {
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
}
}

View File

@@ -1,8 +1,7 @@
package provider package base
import ( import (
"fmt" "fmt"
"github.com/hashicorp/go-version" "github.com/hashicorp/go-version"
) )
@@ -13,7 +12,10 @@ func asVersion(versionString string) *version.Version {
var ( var (
ControllerV6 = asVersion("6.0.0") ControllerV6 = asVersion("6.0.0")
ControllerV7 = asVersion("7.0.0") ControllerV7 = asVersion("7.0.0")
ControllerV9 = asVersion("9.0.0")
ControllerVersionApiKeyAuth = asVersion("9.0.108") ControllerVersionApiKeyAuth = asVersion("9.0.108")
// https://community.ui.com/releases/UniFi-Network-Application-8-2-93/fce86dc6-897a-4944-9c53-1eec7e37e738
ControllerVersionDnsRecords = asVersion("8.2.93")
// https://community.ui.com/releases/UniFi-Network-Controller-6-1-61/62f1ad38-1ac5-430c-94b0-becbb8f71d7d // 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")
@@ -27,6 +29,10 @@ func (c *Client) IsControllerV7() bool {
return c.Version.GreaterThanOrEqual(ControllerV7) return c.Version.GreaterThanOrEqual(ControllerV7)
} }
func (c *Client) IsControllerV9() bool {
return c.Version.GreaterThanOrEqual(ControllerV9)
}
func (c *Client) SupportsApiKeyAuthentication() bool { func (c *Client) SupportsApiKeyAuthentication() bool {
return c.Version.GreaterThanOrEqual(ControllerVersionApiKeyAuth) return c.Version.GreaterThanOrEqual(ControllerVersionApiKeyAuth)
} }
@@ -35,6 +41,10 @@ func (c *Client) SupportsWPA3() bool {
return c.Version.GreaterThanOrEqual(ControllerVersionWPA3) return c.Version.GreaterThanOrEqual(ControllerVersionWPA3)
} }
func (c *Client) SupportsDnsRecords() bool {
return c.Version.GreaterThanOrEqual(ControllerVersionDnsRecords)
}
func CheckMinimumControllerVersion(versionString string) error { func CheckMinimumControllerVersion(versionString string) error {
v, err := version.NewVersion(versionString) v, err := version.NewVersion(versionString)
if err != nil { if err != nil {

View File

@@ -1,10 +1,11 @@
package v1 package device
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -16,7 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceDevice() *schema.Resource { func ResourceDevice() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_device` manages a device of the network.\n\n" + Description: "`unifi_device` manages a device of the network.\n\n" +
"Devices are adopted by the controller, so it is not possible for this resource to be created through " + "Devices are adopted by the controller, so it is not possible for this resource to be created through " +
@@ -50,8 +51,8 @@ func resourceDevice() *schema.Resource {
Optional: true, Optional: true,
Computed: true, Computed: true,
ForceNew: true, ForceNew: true,
DiffSuppressFunc: macDiffSuppressFunc, DiffSuppressFunc: utils.MacDiffSuppressFunc,
ValidateFunc: validation.StringMatch(macAddressRegexp, "Mac address is invalid"), ValidateFunc: validation.StringMatch(utils.MacAddressRegexp, "Mac address is invalid"),
}, },
"name": { "name": {
Description: "The name of the device.", Description: "The name of the device.",
@@ -139,7 +140,7 @@ func resourceDevice() *schema.Resource {
} }
func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -152,9 +153,9 @@ func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta inte
id = importParts[1] id = importParts[1]
} }
if macAddressRegexp.MatchString(id) { if utils.MacAddressRegexp.MatchString(id) {
// look up id by mac // look up id by mac
mac := cleanMAC(id) mac := utils.CleanMAC(id)
device, err := c.GetDeviceByMAC(ctx, site, mac) device, err := c.GetDeviceByMAC(ctx, site, mac)
if err != nil { if err != nil {
@@ -175,7 +176,7 @@ func resourceDeviceImport(ctx context.Context, d *schema.ResourceData, meta inte
} }
func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -187,7 +188,7 @@ func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta inte
return diag.Errorf("no MAC address specified, please import the device using terraform import") return diag.Errorf("no MAC address specified, please import the device using terraform import")
} }
mac = cleanMAC(mac) mac = utils.CleanMAC(mac)
device, err := c.GetDeviceByMAC(ctx, site, mac) device, err := c.GetDeviceByMAC(ctx, site, mac)
if device == nil { if device == nil {
@@ -218,7 +219,7 @@ func resourceDeviceCreate(ctx context.Context, d *schema.ResourceData, meta inte
} }
func resourceDeviceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDeviceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -247,7 +248,7 @@ func resourceDeviceUpdate(ctx context.Context, d *schema.ResourceData, meta inte
} }
func resourceDeviceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDeviceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
if !d.Get("forget_on_destroy").(bool) { if !d.Get("forget_on_destroy").(bool) {
return nil return nil
@@ -274,7 +275,7 @@ func resourceDeviceDelete(ctx context.Context, d *schema.ResourceData, meta inte
} }
func resourceDeviceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDeviceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -389,7 +390,7 @@ 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) { func waitForDeviceState(ctx context.Context, d *schema.ResourceData, meta interface{}, targetState unifi.DeviceState, pendingStates []unifi.DeviceState, timeout time.Duration) (*unifi.Device, error) {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
mac := d.Get("mac").(string) mac := d.Get("mac").(string)

View File

@@ -0,0 +1,131 @@
package dns
import (
"context"
"fmt"
"github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
)
var (
_ datasource.DataSource = &dnsRecordDatasource{}
_ datasource.DataSourceWithConfigure = &dnsRecordDatasource{}
_ base.BaseData = &dnsRecordDatasource{}
_ datasource.DataSourceWithConfigValidators = &dnsRecordDatasource{}
)
type dnsRecordDatasource struct {
client *base.Client
}
func NewDnsRecordDatasource() datasource.DataSource {
return &dnsRecordDatasource{}
}
func (d *dnsRecordDatasource) ConfigValidators(_ context.Context) []datasource.ConfigValidator {
return []datasource.ConfigValidator{
datasourcevalidator.ExactlyOneOf(
path.MatchRoot("filter").AtName("name"),
path.MatchRoot("filter").AtName("record"),
),
}
}
func (d *dnsRecordDatasource) SetClient(client *base.Client) {
d.client = client
}
func (d *dnsRecordDatasource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
base.ConfigureDatasource(d, req, resp)
}
func (d *dnsRecordDatasource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, resourceName)
}
func (d *dnsRecordDatasource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Retrieves information about a specific DNS record.",
Attributes: dnsRecordDatasourceAttributes,
Blocks: map[string]schema.Block{
"filter": schema.SingleNestedBlock{
Description: "Filter to apply to the DNS record.",
Validators: []validator.Object{
objectvalidator.IsRequired(),
},
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "DNS record name.",
Optional: true,
},
"record": schema.StringAttribute{
Description: "DNS record content.",
Optional: true,
},
},
},
},
}
}
func (d *dnsRecordDatasource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
if !d.client.SupportsDnsRecords() {
resp.Diagnostics.AddError("DNS Records are not supported", fmt.Sprintf("The Unifi controller in version %q does not support DNS records. Required controller version: %q", d.client.Version, base.ControllerVersionDnsRecords))
}
var state dnsRecordDatasourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
if state.Filter == nil {
// TODO remove after testing validation
resp.Diagnostics.AddError("Filter is required", "Filter is required. Validation should prevent this from happening.")
return
}
list, err := d.client.ListDNSRecord(ctx, d.client.Site)
if err != nil {
resp.Diagnostics.AddError("Failed to list DNS records", err.Error())
return
}
if len(list) == 0 {
resp.Diagnostics.AddError("DNS record not found", "No DNS record found")
return
}
var nameFilter, recordFilter string
if utils.IsStringValueNotEmpty(state.Filter.Name) {
nameFilter = state.Filter.Name.ValueString()
}
if utils.IsStringValueNotEmpty(state.Filter.Record) {
recordFilter = state.Filter.Record.ValueString()
}
if nameFilter != "" && recordFilter != "" {
// TODO remove after testing validation
resp.Diagnostics.AddError("Filter is invalid", "Only one of 'name' or 'record' can be specified. Validation should prevent this from happening.")
return
}
var found *unifi.DNSRecord
for _, record := range list {
if nameFilter != "" && record.Key == nameFilter {
found = &record
break
}
if recordFilter != "" && record.Value == recordFilter {
found = &record
break
}
}
if found == nil {
resp.Diagnostics.AddError("DNS record not found", "No DNS record found")
return
}
(&state.dnsRecordModel).merge(found)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}

View File

@@ -0,0 +1,81 @@
package dns
import (
"context"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)
var (
_ datasource.DataSource = &dnsRecordsDatasource{}
_ datasource.DataSourceWithConfigure = &dnsRecordsDatasource{}
_ base.BaseData = &dnsRecordsDatasource{}
)
type dnsRecordsDatasource struct {
client *base.Client
}
func NewDnsRecordsDatasource() datasource.DataSource {
return &dnsRecordsDatasource{}
}
func (d *dnsRecordsDatasource) SetClient(client *base.Client) {
d.client = client
}
func (d *dnsRecordsDatasource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
base.ConfigureDatasource(d, req, resp)
}
func (d *dnsRecordsDatasource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = fmt.Sprintf("%s_%ss", req.ProviderTypeName, resourceName)
}
func (d *dnsRecordsDatasource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Retrieves information about a all DNS records.",
Attributes: map[string]schema.Attribute{
"result": schema.ListNestedAttribute{
Description: "The list of DNS records.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: dnsRecordDatasourceAttributes,
},
},
},
}
}
func (d *dnsRecordsDatasource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var state dnsRecordsDatasourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
records, err := d.client.ListDNSRecord(ctx, d.client.Site)
if err != nil {
resp.Diagnostics.AddError("Failed to list DNS records", err.Error())
return
}
for _, record := range records {
state.Records = append(state.Records, &dnsRecordModel{
ID: types.StringValue(record.ID),
SiteID: types.StringValue(record.SiteID),
Name: types.StringValue(record.Key),
Record: types.StringValue(record.Value),
Enabled: types.BoolValue(record.Enabled),
Port: types.Int32Value(int32(record.Port)),
Priority: types.Int32Value(int32(record.Priority)),
Type: types.StringValue(record.RecordType),
TTL: types.Int32Value(int32(record.Ttl)),
Weight: types.Int32Value(int32(record.Weight)),
})
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}

View File

@@ -0,0 +1,102 @@
package dns
import (
"github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)
const resourceName = "dns_record"
type dnsRecordModel struct {
ID types.String `tfsdk:"id"`
SiteID types.String `tfsdk:"site_id"`
Name types.String `tfsdk:"name"`
Record types.String `tfsdk:"record"`
Enabled types.Bool `tfsdk:"enabled"`
Port types.Int32 `tfsdk:"port"`
Priority types.Int32 `tfsdk:"priority"`
Type types.String `tfsdk:"type"`
TTL types.Int32 `tfsdk:"ttl"`
Weight types.Int32 `tfsdk:"weight"`
}
type dnsRecordDatasourceModel struct {
dnsRecordModel
Filter *dnsRecordFilterModel `tfsdk:"filter"`
}
type dnsRecordsDatasourceModel struct {
Records []*dnsRecordModel `tfsdk:"result"`
}
var dnsRecordDatasourceAttributes = map[string]schema.Attribute{
"id": utils.ID(),
"site_id": utils.ID("The site ID where the DNS record is located."),
"name": schema.StringAttribute{
Description: "DNS record name.",
Computed: true,
},
"record": schema.StringAttribute{
Description: "DNS record content.",
Computed: true,
},
"enabled": schema.BoolAttribute{
Description: "Whether the DNS record is enabled.",
Computed: true,
},
"port": schema.Int32Attribute{
Description: "The port of the DNS record.",
Computed: true,
},
"priority": schema.Int32Attribute{
Description: "Priority of the DNS records. Present only for MX and SRV records; unused by other record types.",
Computed: true,
},
"type": schema.StringAttribute{
Description: "The type of the DNS record.",
Computed: true,
},
"ttl": schema.Int32Attribute{
Description: "Time To Live (TTL) of the DNS record in seconds. Setting to 0 means 'automatic'.",
Computed: true,
},
"weight": schema.Int32Attribute{
Description: "A numeric value indicating the relative weight of the record.",
Computed: true,
},
}
type dnsRecordFilterModel struct {
Name types.String `tfsdk:"name"`
Record types.String `tfsdk:"record"`
}
func (d *dnsRecordModel) asUnifiModel() *unifi.DNSRecord {
return &unifi.DNSRecord{
ID: d.ID.ValueString(),
SiteID: d.SiteID.ValueString(),
Key: d.Name.ValueString(),
Value: d.Record.ValueString(),
Enabled: d.Enabled.ValueBool(),
Port: int(d.Port.ValueInt32()),
Priority: int(d.Priority.ValueInt32()),
RecordType: d.Type.ValueString(),
Ttl: int(d.TTL.ValueInt32()),
Weight: int(d.Weight.ValueInt32()),
}
}
func (d *dnsRecordModel) merge(other *unifi.DNSRecord) {
d.ID = types.StringValue(other.ID)
d.SiteID = types.StringValue(other.SiteID)
d.Name = types.StringValue(other.Key)
d.Record = types.StringValue(other.Value)
d.Enabled = types.BoolValue(other.Enabled)
d.Port = types.Int32Value(int32(other.Port))
d.Priority = types.Int32Value(int32(other.Priority))
d.Type = types.StringValue(other.RecordType)
d.TTL = types.Int32Value(int32(other.Ttl))
d.Weight = types.Int32Value(int32(other.Weight))
}

View File

@@ -0,0 +1,236 @@
package dns
import (
"context"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
var (
_ resource.Resource = &dnsRecordResource{}
_ resource.ResourceWithConfigure = &dnsRecordResource{}
_ resource.ResourceWithImportState = &dnsRecordResource{}
_ base.BaseData = &dnsRecordResource{}
)
type dnsRecordResource struct {
client *base.Client
}
func (d *dnsRecordResource) SetClient(client *base.Client) {
d.client = client
}
func NewDnsRecordResource() resource.Resource {
return &dnsRecordResource{}
}
func (d *dnsRecordResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
base.ConfigureResource(d, req, resp)
}
func (d *dnsRecordResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, resourceName)
}
func (d *dnsRecordResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Manages a DNS record in the Unifi controller.",
Attributes: map[string]schema.Attribute{
"id": utils.ID(),
"site_id": utils.ID("The site ID where the DNS record is located."),
"name": schema.StringAttribute{
MarkdownDescription: "DNS record name.",
Required: true,
},
"record": schema.StringAttribute{
MarkdownDescription: "DNS record content.",
Required: true,
},
"enabled": schema.BoolAttribute{
MarkdownDescription: "Whether the DNS record is enabled.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(true),
},
"port": schema.Int32Attribute{
MarkdownDescription: "The port of the DNS record.",
Optional: true,
Computed: true,
Validators: []validator.Int32{
int32validator.Between(1, 65535),
},
},
"priority": schema.Int32Attribute{
MarkdownDescription: "Required for MX and SRV records; unused by other record types. Records with lower priorities are preferred",
Optional: true,
Computed: true,
Validators: []validator.Int32{
int32validator.AtLeast(1),
},
},
"type": schema.StringAttribute{
MarkdownDescription: "The type of the DNS record.",
Required: true,
Validators: []validator.String{
stringvalidator.OneOf("A", "AAAA", "CNAME", "MX", "NS", "PTR", "SOA", "SRV", "TXT"),
},
},
"ttl": schema.Int32Attribute{
MarkdownDescription: "Time To Live (TTL) of the DNS record in seconds. Setting to 0 means 'automatic'.",
Optional: true,
Computed: true,
},
"weight": schema.Int32Attribute{
MarkdownDescription: "A numeric value indicating the relative weight of the record.",
Optional: true,
Computed: true,
},
},
}
}
func (d *dnsRecordResource) checkSupportsDnsRecords(diag *diag.Diagnostics) {
if !d.client.SupportsDnsRecords() {
diag.AddError("DNS Records are not supported", fmt.Sprintf("The Unifi controller in version %q does not support DNS records. Required controller version: %q", d.client.Version, base.ControllerVersionDnsRecords))
}
}
func (d *dnsRecordResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
d.checkSupportsDnsRecords(&resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
var plan dnsRecordModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
body := plan.asUnifiModel()
res, err := d.client.CreateDNSRecord(ctx, d.client.Site, body)
if err != nil {
resp.Diagnostics.AddError("Error creating DNS record", err.Error())
return
}
plan.merge(res)
resp.State.Set(ctx, plan)
resp.Diagnostics.Append(diags...)
}
func (d *dnsRecordResource) read(ctx context.Context, state *dnsRecordModel, diag *diag.Diagnostics) {
res, err := d.client.GetDNSRecord(ctx, d.client.Site, state.ID.ValueString())
if err != nil {
diag.AddError("Error reading DNS record", err.Error())
return
}
state.merge(res)
}
func (d *dnsRecordResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
d.checkSupportsDnsRecords(&resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
var state dnsRecordModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
d.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
diags = resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}
func (d *dnsRecordResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
d.checkSupportsDnsRecords(&resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
var plan, state dnsRecordModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
body := plan.asUnifiModel()
res, err := d.client.UpdateDNSRecord(ctx, d.client.Site, body)
if err != nil {
resp.Diagnostics.AddError("Error updating DNS record", err.Error())
return
}
state.merge(res)
diags := resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}
func (d *dnsRecordResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
d.checkSupportsDnsRecords(&resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
var state dnsRecordModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
err := d.client.DeleteDNSRecord(ctx, d.client.Site, state.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Error deleting DNS record", err.Error())
return
}
}
func (d *dnsRecordResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
d.checkSupportsDnsRecords(&resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
id := req.ID
if id == "" {
resp.Diagnostics.AddError("Invalid import ID", "The ID must be set")
return
}
state := dnsRecordModel{
ID: types.StringValue(id),
}
d.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
d.read(ctx, &state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
diags := resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}

View File

@@ -1,16 +1,17 @@
package v1 package dns
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func resourceDynamicDNS() *schema.Resource { func ResourceDynamicDNS() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_dynamic_dns` manages dynamic DNS settings for different providers.", Description: "`unifi_dynamic_dns` manages dynamic DNS settings for different providers.",
@@ -19,7 +20,7 @@ func resourceDynamicDNS() *schema.Resource {
UpdateContext: resourceDynamicDNSUpdate, UpdateContext: resourceDynamicDNSUpdate,
DeleteContext: resourceDynamicDNSDelete, DeleteContext: resourceDynamicDNSDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -76,7 +77,7 @@ func resourceDynamicDNS() *schema.Resource {
} }
func resourceDynamicDNSCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDynamicDNSCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceDynamicDNSGetResourceData(d) req, err := resourceDynamicDNSGetResourceData(d)
if err != nil { if err != nil {
@@ -127,7 +128,7 @@ func resourceDynamicDNSSetResourceData(resp *unifi.DynamicDNS, d *schema.Resourc
} }
func resourceDynamicDNSRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDynamicDNSRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -149,7 +150,7 @@ func resourceDynamicDNSRead(ctx context.Context, d *schema.ResourceData, meta in
} }
func resourceDynamicDNSUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDynamicDNSUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceDynamicDNSGetResourceData(d) req, err := resourceDynamicDNSGetResourceData(d)
if err != nil { if err != nil {
@@ -173,7 +174,7 @@ func resourceDynamicDNSUpdate(ctx context.Context, d *schema.ResourceData, meta
} }
func resourceDynamicDNSDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceDynamicDNSDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,9 +1,9 @@
package v1 package firewall
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
@@ -12,7 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceFirewallGroup() *schema.Resource { func ResourceFirewallGroup() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_firewall_group` manages groups of addresses or ports for use in firewall rules (`unifi_firewall_rule`).", Description: "`unifi_firewall_group` manages groups of addresses or ports for use in firewall rules (`unifi_firewall_rule`).",
@@ -21,7 +21,7 @@ func resourceFirewallGroup() *schema.Resource {
UpdateContext: resourceFirewallGroupUpdate, UpdateContext: resourceFirewallGroupUpdate,
DeleteContext: resourceFirewallGroupDelete, DeleteContext: resourceFirewallGroupDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -59,7 +59,7 @@ func resourceFirewallGroup() *schema.Resource {
} }
func resourceFirewallGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceFirewallGroupGetResourceData(d) req, err := resourceFirewallGroupGetResourceData(d)
if err != nil { if err != nil {
@@ -73,7 +73,7 @@ func resourceFirewallGroupCreate(ctx context.Context, d *schema.ResourceData, me
resp, err := c.CreateFirewallGroup(ctx, site, req) resp, err := c.CreateFirewallGroup(ctx, site, req)
if err != nil { if err != nil {
if provider.IsServerErrorContains(err, "api.err.FirewallGroupExisted") { if base.IsServerErrorContains(err, "api.err.FirewallGroupExisted") {
return diag.Errorf("firewall groups must have unique names: %s", err) return diag.Errorf("firewall groups must have unique names: %s", err)
} }
return diag.FromErr(err) return diag.FromErr(err)
@@ -107,7 +107,7 @@ func resourceFirewallGroupSetResourceData(resp *unifi.FirewallGroup, d *schema.R
} }
func resourceFirewallGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -129,7 +129,7 @@ func resourceFirewallGroupRead(ctx context.Context, d *schema.ResourceData, meta
} }
func resourceFirewallGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceFirewallGroupGetResourceData(d) req, err := resourceFirewallGroupGetResourceData(d)
if err != nil { if err != nil {
@@ -153,7 +153,7 @@ func resourceFirewallGroupUpdate(ctx context.Context, d *schema.ResourceData, me
} }
func resourceFirewallGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,9 +1,9 @@
package v1 package firewall
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"regexp" "regexp"
@@ -17,7 +17,7 @@ var firewallRuleProtocolRegexp = regexp.MustCompile("^$|all|([0-9]|[1-9][0-9]|1[
var firewallRuleProtocolV6Regexp = regexp.MustCompile("^$|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|ah|all|dccp|eigrp|esp|gre|icmpv6|ipcomp|ipv6|ipv6-frag|ipv6-icmp|ipv6-nonxt|ipv6-opts|ipv6-route|isis|l2tp|manet|mobility-header|mpls-in-ip|ospf|pim|rsvp|sctp|shim6|tcp|tcp_udp|udp|vrrp") var firewallRuleProtocolV6Regexp = regexp.MustCompile("^$|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|ah|all|dccp|eigrp|esp|gre|icmpv6|ipcomp|ipv6|ipv6-frag|ipv6-icmp|ipv6-nonxt|ipv6-opts|ipv6-route|isis|l2tp|manet|mobility-header|mpls-in-ip|ospf|pim|rsvp|sctp|shim6|tcp|tcp_udp|udp|vrrp")
var firewallRuleICMPv6TypenameRegexp = regexp.MustCompile("^$|address-unreachable|bad-header|beyond-scope|communication-prohibited|destination-unreachable|echo-reply|echo-request|failed-policy|neighbor-advertisement|neighbor-solicitation|no-route|packet-too-big|parameter-problem|port-unreachable|redirect|reject-route|router-advertisement|router-solicitation|time-exceeded|ttl-zero-during-reassembly|ttl-zero-during-transit|unknown-header-type|unknown-option") var firewallRuleICMPv6TypenameRegexp = regexp.MustCompile("^$|address-unreachable|bad-header|beyond-scope|communication-prohibited|destination-unreachable|echo-reply|echo-request|failed-policy|neighbor-advertisement|neighbor-solicitation|no-route|packet-too-big|parameter-problem|port-unreachable|redirect|reject-route|router-advertisement|router-solicitation|time-exceeded|ttl-zero-during-reassembly|ttl-zero-during-transit|unknown-header-type|unknown-option")
func resourceFirewallRule() *schema.Resource { func ResourceFirewallRule() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_firewall_rule` manages an individual firewall rule on the gateway.", Description: "`unifi_firewall_rule` manages an individual firewall rule on the gateway.",
@@ -26,7 +26,7 @@ func resourceFirewallRule() *schema.Resource {
UpdateContext: resourceFirewallRuleUpdate, UpdateContext: resourceFirewallRuleUpdate,
DeleteContext: resourceFirewallRuleDelete, DeleteContext: resourceFirewallRuleDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -131,7 +131,7 @@ func resourceFirewallRule() *schema.Resource {
Description: "The source port of the firewall rule.", Description: "The source port of the firewall rule.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ValidateFunc: validatePortRange, ValidateFunc: utils.ValidatePortRange,
}, },
"src_mac": { "src_mac": {
Description: "The source MAC address of the firewall rule.", Description: "The source MAC address of the firewall rule.",
@@ -172,7 +172,7 @@ func resourceFirewallRule() *schema.Resource {
Description: "The destination port of the firewall rule.", Description: "The destination port of the firewall rule.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ValidateFunc: validatePortRange, ValidateFunc: utils.ValidatePortRange,
}, },
// advanced // advanced
@@ -212,7 +212,7 @@ func resourceFirewallRule() *schema.Resource {
} }
func resourceFirewallRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceFirewallRuleGetResourceData(d) req, err := resourceFirewallRuleGetResourceData(d)
if err != nil { if err != nil {
@@ -226,7 +226,7 @@ func resourceFirewallRuleCreate(ctx context.Context, d *schema.ResourceData, met
resp, err := c.CreateFirewallRule(ctx, site, req) resp, err := c.CreateFirewallRule(ctx, site, req)
if err != nil { if err != nil {
if provider.IsServerErrorContains(err, "api.err.FirewallGroupTypeExists") { if base.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) return diag.Errorf("firewall rule groups must be of different group types (ie. a port group and address group): %s", err)
} }
@@ -320,7 +320,7 @@ func resourceFirewallRuleSetResourceData(resp *unifi.FirewallRule, d *schema.Res
} }
func resourceFirewallRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -342,7 +342,7 @@ func resourceFirewallRuleRead(ctx context.Context, d *schema.ResourceData, meta
} }
func resourceFirewallRuleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallRuleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceFirewallRuleGetResourceData(d) req, err := resourceFirewallRuleGetResourceData(d)
if err != nil { if err != nil {
@@ -366,7 +366,7 @@ func resourceFirewallRuleUpdate(ctx context.Context, d *schema.ResourceData, met
} }
func resourceFirewallRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceFirewallRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,15 +1,15 @@
package v1 package network
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func dataNetwork() *schema.Resource { func DataNetwork() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_network` data source can be used to retrieve settings for a network by name or ID.", Description: "`unifi_network` data source can be used to retrieve settings for a network by name or ID.",
@@ -129,7 +129,7 @@ func dataNetwork() *schema.Resource {
Computed: true, Computed: true,
}, },
"dhcp_v6_start": { "dhcp_v6_start": {
Description: "Start address of the DHCPv6 range. Used in static DHCPv6 configuration.", Description: "start address of the DHCPv6 range. Used in static DHCPv6 configuration.",
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
@@ -169,7 +169,7 @@ func dataNetwork() *schema.Resource {
Computed: true, Computed: true,
}, },
"ipv6_pd_start": { "ipv6_pd_start": {
Description: "Start address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`.", Description: "start address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`.",
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
@@ -281,7 +281,7 @@ func dataNetwork() *schema.Resource {
} }
func dataNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func dataNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
name := d.Get("name").(string) name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -1,14 +1,13 @@
package v1 package network
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func dataPortProfile() *schema.Resource { func DataPortProfile() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_port_profile` data source can be used to retrieve the ID for a port profile by name.", Description: "`unifi_port_profile` data source can be used to retrieve the ID for a port profile by name.",
@@ -37,7 +36,7 @@ func dataPortProfile() *schema.Resource {
} }
func dataPortProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func dataPortProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
name := d.Get("name").(string) name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -1,10 +1,10 @@
package v1 package network
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"regexp" "regexp"
"strings" "strings"
@@ -44,7 +44,7 @@ var (
validateIpV6RAPriority = validation.StringMatch(ipV6RAPriorityRegexp, "invalid IPv6 RA priority") validateIpV6RAPriority = validation.StringMatch(ipV6RAPriorityRegexp, "invalid IPv6 RA priority")
) )
func resourceNetwork() *schema.Resource { func ResourceNetwork() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_network` manages WAN/LAN/VLAN networks.", Description: "`unifi_network` manages WAN/LAN/VLAN networks.",
@@ -91,7 +91,7 @@ func resourceNetwork() *schema.Resource {
Description: "The subnet of the network. Must be a valid CIDR address.", Description: "The subnet of the network. Must be a valid CIDR address.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
DiffSuppressFunc: cidrDiffSuppress, DiffSuppressFunc: utils.CidrDiffSuppress,
ValidateFunc: utils.CidrValidate, ValidateFunc: utils.CidrValidate,
}, },
"network_group": { "network_group": {
@@ -189,7 +189,7 @@ func resourceNetwork() *schema.Resource {
Default: 86400, Default: 86400,
}, },
"dhcp_v6_start": { "dhcp_v6_start": {
Description: "Start address of the DHCPv6 range. Used in static DHCPv6 configuration.", Description: "start address of the DHCPv6 range. Used in static DHCPv6 configuration.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ValidateFunc: validation.IsIPv6Address, ValidateFunc: validation.IsIPv6Address,
@@ -240,7 +240,7 @@ func resourceNetwork() *schema.Resource {
Optional: true, Optional: true,
}, },
"ipv6_pd_start": { "ipv6_pd_start": {
Description: "Start address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`.", Description: "start address of the DHCPv6 range. Used if `ipv6_interface_type` is set to `pd`.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ValidateFunc: validation.IsIPv6Address, ValidateFunc: validation.IsIPv6Address,
@@ -384,7 +384,7 @@ func resourceNetwork() *schema.Resource {
} }
func resourceNetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceNetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceNetworkGetResourceData(d, meta) req, err := resourceNetworkGetResourceData(d, meta)
if err != nil { if err != nil {
@@ -626,7 +626,7 @@ func resourceNetworkSetResourceData(resp *unifi.Network, d *schema.ResourceData,
} }
func resourceNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -648,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 { func resourceNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceNetworkGetResourceData(d, meta) req, err := resourceNetworkGetResourceData(d, meta)
if err != nil { if err != nil {
@@ -671,7 +671,7 @@ func resourceNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta int
} }
func resourceNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -687,7 +687,7 @@ func resourceNetworkDelete(ctx context.Context, d *schema.ResourceData, meta int
} }
func importNetwork(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { func importNetwork(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {

View File

@@ -1,9 +1,9 @@
package v1 package network
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
@@ -12,7 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourcePortProfile() *schema.Resource { func ResourcePortProfile() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_port_profile` manages a port profile for use on network switches.", Description: "`unifi_port_profile` manages a port profile for use on network switches.",
@@ -21,7 +21,7 @@ func resourcePortProfile() *schema.Resource {
UpdateContext: resourcePortProfileUpdate, UpdateContext: resourcePortProfileUpdate,
DeleteContext: resourcePortProfileDelete, DeleteContext: resourcePortProfileDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -258,7 +258,7 @@ func resourcePortProfile() *schema.Resource {
} }
func resourcePortProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourcePortProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourcePortProfileGetResourceData(d) req, err := resourcePortProfileGetResourceData(d)
if err != nil { if err != nil {
@@ -371,7 +371,7 @@ func resourcePortProfileSetResourceData(resp *unifi.PortProfile, d *schema.Resou
} }
func resourcePortProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourcePortProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -392,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 { func resourcePortProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourcePortProfileGetResourceData(d) req, err := resourcePortProfileGetResourceData(d)
if err != nil { if err != nil {
@@ -416,7 +416,7 @@ func resourcePortProfileUpdate(ctx context.Context, d *schema.ResourceData, meta
} }
func resourcePortProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourcePortProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,10 +1,10 @@
package v1 package network
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
@@ -18,7 +18,7 @@ var (
wlanValidMinimumDataRate5g = []int{6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000} wlanValidMinimumDataRate5g = []int{6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000}
) )
func resourceWLAN() *schema.Resource { func ResourceWLAN() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_wlan` manages a WiFi network / SSID.", Description: "`unifi_wlan` manages a WiFi network / SSID.",
@@ -27,7 +27,7 @@ func resourceWLAN() *schema.Resource {
UpdateContext: resourceWLANUpdate, UpdateContext: resourceWLANUpdate,
DeleteContext: resourceWLANDelete, DeleteContext: resourceWLANDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -110,8 +110,8 @@ func resourceWLAN() *schema.Resource {
Optional: true, Optional: true,
Elem: &schema.Schema{ Elem: &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
ValidateFunc: validation.StringMatch(macAddressRegexp, "Mac address is invalid"), ValidateFunc: validation.StringMatch(utils.MacAddressRegexp, "Mac address is invalid"),
DiffSuppressFunc: macDiffSuppressFunc, DiffSuppressFunc: utils.MacDiffSuppressFunc,
}, },
}, },
"mac_filter_policy": { "mac_filter_policy": {
@@ -128,7 +128,7 @@ func resourceWLAN() *schema.Resource {
Optional: true, Optional: true,
}, },
"schedule": { "schedule": {
Description: "Start and stop schedules for the WLAN", Description: "start and stop schedules for the WLAN",
Type: schema.TypeList, Type: schema.TypeList,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
@@ -140,13 +140,13 @@ func resourceWLAN() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{"sun", "mon", "tue", "wed", "thu", "fri", "sat", "sun"}, false), ValidateFunc: validation.StringInSlice([]string{"sun", "mon", "tue", "wed", "thu", "fri", "sat", "sun"}, false),
}, },
"start_hour": { "start_hour": {
Description: "Start hour for the block (0-23).", Description: "start hour for the block (0-23).",
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ValidateFunc: validation.IntBetween(0, 23), ValidateFunc: validation.IntBetween(0, 23),
}, },
"start_minute": { "start_minute": {
Description: "Start minute for the block (0-59).", Description: "start minute for the block (0-59).",
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 0, Default: 0,
@@ -245,7 +245,7 @@ func resourceWLAN() *schema.Resource {
} }
func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*unifi.WLAN, error) { func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*unifi.WLAN, error) {
c := meta.(*provider.Client) c := meta.(*base.Client)
security := d.Get("security").(string) security := d.Get("security").(string)
passphrase := d.Get("passphrase").(string) passphrase := d.Get("passphrase").(string)
@@ -267,7 +267,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni
} }
if !c.SupportsWPA3() { if !c.SupportsWPA3() {
if wpa3 || wpa3Transition { 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, provider.ControllerVersionWPA3) return nil, fmt.Errorf("WPA 3 support is not available on controller version %q, you must be on %q or higher", c.Version, base.ControllerVersionWPA3)
} }
} }
@@ -355,7 +355,7 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni
} }
func resourceWLANCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceWLANCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceWLANGetResourceData(d, meta) req, err := resourceWLANGetResourceData(d, meta)
if err != nil { if err != nil {
@@ -443,7 +443,7 @@ func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData, meta
} }
func resourceWLANRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceWLANRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
site := d.Get("site").(string) site := d.Get("site").(string)
@@ -464,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 { func resourceWLANUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceWLANGetResourceData(d, meta) req, err := resourceWLANGetResourceData(d, meta)
if err != nil { if err != nil {
@@ -487,7 +487,7 @@ func resourceWLANUpdate(ctx context.Context, d *schema.ResourceData, meta interf
} }
func resourceWLANDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceWLANDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -1,5 +1,27 @@
package provider package provider
import (
"context"
"errors"
"fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider/apgroup"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/provider/device"
"github.com/filipowm/terraform-provider-unifi/internal/provider/dns"
"github.com/filipowm/terraform-provider-unifi/internal/provider/firewall"
"github.com/filipowm/terraform-provider-unifi/internal/provider/network"
"github.com/filipowm/terraform-provider-unifi/internal/provider/radius"
"github.com/filipowm/terraform-provider-unifi/internal/provider/routing"
"github.com/filipowm/terraform-provider-unifi/internal/provider/settings"
"github.com/filipowm/terraform-provider-unifi/internal/provider/site"
"github.com/filipowm/terraform-provider-unifi/internal/provider/user"
"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"
"net/http"
"strings"
)
const ( const (
ProviderUsernameDescription = "Local user name for the Unifi controller API. Can be specified with the `UNIFI_USERNAME` environment variable." 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." ProviderPasswordDescription = "Password for the user accessing the API. Can be specified with the `UNIFI_PASSWORD` environment variable."
@@ -11,3 +33,135 @@ const (
"if you are using your local API without setting up a signed certificate. Can be specified with the " + "if you are using your local API without setting up a signed certificate. Can be specified with the " +
"`UNIFI_INSECURE` environment variable." "`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: ProviderUsernameDescription,
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_USERNAME", ""),
},
"password": {
Description: ProviderPasswordDescription,
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_PASSWORD", ""),
},
"api_key": {
Description: ProviderAPIKeyDescription,
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API_KEY", ""),
},
"api_url": {
Description: ProviderAPIURLDescription,
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_API", ""),
},
"site": {
Description: ProviderSiteDescription,
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_SITE", "default"),
},
"allow_insecure": {
Description: ProviderAllowInsecureDescription,
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("UNIFI_INSECURE", false),
},
},
DataSourcesMap: map[string]*schema.Resource{
"unifi_ap_group": apgroup.DataAPGroup(),
"unifi_network": network.DataNetwork(),
"unifi_port_profile": network.DataPortProfile(),
"unifi_radius_profile": radius.DataRADIUSProfile(),
"unifi_user_group": user.DataUserGroup(),
"unifi_user": user.DataUser(),
"unifi_account": radius.DataAccount(),
},
ResourcesMap: map[string]*schema.Resource{
// TODO: "unifi_ap_group"
"unifi_device": device.ResourceDevice(),
"unifi_dynamic_dns": dns.ResourceDynamicDNS(),
"unifi_firewall_group": firewall.ResourceFirewallGroup(),
"unifi_firewall_rule": firewall.ResourceFirewallRule(),
"unifi_network": network.ResourceNetwork(),
"unifi_port_forward": routing.ResourcePortForward(),
"unifi_static_route": routing.ResourceStaticRoute(),
"unifi_wlan": network.ResourceWLAN(),
"unifi_port_profile": network.ResourcePortProfile(),
"unifi_site": site.ResourceSite(),
"unifi_account": radius.ResourceAccount(),
"unifi_radius_profile": radius.ResourceRadiusProfile(),
"unifi_setting_mgmt": settings.ResourceSettingMgmt(),
"unifi_setting_radius": settings.ResourceSettingRadius(),
"unifi_setting_usg": settings.ResourceSettingUsg(),
"unifi_user_group": user.ResourceUserGroup(),
"unifi_user": user.ResourceUser(),
},
}
p.ConfigureContextFunc = configure(version, p)
return p
}
}
func createHTTPTransport(insecure bool, subsystem string) http.RoundTripper {
transport := base.CreateHttpTransport(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 := base.NewClient(&base.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,8 +1,9 @@
package v2 package provider
import ( import (
"context" "context"
up "github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/provider/dns"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
@@ -15,7 +16,7 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
) )
func New(version string) func() provider.Provider { func NewV2(version string) func() provider.Provider {
return func() provider.Provider { return func() provider.Provider {
return &unifiProvider{ return &unifiProvider{
version: version, version: version,
@@ -45,32 +46,32 @@ func (p *unifiProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"username": schema.StringAttribute{ "username": schema.StringAttribute{
MarkdownDescription: up.ProviderUsernameDescription, MarkdownDescription: ProviderUsernameDescription,
Optional: true, Optional: true,
}, },
"password": schema.StringAttribute{ "password": schema.StringAttribute{
MarkdownDescription: up.ProviderPasswordDescription, MarkdownDescription: ProviderPasswordDescription,
Optional: true, Optional: true,
Sensitive: true, Sensitive: true,
}, },
"api_key": schema.StringAttribute{ "api_key": schema.StringAttribute{
MarkdownDescription: up.ProviderAPIKeyDescription, MarkdownDescription: ProviderAPIKeyDescription,
Optional: true, Optional: true,
Sensitive: true, Sensitive: true,
}, },
"api_url": schema.StringAttribute{ "api_url": schema.StringAttribute{
MarkdownDescription: up.ProviderAPIURLDescription, MarkdownDescription: ProviderAPIURLDescription,
Validators: []validator.String{ 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 stringvalidator.LengthAtLeast(1), // workaround for `required: true`, because it fails on doc generation due to incorrectly detected difference between v1 and v2
}, },
Optional: true, Optional: true,
}, },
"site": schema.StringAttribute{ "site": schema.StringAttribute{
MarkdownDescription: up.ProviderSiteDescription, MarkdownDescription: ProviderSiteDescription,
Optional: true, Optional: true,
}, },
"allow_insecure": schema.BoolAttribute{ "allow_insecure": schema.BoolAttribute{
MarkdownDescription: up.ProviderAllowInsecureDescription, MarkdownDescription: ProviderAllowInsecureDescription,
Optional: true, Optional: true,
}, },
}, },
@@ -97,7 +98,7 @@ func (p *unifiProvider) Configure(ctx context.Context, req provider.ConfigureReq
"Unknown UniFi Controller API URL", "Unknown UniFi Controller API URL",
"The provider cannot create the UniFi Controller API client as there is an unknown configuration value "+ "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 "+ "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.", "the configuration, or use the UNIFI_API environment variable.",
) )
} }
@@ -111,7 +112,7 @@ func (p *unifiProvider) Configure(ctx context.Context, req provider.ConfigureReq
username := utils.GetAnyStringEnv("UNIFI_USERNAME") username := utils.GetAnyStringEnv("UNIFI_USERNAME")
password := utils.GetAnyStringEnv("UNIFI_PASSWORD") password := utils.GetAnyStringEnv("UNIFI_PASSWORD")
apiKey := utils.GetAnyStringEnv("UNIFI_API_KEY") apiKey := utils.GetAnyStringEnv("UNIFI_API_KEY")
apiUrl := utils.GetAnyStringEnv("UNIFI_API_URL") apiUrl := utils.GetAnyStringEnv("UNIFI_API")
site := utils.GetAnyStringEnv("UNIFI_SITE") site := utils.GetAnyStringEnv("UNIFI_SITE")
insecure := utils.GetAnyBoolEnv("UNIFI_INSECURE") insecure := utils.GetAnyBoolEnv("UNIFI_INSECURE")
@@ -147,7 +148,7 @@ func (p *unifiProvider) Configure(ctx context.Context, req provider.ConfigureReq
if site == "" { if site == "" {
site = "default" // set default site if not provided site = "default" // set default site if not provided
} }
c, err := up.NewClient(&up.ClientConfig{ c, err := base.NewClient(&base.ClientConfig{
Username: username, Username: username,
Password: password, Password: password,
ApiKey: apiKey, ApiKey: apiKey,
@@ -164,9 +165,14 @@ func (p *unifiProvider) Configure(ctx context.Context, req provider.ConfigureReq
} }
func (p *unifiProvider) Resources(_ context.Context) []func() resource.Resource { func (p *unifiProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{} return []func() resource.Resource{
dns.NewDnsRecordResource,
}
} }
func (p *unifiProvider) DataSources(_ context.Context) []func() datasource.DataSource { func (p *unifiProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{} return []func() datasource.DataSource{
dns.NewDnsRecordsDatasource,
dns.NewDnsRecordDatasource,
}
} }

View File

@@ -1,14 +1,13 @@
package v1 package radius
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func dataAccount() *schema.Resource { func DataAccount() *schema.Resource {
return &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",
@@ -58,7 +57,7 @@ func dataAccount() *schema.Resource {
} }
func dataAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func dataAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
name := d.Get("name").(string) name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -1,14 +1,13 @@
package v1 package radius
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func dataRADIUSProfile() *schema.Resource { func DataRADIUSProfile() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_radius_profile` data source can be used to retrieve the ID for a RADIUS profile by name.", Description: "`unifi_radius_profile` data source can be used to retrieve the ID for a RADIUS profile by name.",
@@ -37,7 +36,7 @@ func dataRADIUSProfile() *schema.Resource {
} }
func dataRADIUSProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func dataRADIUSProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
name := d.Get("name").(string) name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -1,9 +1,10 @@
package v1 package radius
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -11,7 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceAccount() *schema.Resource { func ResourceAccount() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_account` manages a RADIUS user account\n\n" + Description: "`unifi_account` manages a RADIUS user account\n\n" +
"To authenticate devices based on MAC address, use the MAC address as the username and password under client creation. \n" + "To authenticate devices based on MAC address, use the MAC address as the username and password under client creation. \n" +
@@ -24,7 +25,7 @@ func resourceAccount() *schema.Resource {
UpdateContext: resourceAccountUpdate, UpdateContext: resourceAccountUpdate,
DeleteContext: resourceAccountDelete, DeleteContext: resourceAccountDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -75,7 +76,7 @@ func resourceAccount() *schema.Resource {
} }
func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceAccountGetResourceData(d) req, err := resourceAccountGetResourceData(d)
if err != nil { if err != nil {
@@ -98,7 +99,7 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, meta int
} }
func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -122,7 +123,7 @@ func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, meta int
} }
func resourceAccountDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceAccountDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
//name := d.Get("name").(string) //name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)
@@ -139,7 +140,7 @@ func resourceAccountDelete(ctx context.Context, d *schema.ResourceData, meta int
} }
func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,10 +1,10 @@
package v1 package radius
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"strings" "strings"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
@@ -13,7 +13,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceRadiusProfile() *schema.Resource { func ResourceRadiusProfile() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_radius_profile` manages RADIUS profiles.", Description: "`unifi_radius_profile` manages RADIUS profiles.",
@@ -235,7 +235,7 @@ func fromAcctServer(sshKey unifi.RADIUSProfileAcctServers) (map[string]interface
} }
func resourceRadiusProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceRadiusProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceRadiusProfileGetResourceData(d) req, err := resourceRadiusProfileGetResourceData(d)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
@@ -303,7 +303,7 @@ func resourceRadiusProfileSetResourceData(resp *unifi.RADIUSProfile, d *schema.R
} }
func resourceRadiusProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceRadiusProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -324,7 +324,7 @@ func resourceRadiusProfileRead(ctx context.Context, d *schema.ResourceData, meta
} }
func resourceRadiusProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceRadiusProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceRadiusProfileGetResourceData(d) req, err := resourceRadiusProfileGetResourceData(d)
if err != nil { if err != nil {
@@ -348,7 +348,7 @@ func resourceRadiusProfileUpdate(ctx context.Context, d *schema.ResourceData, me
} }
func resourceRadiusProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceRadiusProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -362,7 +362,7 @@ func resourceRadiusProfileDelete(ctx context.Context, d *schema.ResourceData, me
} }
func importRadiusProfile(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { func importRadiusProfile(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {

View File

@@ -1,9 +1,9 @@
package v1 package routing
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
@@ -12,7 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourcePortForward() *schema.Resource { func ResourcePortForward() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_port_forward` manages a port forwarding rule on the gateway.", Description: "`unifi_port_forward` manages a port forwarding rule on the gateway.",
@@ -21,7 +21,7 @@ func resourcePortForward() *schema.Resource {
UpdateContext: resourcePortForwardUpdate, UpdateContext: resourcePortForwardUpdate,
DeleteContext: resourcePortForwardDelete, DeleteContext: resourcePortForwardDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -41,7 +41,7 @@ func resourcePortForward() *schema.Resource {
Description: "The destination port for the forwarding.", Description: "The destination port for the forwarding.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ValidateFunc: validatePortRange, ValidateFunc: utils.ValidatePortRange,
}, },
// TODO: remove this, disabled rules should just be deleted. // TODO: remove this, disabled rules should just be deleted.
"enabled": { "enabled": {
@@ -62,7 +62,7 @@ func resourcePortForward() *schema.Resource {
Description: "The port to forward traffic to.", Description: "The port to forward traffic to.",
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ValidateFunc: validatePortRange, ValidateFunc: utils.ValidatePortRange,
}, },
"log": { "log": {
Description: "Specifies whether to log forwarded traffic or not.", Description: "Specifies whether to log forwarded traffic or not.",
@@ -104,7 +104,7 @@ func resourcePortForward() *schema.Resource {
} }
func resourcePortForwardCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourcePortForwardCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourcePortForwardGetResourceData(d) req, err := resourcePortForwardGetResourceData(d)
if err != nil { if err != nil {
@@ -155,7 +155,7 @@ func resourcePortForwardSetResourceData(resp *unifi.PortForward, d *schema.Resou
} }
func resourcePortForwardRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourcePortForwardRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -176,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 { func resourcePortForwardUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourcePortForwardGetResourceData(d) req, err := resourcePortForwardGetResourceData(d)
if err != nil { if err != nil {
@@ -200,7 +200,7 @@ func resourcePortForwardUpdate(ctx context.Context, d *schema.ResourceData, meta
} }
func resourcePortForwardDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourcePortForwardDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,10 +1,10 @@
package v1 package routing
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
@@ -13,7 +13,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceStaticRoute() *schema.Resource { func ResourceStaticRoute() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_static_route` manages a static route.", Description: "`unifi_static_route` manages a static route.",
@@ -22,7 +22,7 @@ func resourceStaticRoute() *schema.Resource {
UpdateContext: resourceStaticRouteUpdate, UpdateContext: resourceStaticRouteUpdate,
DeleteContext: resourceStaticRouteDelete, DeleteContext: resourceStaticRouteDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -49,7 +49,7 @@ func resourceStaticRoute() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ValidateFunc: utils.CidrValidate, ValidateFunc: utils.CidrValidate,
DiffSuppressFunc: cidrDiffSuppress, DiffSuppressFunc: utils.CidrDiffSuppress,
}, },
"type": { "type": {
Description: "The type of static route. Can be `interface-route`, `nexthop-route`, or `blackhole`.", Description: "The type of static route. Can be `interface-route`, `nexthop-route`, or `blackhole`.",
@@ -79,7 +79,7 @@ func resourceStaticRoute() *schema.Resource {
} }
func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceStaticRouteGetResourceData(d) req, err := resourceStaticRouteGetResourceData(d)
if err != nil { if err != nil {
@@ -154,7 +154,7 @@ func resourceStaticRouteSetResourceData(resp *unifi.Routing, d *schema.ResourceD
} }
func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceStaticRouteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -176,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 { func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceStaticRouteGetResourceData(d) req, err := resourceStaticRouteGetResourceData(d)
if err != nil { if err != nil {
@@ -200,7 +200,7 @@ func resourceStaticRouteUpdate(ctx context.Context, d *schema.ResourceData, meta
} }
func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceStaticRouteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,10 +1,11 @@
package v1 package settings
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -14,7 +15,7 @@ import (
// TODO: probably need to update this to be more like setting_usg, // TODO: probably need to update this to be more like setting_usg,
// using locking, and upsert, more computed, etc. // using locking, and upsert, more computed, etc.
func resourceSettingMgmt() *schema.Resource { func ResourceSettingMgmt() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_setting_mgmt` manages settings for a unifi site.", Description: "`unifi_setting_mgmt` manages settings for a unifi site.",
@@ -23,7 +24,7 @@ func resourceSettingMgmt() *schema.Resource {
UpdateContext: resourceSettingMgmtUpdate, UpdateContext: resourceSettingMgmtUpdate,
DeleteContext: resourceSettingMgmtDelete, DeleteContext: resourceSettingMgmtDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -142,7 +143,7 @@ func resourceSettingMgmtGetResourceData(d *schema.ResourceData, meta interface{}
} }
func resourceSettingMgmtCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingMgmtCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceSettingMgmtGetResourceData(d, meta) req, err := resourceSettingMgmtGetResourceData(d, meta)
if err != nil { if err != nil {
@@ -178,7 +179,7 @@ func resourceSettingMgmtSetResourceData(resp *unifi.SettingMgmt, d *schema.Resou
} }
func resourceSettingMgmtRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingMgmtRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -198,7 +199,7 @@ func resourceSettingMgmtRead(ctx context.Context, d *schema.ResourceData, meta i
} }
func resourceSettingMgmtUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingMgmtUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceSettingMgmtGetResourceData(d, meta) req, err := resourceSettingMgmtGetResourceData(d, meta)
if err != nil { if err != nil {

View File

@@ -1,9 +1,10 @@
package v1 package settings
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -11,7 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceSettingRadius() *schema.Resource { func ResourceSettingRadius() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_setting_radius` manages settings for the built-in RADIUS server.", Description: "`unifi_setting_radius` manages settings for the built-in RADIUS server.",
@@ -20,7 +21,7 @@ func resourceSettingRadius() *schema.Resource {
UpdateContext: resourceSettingRadiusUpdate, UpdateContext: resourceSettingRadiusUpdate,
DeleteContext: schema.NoopContext, DeleteContext: schema.NoopContext,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -99,7 +100,7 @@ func resourceSettingRadiusGetResourceData(d *schema.ResourceData, meta interface
} }
func resourceSettingRadiusCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingRadiusCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceSettingRadiusGetResourceData(d, meta) req, err := resourceSettingRadiusGetResourceData(d, meta)
if err != nil { if err != nil {
@@ -134,7 +135,7 @@ func resourceSettingRadiusSetResourceData(resp *unifi.SettingRadius, d *schema.R
} }
func resourceSettingRadiusRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingRadiusRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -154,7 +155,7 @@ func resourceSettingRadiusRead(ctx context.Context, d *schema.ResourceData, meta
} }
func resourceSettingRadiusUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingRadiusUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceSettingRadiusGetResourceData(d, meta) req, err := resourceSettingRadiusGetResourceData(d, meta)
if err != nil { if err != nil {

View File

@@ -1,10 +1,10 @@
package v1 package settings
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils" "github.com/filipowm/terraform-provider-unifi/internal/utils"
"sync" "sync"
@@ -24,7 +24,7 @@ func resourceSettingUsgLocker(f func(context.Context, *schema.ResourceData, inte
} }
} }
func resourceSettingUsg() *schema.Resource { func ResourceSettingUsg() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_setting_usg` manages settings for a Unifi Security Gateway.", Description: "`unifi_setting_usg` manages settings for a Unifi Security Gateway.",
@@ -33,7 +33,7 @@ func resourceSettingUsg() *schema.Resource {
UpdateContext: resourceSettingUsgLocker(resourceSettingUsgUpsert), UpdateContext: resourceSettingUsgLocker(resourceSettingUsgUpsert),
DeleteContext: schema.NoopContext, DeleteContext: schema.NoopContext,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -75,7 +75,7 @@ func resourceSettingUsg() *schema.Resource {
} }
func resourceSettingUsgUpdateResourceData(d *schema.ResourceData, meta interface{}, setting *unifi.SettingUsg) error { func resourceSettingUsgUpdateResourceData(d *schema.ResourceData, meta interface{}, setting *unifi.SettingUsg) error {
c := meta.(*provider.Client) c := meta.(*base.Client)
//nolint // GetOkExists is deprecated, but using here: //nolint // GetOkExists is deprecated, but using here:
if mdns, hasMdns := d.GetOkExists("multicast_dns_enabled"); hasMdns { if mdns, hasMdns := d.GetOkExists("multicast_dns_enabled"); hasMdns {
@@ -100,7 +100,7 @@ func resourceSettingUsgUpdateResourceData(d *schema.ResourceData, meta interface
} }
func resourceSettingUsgUpsert(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingUsgUpsert(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -149,7 +149,7 @@ func resourceSettingUsgSetResourceData(resp *unifi.SettingUsg, d *schema.Resourc
} }
func resourceSettingUsgRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSettingUsgRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {

View File

@@ -1,17 +1,16 @@
package v1 package site
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/filipowm/terraform-provider-unifi/internal/provider"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func resourceSite() *schema.Resource { func ResourceSite() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_site` manages Unifi sites", Description: "`unifi_site` manages Unifi sites",
@@ -44,7 +43,7 @@ func resourceSite() *schema.Resource {
} }
func resourceSiteImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { func resourceSiteImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
_, err := c.GetSite(ctx, id) _, err := c.GetSite(ctx, id)
@@ -74,7 +73,7 @@ func resourceSiteImport(ctx context.Context, d *schema.ResourceData, meta interf
} }
func resourceSiteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSiteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
description := d.Get("description").(string) description := d.Get("description").(string)
@@ -96,7 +95,7 @@ func resourceSiteSetResourceData(resp *unifi.Site, d *schema.ResourceData) diag.
} }
func resourceSiteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSiteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -113,7 +112,7 @@ func resourceSiteRead(ctx context.Context, d *schema.ResourceData, meta interfac
} }
func resourceSiteUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSiteUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := &unifi.Site{ site := &unifi.Site{
ID: d.Id(), ID: d.Id(),
@@ -130,7 +129,7 @@ func resourceSiteUpdate(ctx context.Context, d *schema.ResourceData, meta interf
} }
func resourceSiteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceSiteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
_, err := c.DeleteSite(ctx, id) _, err := c.DeleteSite(ctx, id)
return diag.FromErr(err) return diag.FromErr(err)

View File

@@ -0,0 +1,277 @@
package testing
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"net/http"
"os"
"path/filepath"
"sync"
"testing"
"time"
"github.com/filipowm/go-unifi/unifi"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/compose"
)
const (
TestEnvStarting testEnvironmentStatus = iota
TestEnvReady
TestEnvDown
TestEnvUnknown
)
type testEnvironmentStatus int
type TestEnvironment struct {
Client unifi.Client
Endpoint string
Shutdown func()
ctx context.Context
internalClient *http.Client
mutex sync.Mutex
timeout time.Duration
}
type envStatus struct {
Meta struct {
Up bool `json:"up"`
} `json:"meta"`
}
func Run(m *testing.M, callback func(env *TestEnvironment)) int {
if os.Getenv(resource.EnvTfAcc) == "" {
// short circuit non-acceptance test runs
os.Exit(m.Run())
}
env := NewTestEnvironment(5 * time.Minute)
return env.run(m, callback)
}
func NewTestEnvironment(startupTimeout time.Duration) *TestEnvironment {
c := http.Client{Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}}
ctx := context.Background()
return &TestEnvironment{
Endpoint: "https://localhost:8443", // default endpoint, assumed
timeout: startupTimeout,
mutex: sync.Mutex{},
ctx: ctx,
internalClient: &c,
Shutdown: func() {},
}
}
func (te *TestEnvironment) isReady() bool {
if st, _ := te.readStatus(te.ctx); st != TestEnvReady {
return false
}
return true
}
func (te *TestEnvironment) run(m *testing.M, callback func(env *TestEnvironment)) int {
err := te.Start()
defer func() {
te.Shutdown()
}()
if err != nil {
panic(err)
}
err = te.WaitUntilReady()
if err != nil {
panic(err)
}
c, err := te.newTestClient()
if err != nil {
panic(err)
}
te.Client = c
callback(te)
return m.Run()
}
func (te *TestEnvironment) readStatus(ctx context.Context) (testEnvironmentStatus, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/status", te.Endpoint), nil)
if err != nil {
return TestEnvUnknown, err
}
req = req.WithContext(ctx)
r, err := te.internalClient.Do(req)
if err != nil {
return TestEnvDown, err
}
resp := envStatus{}
err = json.NewDecoder(r.Body).Decode(&resp)
if err != nil {
return TestEnvUnknown, err
}
if resp.Meta.Up {
return TestEnvReady, nil
}
return TestEnvStarting, nil
}
func findFileInProject(filename string) (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
// Walk up the directory tree until we find a file
for {
path := filepath.Join(wd, filename)
if _, err := os.Stat(path); err == nil {
return path, nil
}
if wd == "/" {
break
}
wd = filepath.Dir(wd)
}
return "", fmt.Errorf("file %s not found in project", filename)
}
func (te *TestEnvironment) startDockerController(ctx context.Context) error {
composeFile, err := findFileInProject("docker-compose.yaml")
if err != nil {
return fmt.Errorf("failed to find docker-compose.yaml file: %w", err)
}
dc, err := compose.NewDockerCompose(composeFile)
shutdown := func() {
if dc != nil {
if err := dc.Down(context.Background(), compose.RemoveOrphans(true), compose.RemoveImagesLocal); err != nil {
panic(err)
}
}
}
te.Shutdown = shutdown
if err != nil {
return err
}
if err = dc.WithOsEnv().Up(ctx, compose.Wait(true)); err != nil {
return fmt.Errorf("failed to Start docker-compose. Controller container might be already running or starting: %w", err)
}
container, err := dc.ServiceContainer(ctx, "unifi")
if err != nil {
return err
}
// Dump the container logs on exit.
//
// TODO: Use https://pkg.go.dev/github.com/testcontainers/testcontainers-go#LogConsumer instead.
te.Shutdown = func() {
shutdown()
if os.Getenv("UNIFI_STDOUT") == "" {
return
}
stream, err := container.Logs(ctx)
if err != nil {
fmt.Printf("Failed to get logs from container: %v", err)
return
}
buffer := new(bytes.Buffer)
buffer.ReadFrom(stream)
testcontainers.Logger.Printf("%s", buffer)
}
endpoint, err := container.PortEndpoint(ctx, "8443/tcp", "https")
if err != nil {
return err
}
te.Endpoint = endpoint
return nil
}
func (te *TestEnvironment) WaitUntilReady() error {
te.mutex.Lock()
ctx, cancel := context.WithTimeoutCause(te.ctx, te.timeout, fmt.Errorf("controller was not ready within %s", te.timeout))
defer cancel()
defer te.mutex.Unlock()
if st, _ := te.readStatus(ctx); st == TestEnvDown || st == TestEnvUnknown {
return fmt.Errorf("controller is not starting nor running. Use Start() first to Start the controller")
}
te.waitForController(ctx)
if !te.isReady() {
return fmt.Errorf("controller is not ready within %s", te.timeout)
}
return nil
}
func (te *TestEnvironment) Start() error {
tflog.Error(te.ctx, "Starting test environment")
if te.isReady() {
tflog.Warn(te.ctx, "Environment is already running at "+te.Endpoint)
if te.Client == nil {
c, err := te.newTestClient()
if err != nil {
return err
}
te.Client = c
}
return nil
}
ctx, cancel := context.WithTimeoutCause(te.ctx, te.timeout, fmt.Errorf("controller did not Start within %s", te.timeout))
defer cancel()
err := te.startDockerController(ctx)
if err != nil {
return err
}
tflog.Info(te.ctx, "Environment is starting at "+te.Endpoint)
return nil
}
func (te *TestEnvironment) waitForController(ctx context.Context) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
for {
if st, err := te.readStatus(ctx); err != nil {
return
} else if st == TestEnvReady {
wg.Done()
return
}
time.Sleep(1 * time.Second)
}
}()
wg.Wait()
}
func (te *TestEnvironment) newTestClient() (unifi.Client, error) {
const user = "admin"
const password = "admin"
var err error
if err = os.Setenv("UNIFI_USERNAME", user); err != nil {
return nil, err
}
if err = os.Setenv("UNIFI_PASSWORD", password); err != nil {
return nil, err
}
if err = os.Setenv("UNIFI_INSECURE", "true"); err != nil {
return nil, err
}
if err = os.Setenv("UNIFI_API", te.Endpoint); err != nil {
return nil, err
}
return unifi.NewClient(&unifi.ClientConfig{
URL: te.Endpoint,
User: user,
Password: password,
VerifySSL: false,
ValidationMode: unifi.DisableValidation,
Logger: unifi.NewDefaultLogger(unifi.WarnLevel),
})
}

View File

@@ -0,0 +1,78 @@
package testing
import (
"fmt"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"os"
"strings"
"testing"
)
// MarkAccTest marks the test as acceptance test. Useful when executing code before resource.ParallelTest or resource.Test
// to bring acceptance test check earlier when test environment is required
func MarkAccTest(t *testing.T) {
t.Helper()
if os.Getenv(resource.EnvTfAcc) == "" {
t.Skipf("Acceptance tests skipped unless env '%s' set", resource.EnvTfAcc)
return
}
}
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
}
// SiteAndIDImportStateIDFunc returns a function that can be used to import resources that require site and id.
func SiteAndIDImportStateIDFunc(resourceName string) func(*terraform.State) (string, error) {
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return "", fmt.Errorf("not found: %s", resourceName)
}
id := rs.Primary.Attributes["id"]
site := rs.Primary.Attributes["site"]
return site + ":" + id, nil
}
}
// PreCheck checks if provided environment variables are set. If not, it will fail the test.
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)
}
}
}
func CheckPlanPreApply(checks ...plancheck.PlanCheck) resource.ConfigPlanChecks {
return resource.ConfigPlanChecks{
PreApply: checks,
}
}
func CheckResourceAction(resourceAddress string, action plancheck.ResourceActionType) resource.ConfigPlanChecks {
return CheckPlanPreApply(plancheck.ExpectResourceAction(resourceAddress, action))
}
func ComposeConfig(configs ...string) string {
return strings.Join(configs, "\n")
}

View File

@@ -1,34 +1,48 @@
package v1 package testing
import ( import (
"github.com/apparentlymart/go-cidr/cidr"
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"math"
"net" "net"
"regexp"
"strings"
"sync" "sync"
"testing" "testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
) )
var macAddressRegexp = regexp.MustCompile("^([0-9a-fA-F][0-9a-fA-F][-:]){5}([0-9a-fA-F][0-9a-fA-F])$") const (
vlanMin = 2
func cleanMAC(mac string) string { vlanMax = 4095
return strings.TrimSpace(strings.ReplaceAll(strings.ToLower(mac), "-", ":")) )
}
func macDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
old = cleanMAC(old)
new = cleanMAC(new)
return old == new
}
var ( var (
macInit sync.Once macInit sync.Once
macPool = mapset.NewSet[*net.HardwareAddr]() macPool = mapset.NewSet[*net.HardwareAddr]()
network = &net.IPNet{
IP: net.IPv4(10, 0, 0, 0).To4(),
Mask: net.IPv4Mask(255, 0, 0, 0),
}
vlanLock sync.Mutex
vlanNext = vlanMin
) )
func allocateTestMac(t *testing.T) (string, func()) { func GetTestVLAN(t *testing.T) (*net.IPNet, int) {
vlanLock.Lock()
defer vlanLock.Unlock()
vlan := vlanNext
vlanNext++
subnet, err := cidr.Subnet(network, int(math.Ceil(math.Log2(vlanMax))), vlan)
if err != nil {
t.Error(err)
}
return subnet, vlan
}
func AllocateTestMac(t *testing.T) (string, func()) {
MarkAccTest(t)
macInit.Do(func() { macInit.Do(func() {
// for test MAC addresses, see https://tools.ietf.org/html/rfc7042#section-2.1. // for test MAC addresses, see https://tools.ietf.org/html/rfc7042#section-2.1.
for i := 0; i < 512; i++ { for i := 0; i < 512; i++ {

View File

@@ -0,0 +1,23 @@
package testing
import (
"fmt"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
)
func RandHostname() string {
return RandHostnameWithSuffix("test.com")
}
func RandHostnameWithSuffix(suffix string) string {
return fmt.Sprintf("%s.%s", RandAlpha(10), suffix)
}
func RandAlpha(len int) string {
return acctest.RandStringFromCharSet(len, acctest.CharSetAlpha)
}
func RandIpAddress() string {
ip, _ := acctest.RandIpAddress("192.168.0.1/24")
return ip
}

View File

@@ -0,0 +1,10 @@
package testing
import (
"fmt"
"regexp"
)
func MissingArgumentErrorRegex(arg string) *regexp.Regexp {
return regexp.MustCompile(fmt.Sprintf(`%q is required`, arg))
}

View File

@@ -1,8 +1,9 @@
package v1 package user
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"strings" "strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -10,7 +11,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func dataUser() *schema.Resource { func DataUser() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_user` retrieves properties of a user (or \"client\" in the UI) of the network by MAC address.", Description: "`unifi_user` retrieves properties of a user (or \"client\" in the UI) of the network by MAC address.",
@@ -27,8 +28,8 @@ func dataUser() *schema.Resource {
Description: "The MAC address of the user.", Description: "The MAC address of the user.",
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
DiffSuppressFunc: macDiffSuppressFunc, DiffSuppressFunc: utils.MacDiffSuppressFunc,
ValidateFunc: validation.StringMatch(macAddressRegexp, "Mac address is invalid"), ValidateFunc: validation.StringMatch(utils.MacAddressRegexp, "Mac address is invalid"),
}, },
// read-only / computed // read-only / computed
@@ -92,7 +93,7 @@ func dataUser() *schema.Resource {
} }
func dataUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func dataUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {

View File

@@ -1,14 +1,13 @@
package v1 package user
import ( import (
"context" "context"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func dataUserGroup() *schema.Resource { func DataUserGroup() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_user_group` data source can be used to retrieve the ID for a user group by name.", Description: "`unifi_user_group` data source can be used to retrieve the ID for a user group by name.",
@@ -46,7 +45,7 @@ func dataUserGroup() *schema.Resource {
} }
func dataUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func dataUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
name := d.Get("name").(string) name := d.Get("name").(string)
site := d.Get("site").(string) site := d.Get("site").(string)

View File

@@ -1,16 +1,17 @@
package v1 package user
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
func resourceUser() *schema.Resource { func ResourceUser() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_user` manages a user (or \"client\" in the UI) of the network, these are identified " + Description: "`unifi_user` manages a user (or \"client\" in the UI) of the network, these are identified " +
"by unique MAC addresses.\n\n" + "by unique MAC addresses.\n\n" +
@@ -22,7 +23,7 @@ func resourceUser() *schema.Resource {
UpdateContext: resourceUserUpdate, UpdateContext: resourceUserUpdate,
DeleteContext: resourceUserDelete, DeleteContext: resourceUserDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -43,8 +44,8 @@ func resourceUser() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
DiffSuppressFunc: macDiffSuppressFunc, DiffSuppressFunc: utils.MacDiffSuppressFunc,
ValidateFunc: validation.StringMatch(macAddressRegexp, "Mac address is invalid"), ValidateFunc: validation.StringMatch(utils.MacAddressRegexp, "Mac address is invalid"),
}, },
"name": { "name": {
Description: "The name of the user.", Description: "The name of the user.",
@@ -119,7 +120,7 @@ func resourceUser() *schema.Resource {
} }
func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceUserGetResourceData(d) req, err := resourceUserGetResourceData(d)
if err != nil { if err != nil {
@@ -135,7 +136,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
resp, err := c.CreateUser(ctx, site, req) resp, err := c.CreateUser(ctx, site, req)
if err != nil { if err != nil {
if !provider.IsServerErrorContains(err, "api.err.MacUsed") || !allowExisting { if !base.IsServerErrorContains(err, "api.err.MacUsed") || !allowExisting {
return diag.FromErr(err) return diag.FromErr(err)
} }
@@ -227,7 +228,7 @@ func resourceUserSetResourceData(resp *unifi.User, d *schema.ResourceData, site
} }
func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -263,7 +264,7 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
} }
func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
site := d.Get("site").(string) site := d.Get("site").(string)
if site == "" { if site == "" {
@@ -316,7 +317,7 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
} }
func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,16 +1,17 @@
package v1 package user
import ( import (
"context" "context"
"errors" "errors"
"github.com/filipowm/terraform-provider-unifi/internal/provider" "github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/filipowm/terraform-provider-unifi/internal/utils"
"github.com/filipowm/go-unifi/unifi" "github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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/schema"
) )
func resourceUserGroup() *schema.Resource { func ResourceUserGroup() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Description: "`unifi_user_group` manages a user group (called \"client group\" in the UI), which can be used " + Description: "`unifi_user_group` manages a user group (called \"client group\" in the UI), which can be used " +
"to limit bandwidth for groups of users.", "to limit bandwidth for groups of users.",
@@ -20,7 +21,7 @@ func resourceUserGroup() *schema.Resource {
UpdateContext: resourceUserGroupUpdate, UpdateContext: resourceUserGroupUpdate,
DeleteContext: resourceUserGroupDelete, DeleteContext: resourceUserGroupDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
StateContext: importSiteAndID, StateContext: utils.ImportSiteAndID,
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@@ -60,7 +61,7 @@ func resourceUserGroup() *schema.Resource {
} }
func resourceUserGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceUserGroupGetResourceData(d) req, err := resourceUserGroupGetResourceData(d)
if err != nil { if err != nil {
@@ -99,7 +100,7 @@ func resourceUserGroupSetResourceData(resp *unifi.UserGroup, d *schema.ResourceD
} }
func resourceUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()
@@ -121,7 +122,7 @@ func resourceUserGroupRead(ctx context.Context, d *schema.ResourceData, meta int
} }
func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
req, err := resourceUserGroupGetResourceData(d) req, err := resourceUserGroupGetResourceData(d)
if err != nil { if err != nil {
@@ -145,7 +146,7 @@ func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta i
} }
func resourceUserGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { func resourceUserGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*provider.Client) c := meta.(*base.Client)
id := d.Id() id := d.Id()

View File

@@ -1,63 +0,0 @@
package v1
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
func TestAccDataPortProfile_default(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
preCheck(t)
preCheckVersionConstraint(t, "< 7.4")
},
ProviderFactories: providerFactories,
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccDataPortProfileConfig_default,
Check: resource.ComposeTestCheckFunc(),
},
},
})
}
func TestAccDataPortProfile_multiple_providers(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
preCheck(t)
preCheckVersionConstraint(t, "< 7.4")
},
ProviderFactories: map[string]func() (*schema.Provider, error){
"unifi2": func() (*schema.Provider, error) {
return New("acctest")(), nil
},
"unifi3": func() (*schema.Provider, error) {
return New("acctest")(), nil
},
},
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: `
data "unifi_port_profile" "unifi2" {
provider = "unifi2"
}
data "unifi_port_profile" "unifi3" {
provider = "unifi3"
}
`,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
},
})
}
const testAccDataPortProfileConfig_default = `
data "unifi_port_profile" "default" {
}
`

View File

@@ -1,59 +0,0 @@
package v1
import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
func TestAccDataUserGroup_default(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: providerFactories,
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: testAccDataUserGroupConfig_default,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
},
})
}
func TestAccDataUserGroup_multiple_providers(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { preCheck(t) },
ProviderFactories: map[string]func() (*schema.Provider, error){
"unifi2": func() (*schema.Provider, error) {
return New("acctest")(), nil
},
"unifi3": func() (*schema.Provider, error) {
return New("acctest")(), nil
},
},
// TODO: CheckDestroy: ,
Steps: []resource.TestStep{
{
Config: `
data "unifi_user_group" "unifi2" {
provider = "unifi2"
}
data "unifi_user_group" "unifi3" {
provider = "unifi3"
}
`,
Check: resource.ComposeTestCheckFunc(
// testCheckNetworkExists(t, "name"),
),
},
},
})
}
const testAccDataUserGroupConfig_default = `
data "unifi_user_group" "default" {
}
`

View File

@@ -1,20 +0,0 @@
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,165 +0,0 @@
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,192 +0,0 @@
package v1
import (
"bytes"
"context"
"fmt"
"math"
"net"
"net/http"
"os"
"sync"
"testing"
"github.com/apparentlymart/go-cidr/cidr"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/compose"
)
var providerFactories = map[string]func() (*schema.Provider, error){
"unifi": func() (*schema.Provider, error) {
return New("acctest")(), nil
},
}
var testClient unifi.Client
func TestMain(m *testing.M) {
if os.Getenv("TF_ACC") == "" {
// short circuit non-acceptance test runs
os.Exit(m.Run())
}
os.Exit(runAcceptanceTests(m))
}
func runAcceptanceTests(m *testing.M) int {
dc, err := compose.NewDockerCompose("../../../docker-compose.yaml")
if err != nil {
panic(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err = dc.WithOsEnv().Up(ctx, compose.Wait(true)); err != nil {
panic(err)
}
defer func() {
if err := dc.Down(context.Background(), compose.RemoveOrphans(true), compose.RemoveImagesLocal); err != nil {
panic(err)
}
}()
container, err := dc.ServiceContainer(ctx, "unifi")
if err != nil {
panic(err)
}
// Dump the container logs on exit.
//
// TODO: Use https://pkg.go.dev/github.com/testcontainers/testcontainers-go#LogConsumer instead.
defer func() {
if os.Getenv("UNIFI_STDOUT") == "" {
return
}
stream, err := container.Logs(ctx)
if err != nil {
panic(err)
}
buffer := new(bytes.Buffer)
buffer.ReadFrom(stream)
testcontainers.Logger.Printf("%s", buffer)
}()
endpoint, err := container.PortEndpoint(ctx, "8443/tcp", "https")
if err != nil {
panic(err)
}
const user = "admin"
const password = "admin"
if err = os.Setenv("UNIFI_USERNAME", user); err != nil {
panic(err)
}
if err = os.Setenv("UNIFI_PASSWORD", password); err != nil {
panic(err)
}
if err = os.Setenv("UNIFI_INSECURE", "true"); err != nil {
panic(err)
}
if err = os.Setenv("UNIFI_API", endpoint); err != nil {
panic(err)
}
testClient, err = unifi.NewClient(&unifi.ClientConfig{
URL: endpoint,
User: user,
Password: password,
HttpRoundTripperProvider: func() http.RoundTripper {
return createHTTPTransport(true, "unifi")
},
ValidationMode: unifi.DisableValidation,
Logger: unifi.NewDefaultLogger(unifi.WarnLevel),
})
if err != nil {
panic(err)
}
return m.Run()
}
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 siteAndIDImportStateIDFunc(resourceName string) func(*terraform.State) (string, error) {
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return "", fmt.Errorf("not found: %s", resourceName)
}
networkID := rs.Primary.Attributes["id"]
site := rs.Primary.Attributes["site"]
return site + ":" + networkID, nil
}
}
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)
}
}
}
const (
vlanMin = 2
vlanMax = 4095
)
var (
network = &net.IPNet{
IP: net.IPv4(10, 0, 0, 0).To4(),
Mask: net.IPv4Mask(255, 0, 0, 0),
}
vlanLock sync.Mutex
vlanNext = vlanMin
)
func getTestVLAN(t *testing.T) (*net.IPNet, int) {
vlanLock.Lock()
defer vlanLock.Unlock()
vlan := vlanNext
vlanNext++
subnet, err := cidr.Subnet(network, int(math.Ceil(math.Log2(vlanMax))), vlan)
if err != nil {
t.Error(err)
}
return subnet, vlan
}

View File

@@ -0,0 +1,35 @@
package utils
import (
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
)
// ID generates an attribute definition suitable for the always-present `id` attribute.
func ID(desc ...string) schema.StringAttribute {
a := schema.StringAttribute{
Computed: true,
Description: "The unique identifier of this resource.",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
}
if len(desc) > 0 {
a.Description = desc[0]
}
return a
}
// ShouldBeRemoved evaluates if an attribute should be removed from the plan during update.
func ShouldBeRemoved(plan attr.Value, state attr.Value, isClone bool) bool {
return !IsDefined(plan) && IsDefined(state) && !isClone
}
// IsDefined returns true if attribute is known and not null.
func IsDefined(v attr.Value) bool {
return !v.IsNull() && !v.IsUnknown()
}

View File

@@ -2,6 +2,7 @@ package utils
import ( import (
"fmt" "fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"net" "net"
) )
@@ -38,3 +39,17 @@ func CidrOneBased(cidr string) string {
return cidrNet.String() return cidrNet.String()
} }
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,13 +1,12 @@
package v1 package utils
import ( import (
"context" "context"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"strings"
) )
func importSiteAndID(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { func ImportSiteAndID(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
if id := d.Id(); strings.Contains(id, ":") { if id := d.Id(); strings.Contains(id, ":") {
importParts := strings.SplitN(id, ":", 2) importParts := strings.SplitN(id, ":", 2)
d.SetId(importParts[1]) d.SetId(importParts[1])

19
internal/utils/mac.go Normal file
View File

@@ -0,0 +1,19 @@
package utils
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"regexp"
"strings"
)
var MacAddressRegexp = regexp.MustCompile("^([0-9a-fA-F][0-9a-fA-F][-:]){5}([0-9a-fA-F][0-9a-fA-F])$")
func CleanMAC(mac string) string {
return strings.TrimSpace(strings.ReplaceAll(strings.ToLower(mac), "-", ":"))
}
func MacDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
old = CleanMAC(old)
new = CleanMAC(new)
return old == new
}

View File

@@ -1,4 +1,4 @@
package v1 package utils
import ( import (
"regexp" "regexp"
@@ -7,6 +7,6 @@ import (
) )
var ( var (
portRangeRegexp = regexp.MustCompile("(([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])|([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])-([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5]))+(,([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])|,([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])-([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])){0,14}") PortRangeRegexp = regexp.MustCompile("(([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])|([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])-([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5]))+(,([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])|,([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])-([1-9][0-9]{0,3}|[1-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-4][0-9]{2}|[6][5][5][0-2][0-9]|[6][5][5][3][0-5])){0,14}")
validatePortRange = validation.StringMatch(portRangeRegexp, "invalid port range") ValidatePortRange = validation.StringMatch(PortRangeRegexp, "invalid port range")
) )

View File

@@ -2,6 +2,7 @@ package utils
import ( import (
"fmt" "fmt"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
) )
@@ -33,3 +34,7 @@ func StringSliceToList(list []string) []interface{} {
func StringSliceToSet(src []string) *schema.Set { func StringSliceToSet(src []string) *schema.Set {
return schema.NewSet(schema.HashString, StringSliceToList(src)) return schema.NewSet(schema.HashString, StringSliceToList(src))
} }
func IsStringValueNotEmpty(s basetypes.StringValue) bool {
return !s.IsUnknown() && !s.IsNull() && s.ValueString() != ""
}

View File

@@ -3,8 +3,7 @@ package main // import "github.com/filipowm/terraform-provider-unifi"
import ( import (
"context" "context"
"flag" "flag"
v1 "github.com/filipowm/terraform-provider-unifi/internal/provider/v1" "github.com/filipowm/terraform-provider-unifi/internal/provider"
v2 "github.com/filipowm/terraform-provider-unifi/internal/provider/v2"
"github.com/hashicorp/terraform-plugin-framework/providerserver" "github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tfprotov6"
@@ -31,7 +30,7 @@ func main() {
flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve") flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse() flag.Parse()
p := v1.New(version) p := provider.New(version)
upgradedSdkServer, err := tf5to6server.UpgradeServer( upgradedSdkServer, err := tf5to6server.UpgradeServer(
ctx, ctx,
func() tfprotov5.ProviderServer { func() tfprotov5.ProviderServer {
@@ -43,7 +42,7 @@ func main() {
} }
providers := []func() tfprotov6.ProviderServer{ providers := []func() tfprotov6.ProviderServer{
providerserver.NewProtocol6(v2.New(version)()), providerserver.NewProtocol6(provider.NewV2(version)()),
func() tfprotov6.ProviderServer { func() tfprotov6.ProviderServer {
return upgradedSdkServer return upgradedSdkServer
}, },