658bda1d24
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
105 lines
3.7 KiB
Go
105 lines
3.7 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// InstanceForwardRow is one panel-owned port forward in opnfwd. Composite
|
|
// key (instance_id, port_name) — the panel allocates one forward per
|
|
// manifest port per instance.
|
|
type InstanceForwardRow struct {
|
|
InstanceID string
|
|
PortName string
|
|
NatUUID string
|
|
FilterUUID string
|
|
TargetIP string
|
|
HostPort int32
|
|
Proto string // "tcp" | "udp" | "tcp/udp"
|
|
Descr string // "panel-<instance>-<port_name>" — matches the OPNsense rule's <descr>
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// UpsertInstanceForward persists a single forward, replacing any prior row
|
|
// for the same (instance, port_name). The replace is intentional — if the
|
|
// panel re-creates a forward for an existing port (e.g. operator clicked
|
|
// Reconcile and we recreated), the new uuids supersede the old.
|
|
func (db *DB) UpsertInstanceForward(ctx context.Context, r InstanceForwardRow) error {
|
|
_, err := db.pool.Exec(ctx, `
|
|
INSERT INTO instance_forwards (instance_id, port_name, nat_uuid, filter_uuid, target_ip, host_port, proto, descr)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
ON CONFLICT (instance_id, port_name) DO UPDATE SET
|
|
nat_uuid = EXCLUDED.nat_uuid,
|
|
filter_uuid = EXCLUDED.filter_uuid,
|
|
target_ip = EXCLUDED.target_ip,
|
|
host_port = EXCLUDED.host_port,
|
|
proto = EXCLUDED.proto,
|
|
descr = EXCLUDED.descr
|
|
`, r.InstanceID, r.PortName, r.NatUUID, r.FilterUUID, r.TargetIP, r.HostPort, r.Proto, r.Descr)
|
|
if err != nil {
|
|
return fmt.Errorf("upsert instance_forward: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ListInstanceForwards returns every forward for the given instance, used
|
|
// at delete time + by the instance-modal "Forwards" pill.
|
|
func (db *DB) ListInstanceForwards(ctx context.Context, instanceID string) ([]InstanceForwardRow, error) {
|
|
rows, err := db.pool.Query(ctx, `
|
|
SELECT instance_id, port_name, nat_uuid, filter_uuid, target_ip, host_port, proto, descr, created_at
|
|
FROM instance_forwards
|
|
WHERE instance_id = $1
|
|
ORDER BY port_name
|
|
`, instanceID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list instance_forwards: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
var out []InstanceForwardRow
|
|
for rows.Next() {
|
|
var r InstanceForwardRow
|
|
if err := rows.Scan(&r.InstanceID, &r.PortName, &r.NatUUID, &r.FilterUUID,
|
|
&r.TargetIP, &r.HostPort, &r.Proto, &r.Descr, &r.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("scan instance_forward: %w", err)
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
// ListAllInstanceForwards is for the reconcile path — compare every
|
|
// panel-tracked forward against opnfwd's view of the world.
|
|
func (db *DB) ListAllInstanceForwards(ctx context.Context) ([]InstanceForwardRow, error) {
|
|
rows, err := db.pool.Query(ctx, `
|
|
SELECT instance_id, port_name, nat_uuid, filter_uuid, target_ip, host_port, proto, descr, created_at
|
|
FROM instance_forwards
|
|
ORDER BY instance_id, port_name
|
|
`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list all instance_forwards: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
var out []InstanceForwardRow
|
|
for rows.Next() {
|
|
var r InstanceForwardRow
|
|
if err := rows.Scan(&r.InstanceID, &r.PortName, &r.NatUUID, &r.FilterUUID,
|
|
&r.TargetIP, &r.HostPort, &r.Proto, &r.Descr, &r.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("scan instance_forward: %w", err)
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
// DeleteInstanceForwards removes every panel-tracked forward for an
|
|
// instance. Called from the delete path AFTER opnfwd's bulk-delete
|
|
// returned successfully — this just drops the local mirror.
|
|
func (db *DB) DeleteInstanceForwards(ctx context.Context, instanceID string) error {
|
|
_, err := db.pool.Exec(ctx, `DELETE FROM instance_forwards WHERE instance_id = $1`, instanceID)
|
|
if err != nil {
|
|
return fmt.Errorf("delete instance_forwards: %w", err)
|
|
}
|
|
return nil
|
|
}
|