11package firewall
22
33import (
4+ "context"
5+ "fmt"
46 "regexp"
7+ "strings"
58
69 "github.com/browningluke/opnsense-go/pkg/api"
10+ "github.com/browningluke/opnsense-go/pkg/firewall"
711 "github.com/browningluke/terraform-provider-opnsense/internal/tools"
812 "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
913 "github.com/hashicorp/terraform-plugin-framework/attr"
@@ -13,6 +17,7 @@ import (
1317 "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
1418 "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault"
1519 "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
20+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault"
1621 "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
1722 "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
1823 "github.com/hashicorp/terraform-plugin-framework/schema/validator"
@@ -39,6 +44,7 @@ type dnatResourceModel struct {
3944 PoolOptions types.String `tfsdk:"pool_options"`
4045 NatReflection types.String `tfsdk:"nat_reflection"`
4146 Pass types.String `tfsdk:"pass"`
47+ Categories types.Set `tfsdk:"categories"`
4248
4349 Id types.String `tfsdk:"id"`
4450}
@@ -217,6 +223,13 @@ func dnatResourceSchema() schema.Schema {
217223 Computed : true ,
218224 Default : stringdefault .StaticString ("" ),
219225 },
226+ "categories" : schema.SetAttribute {
227+ MarkdownDescription : "Set of category IDs to apply. Defaults to `[]`." ,
228+ Optional : true ,
229+ Computed : true ,
230+ ElementType : types .StringType ,
231+ Default : setdefault .StaticValue (tools .EmptySetValue (types .StringType )),
232+ },
220233 "id" : schema.StringAttribute {
221234 Computed : true ,
222235 MarkdownDescription : "UUID of the resource." ,
@@ -328,11 +341,27 @@ func dnatDataSourceSchema() dschema.Schema {
328341 MarkdownDescription : "When set, a firewall rule matching this NAT rule will be automatically created." ,
329342 Computed : true ,
330343 },
344+ "categories" : dschema.SetAttribute {
345+ MarkdownDescription : "Set of category IDs applied to this rule." ,
346+ Computed : true ,
347+ ElementType : types .StringType ,
348+ },
331349 },
332350 }
333351}
334352
335- func convertDNATSchemaToStruct (d * dnatResourceModel ) (* DNAT , error ) {
353+ func convertDNATSchemaToStruct (client * api.Client , ctx context.Context , d * dnatResourceModel ) (* DNAT , error ) {
354+ // Resolve category UUIDs to names (DNAT API CategoryField expects names)
355+ categoryUUIDs := tools .SetToStringSlice (d .Categories )
356+ categoryNames := make ([]string , 0 , len (categoryUUIDs ))
357+ for _ , uuid := range categoryUUIDs {
358+ cat , err := api .Get (client , ctx , firewall .CategoryOpts , & firewall.Category {}, uuid )
359+ if err != nil {
360+ return nil , fmt .Errorf ("unable to resolve category UUID %s: %w" , uuid , err )
361+ }
362+ categoryNames = append (categoryNames , cat .Name )
363+ }
364+
336365 return & DNAT {
337366 Disabled : tools .BoolToString (! d .Enabled .ValueBool ()),
338367 NoRdr : tools .BoolToString (d .NoRdr .ValueBool ()),
@@ -357,10 +386,17 @@ func convertDNATSchemaToStruct(d *dnatResourceModel) (*DNAT, error) {
357386 PoolOptions : api .SelectedMap (d .PoolOptions .ValueString ()),
358387 NatReflection : api .SelectedMap (d .NatReflection .ValueString ()),
359388 Pass : api .SelectedMap (d .Pass .ValueString ()),
389+ Category : api .SelectedMapList (categoryNames ),
360390 }, nil
361391}
362392
363393func convertDNATStructToSchema (d * DNAT ) (* dnatResourceModel , error ) {
394+ // Parse category UUIDs from the volatile "categories" field (comma-separated string)
395+ var categoryUUIDs []string
396+ if d .Categories != "" {
397+ categoryUUIDs = strings .Split (d .Categories , "," )
398+ }
399+
364400 return & dnatResourceModel {
365401 Enabled : types .BoolValue (! tools .StringToBool (d .Disabled )),
366402 NoRdr : types .BoolValue (tools .StringToBool (d .NoRdr )),
@@ -387,5 +423,6 @@ func convertDNATStructToSchema(d *DNAT) (*dnatResourceModel, error) {
387423 PoolOptions : types .StringValue (d .PoolOptions .String ()),
388424 NatReflection : types .StringValue (d .NatReflection .String ()),
389425 Pass : types .StringValue (d .Pass .String ()),
426+ Categories : tools .StringSliceToSet (categoryUUIDs ),
390427 }, nil
391428}
0 commit comments