Files
panel/controller/internal/db/instance_forwards.go
T
dbledeez a00bd620a1 Panel — public source drop (v0.9.0)
Self-hostable game-server control panel: controller + agent + 26 game
modules. One-line install (prebuilt release, no Go required):

  curl -fsSL https://git.pdxtechs.com/dbledeez/panel/raw/branch/main/install.sh | sudo bash

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 21:17:39 -07:00

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
}