Skip to content

Commit f6a43c4

Browse files
fixed categories on dnat
1 parent 7e2ea79 commit f6a43c4

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

internal/service/firewall/dnat_resource.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ type DNAT struct {
3636
Description string `json:"descr"`
3737
PoolOptions api.SelectedMap `json:"poolopts"`
3838
NatReflection api.SelectedMap `json:"natreflection"`
39-
Pass api.SelectedMap `json:"pass"`
39+
Pass api.SelectedMap `json:"pass"`
40+
Category api.SelectedMapList `json:"category"`
41+
Categories string `json:"categories"`
4042
}
4143

4244
var dnatOpts = api.ReqOpts{
@@ -99,7 +101,7 @@ func (r *dnatResource) Create(ctx context.Context, req resource.CreateRequest, r
99101
}
100102

101103
// Convert TF schema to OPNsense struct
102-
dnatRule, err := convertDNATSchemaToStruct(data)
104+
dnatRule, err := convertDNATSchemaToStruct(r.client, ctx, data)
103105
if err != nil {
104106
resp.Diagnostics.AddError("Client Error",
105107
fmt.Sprintf("Unable to parse firewall dnat, got error: %s", err))
@@ -183,7 +185,7 @@ func (r *dnatResource) Update(ctx context.Context, req resource.UpdateRequest, r
183185
}
184186

185187
// Convert TF schema to OPNsense struct
186-
dnatRule, err := convertDNATSchemaToStruct(data)
188+
dnatRule, err := convertDNATSchemaToStruct(r.client, ctx, data)
187189
if err != nil {
188190
resp.Diagnostics.AddError("Client Error",
189191
fmt.Sprintf("Unable to parse firewall dnat, got error: %s", err))

internal/service/firewall/dnat_schema.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package firewall
22

33
import (
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

363393
func 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

Comments
 (0)