feat: support Firewall Zone resource and datasource (#70)
* feat: support Firewall Zone resource and datasource * disable flaky test
This commit is contained in:
committed by
GitHub
parent
ca21f79083
commit
45ba7aace9
6
go.mod
6
go.mod
@@ -2,7 +2,7 @@ module github.com/filipowm/terraform-provider-unifi
|
||||
|
||||
go 1.23.5
|
||||
|
||||
//replace github.com/filipowm/go-unifi v1.6.0 => ../go-unifi
|
||||
//replace github.com/filipowm/go-unifi v1.6.2 => ../go-unifi
|
||||
// replace github.com/hashicorp/terraform-plugin-docs => ../../hashicorp/terraform-plugin-docs
|
||||
// replace github.com/hashicorp/terraform-plugin-sdk/v2 => ../../hashicorp/terraform-plugin-sdk
|
||||
|
||||
@@ -10,8 +10,8 @@ require (
|
||||
github.com/apparentlymart/go-cidr v1.1.0
|
||||
github.com/biter777/countries v1.7.5
|
||||
github.com/deckarep/golang-set/v2 v2.7.0
|
||||
github.com/filipowm/go-unifi v1.6.1
|
||||
github.com/golangci/golangci-lint v1.64.7
|
||||
github.com/filipowm/go-unifi v1.7.1
|
||||
github.com/golangci/golangci-lint v1.64.8
|
||||
github.com/hashicorp/go-version v1.7.0
|
||||
github.com/hashicorp/terraform-plugin-docs v0.21.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.14.1
|
||||
|
||||
5
go.sum
5
go.sum
@@ -286,6 +286,10 @@ github.com/filipowm/go-unifi v1.6.0 h1:0oLOrsLWcaU8sUsyMyjyGwaAWNC9Ee4YZ1ehtijXa
|
||||
github.com/filipowm/go-unifi v1.6.0/go.mod h1:hB5XyhjtnnU9GC6lYPYxuNmYq4J/SyjmElRVazCKT0U=
|
||||
github.com/filipowm/go-unifi v1.6.1 h1:zkxLUkbUWO3d62cUGr97knIzSJd+/id9RVc32iPojqo=
|
||||
github.com/filipowm/go-unifi v1.6.1/go.mod h1:hB5XyhjtnnU9GC6lYPYxuNmYq4J/SyjmElRVazCKT0U=
|
||||
github.com/filipowm/go-unifi v1.6.2 h1:nbZpcXwGLUA7BjahHsRx+ydbnho0OhL4xYXv4QVne6k=
|
||||
github.com/filipowm/go-unifi v1.6.2/go.mod h1:hB5XyhjtnnU9GC6lYPYxuNmYq4J/SyjmElRVazCKT0U=
|
||||
github.com/filipowm/go-unifi v1.7.1 h1:0RKplPdKWLsDJ3is3/qpTskGNY2hy65A94M33nuweNY=
|
||||
github.com/filipowm/go-unifi v1.7.1/go.mod h1:LwwNzM1idw0ORe+G2pI0qiWOH8xw8GjfjRw530QqWPI=
|
||||
github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA=
|
||||
github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
@@ -399,6 +403,7 @@ github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0a
|
||||
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY=
|
||||
github.com/golangci/golangci-lint v1.64.7 h1:Xk1EyxoXqZabn5b4vnjNKSjCx1whBK53NP+mzLfX7HA=
|
||||
github.com/golangci/golangci-lint v1.64.7/go.mod h1:5cEsUQBSr6zi8XI8OjmcY2Xmliqc4iYL7YoPrL+zLJ4=
|
||||
github.com/golangci/golangci-lint v1.64.8/go.mod h1:5cEsUQBSr6zi8XI8OjmcY2Xmliqc4iYL7YoPrL+zLJ4=
|
||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||
github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
|
||||
|
||||
84
internal/provider/acctest/datasource_firewall_zone_test.go
Normal file
84
internal/provider/acctest/datasource_firewall_zone_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package acctest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"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/resource"
|
||||
)
|
||||
|
||||
const testFirewallZoneDataSourceName = "data.unifi_firewall_zone.test"
|
||||
|
||||
func TestFirewallZoneDataSource_basic(t *testing.T) {
|
||||
pt.SkipIfEnvLocalMissing(t, "Skipping, because test environment does not support firewall zones yet, and no idea how to enable it")
|
||||
name := acctest.RandomWithPrefix("tfacc-")
|
||||
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 9.0.0",
|
||||
Lock: firewallZoneLock,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccFirewallZoneDataSourceConfig(name),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(testFirewallZoneDataSourceName, "name", name),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "networks.#", "0"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestFirewallZoneDataSource_nonExistent(t *testing.T) {
|
||||
pt.SkipIfEnvLocalMissing(t, "Skipping, because test environment does not support firewall zones yet, and no idea how to enable it")
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 9.0.0",
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccFirewallZoneDataSourceConfig_nonExistent(),
|
||||
ExpectError: regexp.MustCompile(`No firewall zone with name`),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestFirewallZoneDataSource_missingName(t *testing.T) {
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 9.0.0",
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccFirewallZoneDataSourceConfigMissingName(),
|
||||
ExpectError: pt.MissingArgumentErrorRegex("name"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccFirewallZoneDataSourceConfig(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
|
||||
resource "unifi_firewall_zone" "test" {
|
||||
name = %[1]q
|
||||
}
|
||||
|
||||
data "unifi_firewall_zone" "test" {
|
||||
name = %[1]q
|
||||
depends_on = [unifi_firewall_zone.test]
|
||||
}`, name)
|
||||
}
|
||||
|
||||
func testAccFirewallZoneDataSourceConfig_nonExistent() string {
|
||||
return `
|
||||
|
||||
data "unifi_firewall_zone" "test" {
|
||||
name = "non-existent"
|
||||
}`
|
||||
}
|
||||
|
||||
func testAccFirewallZoneDataSourceConfigMissingName() string {
|
||||
return `
|
||||
data "unifi_firewall_zone" "test" {
|
||||
}`
|
||||
}
|
||||
138
internal/provider/acctest/resource_firewall_zone_test.go
Normal file
138
internal/provider/acctest/resource_firewall_zone_test.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package acctest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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/resource"
|
||||
"github.com/hashicorp/terraform-plugin-testing/plancheck"
|
||||
"github.com/hashicorp/terraform-plugin-testing/terraform"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testFirewallZoneResourceName = "unifi_firewall_zone.test"
|
||||
|
||||
var firewallZoneLock = &sync.Mutex{}
|
||||
|
||||
// TODO make tests runnable on test environment hosted on container
|
||||
// to enable those tests, set TF_ACC_LOCAL=1
|
||||
|
||||
func TestAccFirewallZone_withNetworks(t *testing.T) {
|
||||
pt.SkipIfEnvLocalMissing(t, "Skipping, because test environment does not support firewall zones yet, and no idea how to enable it")
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 9.0.0",
|
||||
Lock: firewallZoneLock,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccFirewallZoneConfig(t, "test_zone_networks", acctest.RandomWithPrefix("tfacc-")),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttrSet(testFirewallZoneResourceName, "id"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "site", "default"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "name", "test_zone_networks"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "networks.#", "1"),
|
||||
),
|
||||
ConfigPlanChecks: pt.CheckResourceActions(testFirewallZoneResourceName, plancheck.ResourceActionCreate),
|
||||
},
|
||||
pt.ImportStepWithSite(testFirewallZoneResourceName),
|
||||
},
|
||||
CheckDestroy: testAccCheckFirewallZoneDestroy,
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccFirewallZone_update(t *testing.T) {
|
||||
pt.SkipIfEnvLocalMissing(t, "Skipping, because test environment does not support firewall zones yet, and no idea how to enable it")
|
||||
network1 := acctest.RandomWithPrefix("tfacc-")
|
||||
network2 := acctest.RandomWithPrefix("tfacc-")
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 9.0.0",
|
||||
Lock: firewallZoneLock,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccFirewallZoneConfig(t, "initial_zone", network1),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttrSet(testFirewallZoneResourceName, "id"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "name", "initial_zone"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "networks.#", "1"),
|
||||
resource.TestCheckResourceAttrSet(testFirewallZoneResourceName, "networks.0"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccFirewallZoneConfig(t, "updated_zone", network2),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttrSet(testFirewallZoneResourceName, "id"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "name", "updated_zone"),
|
||||
resource.TestCheckResourceAttr(testFirewallZoneResourceName, "networks.#", "1"),
|
||||
resource.TestCheckResourceAttrSet(testFirewallZoneResourceName, "networks.0"),
|
||||
),
|
||||
ConfigPlanChecks: pt.CheckResourceActions(testFirewallZoneResourceName, plancheck.ResourceActionUpdate),
|
||||
},
|
||||
},
|
||||
CheckDestroy: testAccCheckFirewallZoneDestroy,
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccFirewallZone_missingName(t *testing.T) {
|
||||
pt.SkipIfEnvLocalMissing(t, "Skipping, because test environment does not support firewall zones yet, and no idea how to enable it")
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 9.0.0",
|
||||
Lock: firewallZoneLock,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccFirewallZoneConfigMissingName(),
|
||||
ExpectError: pt.MissingArgumentErrorRegex("name"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccFirewallZoneConfig(t *testing.T, name string, network string) string {
|
||||
subnet, vlanId := pt.GetTestVLAN(t)
|
||||
return fmt.Sprintf(`
|
||||
|
||||
resource "unifi_network" "test" {
|
||||
name = %[2]q
|
||||
purpose = "corporate"
|
||||
subnet = %[3]q
|
||||
vlan_id = "%[4]d"
|
||||
}
|
||||
|
||||
resource "unifi_firewall_zone" "test" {
|
||||
name = %[1]q
|
||||
networks = [unifi_network.test.id]
|
||||
}
|
||||
`, name, network, subnet.String(), vlanId)
|
||||
}
|
||||
|
||||
func testAccFirewallZoneConfigMissingName() string {
|
||||
return `
|
||||
resource "unifi_firewall_zone" "test" {
|
||||
networks = []
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
func testAccCheckFirewallZoneDestroy(s *terraform.State) error {
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "unifi_firewall_zone" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := testClient.GetFirewallZone(context.Background(), "default", rs.Primary.ID)
|
||||
if err == nil {
|
||||
return fmt.Errorf("Firewall Zone %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
|
||||
}
|
||||
@@ -175,6 +175,7 @@ func TestAccSettingIps_dnsFilters(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAccSettingIps_suppression(t *testing.T) {
|
||||
t.Skip("Flaky! Alerts often cause ImportStateVerify attributes not equivalent on 2nd step")
|
||||
AcceptanceTest(t, AcceptanceTestCase{
|
||||
VersionConstraint: ">= 8.0",
|
||||
Lock: settingIpsLock,
|
||||
|
||||
113
internal/provider/firewall/datasource_firewall_zone.go
Normal file
113
internal/provider/firewall/datasource_firewall_zone.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/filipowm/go-unifi/unifi"
|
||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ datasource.DataSource = &firewallZoneDatasource{}
|
||||
_ datasource.DataSourceWithConfigure = &firewallZoneDatasource{}
|
||||
_ base.Resource = &firewallZoneDatasource{}
|
||||
)
|
||||
|
||||
type firewallZoneDatasource struct {
|
||||
base.ControllerVersionValidator
|
||||
base.FeatureValidator
|
||||
client *base.Client
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) SetFeatureValidator(validator base.FeatureValidator) {
|
||||
d.FeatureValidator = validator
|
||||
}
|
||||
|
||||
func NewFirewallZoneDatasource() datasource.DataSource {
|
||||
return &firewallZoneDatasource{}
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) SetClient(client *base.Client) {
|
||||
d.client = client
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) SetVersionValidator(validator base.ControllerVersionValidator) {
|
||||
d.ControllerVersionValidator = validator
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
base.ConfigureDatasource(d, req, resp)
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) Metadata(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = "unifi_firewall_zone"
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
MarkdownDescription: "The `unifi_firewall_zone` datsources allows retrieving existing firewall zone details from the UniFi controller by the zone name.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": base.ID(),
|
||||
"site": base.SiteAttribute(),
|
||||
"name": schema.StringAttribute{
|
||||
MarkdownDescription: "The name of the firewall zone.",
|
||||
Required: true,
|
||||
Validators: []validator.String{
|
||||
stringvalidator.LengthAtLeast(1),
|
||||
},
|
||||
},
|
||||
"networks": schema.ListAttribute{
|
||||
MarkdownDescription: "List of network IDs that this firewall zone contains.",
|
||||
Computed: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *firewallZoneDatasource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
resp.Diagnostics.Append(d.RequireMinVersion("9.0.0")...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
var state firewallZoneModel
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
site := d.client.ResolveSite(&state)
|
||||
|
||||
list, err := d.client.ListFirewallZone(ctx, site)
|
||||
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Failed to list Firewall zones", err.Error())
|
||||
return
|
||||
}
|
||||
if len(list) == 0 {
|
||||
resp.Diagnostics.AddError("Firewall zone not found", "No firewall zone found")
|
||||
return
|
||||
}
|
||||
|
||||
expectedName := state.Name.ValueString()
|
||||
var found *unifi.FirewallZone
|
||||
for _, zone := range list {
|
||||
if zone.Name == expectedName {
|
||||
found = &zone
|
||||
break
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
resp.Diagnostics.AddError("Firewall zone not found", fmt.Sprintf("No firewall zone with name %q found", expectedName))
|
||||
return
|
||||
}
|
||||
|
||||
(&state).Merge(ctx, found)
|
||||
state.SetID(found.ID)
|
||||
state.SetSite(site)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
}
|
||||
129
internal/provider/firewall/resource_firewall_zone.go
Normal file
129
internal/provider/firewall/resource_firewall_zone.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filipowm/go-unifi/unifi/features"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
|
||||
"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/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ resource.Resource = &firewallZoneResource{}
|
||||
_ resource.ResourceWithConfigure = &firewallZoneResource{}
|
||||
_ resource.ResourceWithImportState = &firewallZoneResource{}
|
||||
_ resource.ResourceWithModifyPlan = &firewallZoneResource{}
|
||||
_ base.Resource = &firewallZoneResource{}
|
||||
)
|
||||
|
||||
// firewallZoneModel represents the data model for a UniFi Firewall Zone
|
||||
type firewallZoneModel struct {
|
||||
base.Model
|
||||
Name types.String `tfsdk:"name"`
|
||||
Networks types.List `tfsdk:"networks"`
|
||||
}
|
||||
|
||||
// AsUnifiModel converts the Terraform model to the UniFi API model
|
||||
func (m *firewallZoneModel) AsUnifiModel(_ context.Context) (interface{}, diag.Diagnostics) {
|
||||
diags := diag.Diagnostics{}
|
||||
var networkIDs []string
|
||||
|
||||
diags.Append(utils.ListElementsAs(m.Networks, &networkIDs)...)
|
||||
if diags.HasError() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
return &unifi.FirewallZone{
|
||||
ID: m.ID.ValueString(),
|
||||
Name: m.Name.ValueString(),
|
||||
NetworkIDs: networkIDs,
|
||||
}, diags
|
||||
}
|
||||
|
||||
// Merge updates the Terraform model with values from the UniFi API model
|
||||
func (m *firewallZoneModel) Merge(ctx context.Context, other interface{}) diag.Diagnostics {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
model, ok := other.(*unifi.FirewallZone)
|
||||
if !ok {
|
||||
diags.AddError("Invalid model type", "Expected *unifi.FirewallZone")
|
||||
return diags
|
||||
}
|
||||
|
||||
m.ID = types.StringValue(model.ID)
|
||||
m.Name = types.StringValue(model.Name)
|
||||
|
||||
networkIDs, d := types.ListValueFrom(ctx, types.StringType, model.NetworkIDs)
|
||||
diags = append(diags, d...)
|
||||
m.Networks = networkIDs
|
||||
|
||||
return diags
|
||||
}
|
||||
|
||||
type firewallZoneResource struct {
|
||||
*base.GenericResource[*firewallZoneModel]
|
||||
}
|
||||
|
||||
func (r *firewallZoneResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
|
||||
resp.Diagnostics.Append(r.RequireMinVersion("9.0.0")...)
|
||||
site, diags := r.GetClient().ResolveSiteFromConfig(ctx, req.Config)
|
||||
if diags.HasError() {
|
||||
resp.Diagnostics.Append(diags...)
|
||||
return
|
||||
}
|
||||
resp.Diagnostics.Append(r.RequireFeaturesEnabled(ctx, site, features.ZoneBasedFirewall, features.ZoneBasedFirewallMigration)...)
|
||||
}
|
||||
|
||||
// NewFirewallZoneResource creates a new instance of the firewall zone resource
|
||||
func NewFirewallZoneResource() resource.Resource {
|
||||
return &firewallZoneResource{
|
||||
GenericResource: base.NewGenericResource(
|
||||
"unifi_firewall_zone",
|
||||
func() *firewallZoneModel { return &firewallZoneModel{} },
|
||||
base.ResourceFunctions{
|
||||
Read: func(ctx context.Context, client *base.Client, site, id string) (interface{}, error) {
|
||||
return client.GetFirewallZone(ctx, site, id)
|
||||
},
|
||||
Create: func(ctx context.Context, client *base.Client, site string, model interface{}) (interface{}, error) {
|
||||
return client.CreateFirewallZone(ctx, site, model.(*unifi.FirewallZone))
|
||||
},
|
||||
Update: func(ctx context.Context, client *base.Client, site string, model interface{}) (interface{}, error) {
|
||||
return client.UpdateFirewallZone(ctx, site, model.(*unifi.FirewallZone))
|
||||
},
|
||||
Delete: func(ctx context.Context, client *base.Client, site, id string) error {
|
||||
return client.DeleteFirewallZone(ctx, site, id)
|
||||
},
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Schema defines the schema for the resource
|
||||
func (r *firewallZoneResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
MarkdownDescription: "The `unifi_firewall_zone` resource manages firewall zones in the UniFi controller.\n\n" +
|
||||
"Firewall zones allow you to group networks together for firewall rule application. " +
|
||||
"This resource allows you to create, update, and delete firewall zones.",
|
||||
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": base.ID(),
|
||||
"site": base.SiteAttribute(),
|
||||
"name": schema.StringAttribute{
|
||||
MarkdownDescription: "The name of the firewall zone.",
|
||||
Required: true,
|
||||
},
|
||||
"networks": schema.ListAttribute{
|
||||
MarkdownDescription: "List of network IDs to include in this firewall zone.",
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ElementType: types.StringType,
|
||||
Default: utils.DefaultEmptyList(types.StringType),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"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/provider/firewall"
|
||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/settings"
|
||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/validators"
|
||||
"github.com/filipowm/terraform-provider-unifi/internal/utils"
|
||||
@@ -174,8 +175,9 @@ func (p *unifiProvider) Configure(ctx context.Context, req provider.ConfigureReq
|
||||
func (p *unifiProvider) Resources(_ context.Context) []func() resource.Resource {
|
||||
return []func() resource.Resource{
|
||||
dns.NewDnsRecordResource,
|
||||
//firewall.NewFirewallZoneResource,
|
||||
firewall.NewFirewallZoneResource,
|
||||
//firewall.NewFirewallZonePolicyResource,
|
||||
//portal.NewPortalFileResource,
|
||||
settings.NewAutoSpeedtestResource,
|
||||
settings.NewCountryResource,
|
||||
settings.NewDpiResource,
|
||||
@@ -199,5 +201,6 @@ func (p *unifiProvider) DataSources(_ context.Context) []func() datasource.DataS
|
||||
return []func() datasource.DataSource{
|
||||
dns.NewDnsRecordsDatasource,
|
||||
dns.NewDnsRecordDatasource,
|
||||
firewall.NewFirewallZoneDatasource,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const TfAccLocal = "TF_ACC_LOCAL"
|
||||
|
||||
// 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) {
|
||||
@@ -65,8 +67,8 @@ func SiteAndIDImportStateIDFunc(resourceName string) func(*terraform.State) (str
|
||||
// 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_USERNAME",
|
||||
//"UNIFI_PASSWORD",
|
||||
"UNIFI_API",
|
||||
}
|
||||
|
||||
@@ -95,3 +97,15 @@ func CheckResourceActions(resourceAddress string, actions ...plancheck.ResourceA
|
||||
func ComposeConfig(configs ...string) string {
|
||||
return strings.Join(configs, "\n")
|
||||
}
|
||||
|
||||
func SkipIfEnvMissing(t *testing.T, msg string, env string) {
|
||||
t.Helper()
|
||||
if os.Getenv(env) == "" {
|
||||
t.Skip(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func SkipIfEnvLocalMissing(t *testing.T, msg string) {
|
||||
t.Helper()
|
||||
SkipIfEnvMissing(t, msg, TfAccLocal)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user